how to : specify colors for multiple axes chart? - colors

My chart shows up well but the two lines are of the same color. How do I specify different colors for the two lines? Here is my code (fragment) so far:
config.pointIndex = null;
config.areaPoints = new Array();
config.areaPoints[0] = pointsopens;
config.areaPoints[1] = pointsclicks;
var plotLinesopen = createPlotlines(pointsopens);
var plotLinesclick = createPlotlines(pointsclicks);
var options = {
chart : { renderTo : 'areaChart' },
colors: [
'#4572A7',
'#AA4643'
],
xAxis: {
plotLines1: plotLinesopen,
plotLines2: plotLinesclick
},
series : [ data.pointsopens, data.pointsclicks ]
};
if (length > 100) {
options.plotOptions = {
area : {
lineWidth: 1,
marker : { radius : 1 }
}
};
}
options = jQuery.extend(true, {}, areaChartDefault, options);
charts.area = new Highcharts.Chart(options);
Thank you.
PS, my code is now:
config.pointIndex = null;
config.areaPoints = new Array();
config.areaPoints[0] = pointsopens;
config.areaPoints[1] = pointsclicks;
var plotLinesopen = createPlotlines(pointsopens, '#AAAAAA');
var plotLinesclick = createPlotlines(pointsclicks, '#DDDDDD');
var options = {
chart : { renderTo : 'areaChart' },
xAxis: {
plotLines: [plotLinesopen, plotLinesclick]
},
series : [ data.pointsopens, data.pointsclicks ]
};
if (length > 100) {
options.plotOptions = {
area : {
lineWidth: 1,
marker : { radius : 1 }
}
};
}
options = jQuery.extend(true, {}, areaChartDefault, options);
charts.area = new Highcharts.Chart(options);
but it still gives me two dark blue plotlines. The createPlotlines function looks like so:
function createPlotlines(points, colour) {
// Create plotlines from point data
colour = typeof colour !== 'undefined' ? colour : '#CCCCCC';
alert ('colour=='+colour);
var plotLines = [];
var middleYval = 0;
for (var i in points) {
middleYval = Math.max(middleYval, points[i].y);
if (points[i].l) { // l property is true if label should be on for this point
plotLines.push({
color: colour,
id: 'plotline'+i,
value: points[i].x,
width: 1,
});
}
}
return plotLines;
}

Do you mean different colors for the xAxis and yAxis? I only see that this would make one of each. You can definitely set the colors of the axis lines independently.
See this: example, ref
EDIT:
For plotLines you can use this:
demo

If you take a look the reference you'll see that there's no attr named colors.
Other problem is that there's no attr plotLines1 and plotLines2 as you can see here
Solution: If you want to change a plot line color your have to pass your plotlines thrue an array, like the following and set theire color:
var options = {
chart : { renderTo : 'areaChart' },
xAxis: {
plotLines: [{
color: '#4572A7', //
width: 2,
value: 5.5,
id: 'plotline-1'
}, {
color: '#AA4643',
width: 2,
value: 8.5,
id: 'plotline-2'
}]
},
series : [ data.pointsopens, data.pointsclicks ]
};
Live example
Update1:
You're returning an array of objects in this function createPlotlines and then you put this array inside other array. That's the problem.
Replace your function to the following:
function createPlotlines(points, colour) {
// Create plotlines from point data
colour = colour || '#CCCCCC';
var middleYval = 0;
for (var i in points) {
middleYval = Math.max(middleYval, points[i].y);
if (points[i].l) { // l property is true if label should be on for this point
return {
color: colour,
id: 'plotline'+i,
value: points[i].x,
width: 1,
};
}
}
}

ok, here is what I needed, lineColor:
$data = array(
"name" => $name,
"color" => '#00FFFF',
"lineColor"=> '#00FFFF',
"data" => $rows
);
that code goes in a local function called compileChartData in my php.
Thanks for the effort and sorry for the mixup.

you can change plotLines to target single line.
Or else you can change the whole Yaxis or Xaxis
xAxis: {
type: 'datetime',
gridLineColor: '#EEEEEE'
},
yAxis: {
title: {
text: 'Calls'
},
gridLineColor: '#EEEEEE'
}

Related

Trying to detect if 2 specific bodies are colliding with matter.js in phaser 3

I'm trying to add enemies to my platformer game using the matter physics engine however using the this.matter.world.on collisionactive function only checks collision between the floor and enemy after the player jumps once. I'm currently using labels to check for collision. I have tried adding extra conditions but have only been able to allow the player to infinitely jump. i.e- it is checking the labels of what is colliding.
Collision checking code:
this.matter.world.on("collisionactive", (e,o1,o2) => {
if(o1.label == 'floor' && o2.label == 'player')
{
this.touchingGround = true;
console.log('touching')
}
});
Enemy creation function:
Right now the enemies are cubes that are created at the cursor when the player presses f
function createEnemy(scene,x,y)
{
enemy = scene.matter.add.image(x,y,'enemy').setScale(1.5)
enemy.body.label = 'enemy'
}
I don't completely understand the problem, but if you have an issue with checking/finding all current collisions, you can use the pairs property of the event-object-argument (link to the documentation), which is passed to the physics-callback function. This property should contain, the other collisions.
"...The event.pairs array may contain more colliding bodies. ..."
Here a short demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 11 * 16,
height: 6 * 16,
zoom: 2,
pixelArt: true,
scene: {
preload: preload,
create: create
},
physics: {
default: 'matter',
matter: {
gravity: {
y:.3
},
debug:true
}
},
banner: false
};
function preload (){
this.load.image('mario-tiles', 'https://labs.phaser.io/assets/tilemaps/tiles/super-mario.png');
}
function create (){
var level = [
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split(''),
'0'.repeat(11).split('').map( _ => 14),
];
var map = this.make.tilemap({ data: level, tileWidth: 16, tileHeight: 16 });
var tiles = map.addTilesetImage('mario-tiles');
var layer = map.createLayer(0, tiles, 0, 0);
this.add.text(4, 4, 'click to jump', {color:'#9EE6FF', fontSize:10})
.setOrigin(0);
var info = this.add.text(4, 14, 'waiting ...', {color:'#ffffff', fontSize:10})
.setOrigin(0);
let enemy1 = this.add.rectangle(60.25, 5, 8, 8, 0xfff000)
.setOrigin(0.5);
let player = this.add.rectangle(60, 20, 8, 8, 0xffffff);
layer.setCollision([14]);
this.matter.add.gameObject(enemy1);
this.matter.add.gameObject(player);
this.matter.world.convertTilemapLayer(layer, {label:'floor'});
player.body.label = 'player';
enemy1.body.label = 'enemy';
this.input.on('pointerup', _=> player.setVelocityY(-3))
player.setVelocityY(-1)
this.matter.world.on("collisionactive", (e, o1, o2) => {
let text = 'p: ';
if( e.pairs.some (pair => pair.bodyA.label == 'player' && pair.bodyB.label =='floor' )) {
text += 'touch floor ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='player' )) {
text += 'touch enemy ';
}
if( e.pairs.some (pair => pair.bodyA.label == 'enemy' && pair.bodyB.label =='floor' )) {
text += '\ne: touch floor';
}
info.setText(text);
});
}
new Phaser.Game(config);
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

pasting the elements multiple times in rappid js

I am using joint js and rappid with the angular 8 and I have done most of the tasks but in using keyboard events there seems to be a issue. When I copy an element and pasted it on graph it works fine. But for the next element selected it is pasting that new element multiple times.
Here is my code.
var keyboard = this.keyboard = new joint.ui.Keyboard();
var clipboard = this.clipboard = new joint.ui.Clipboard();
selection.collection.on('reset add remove', this.onSelectionChange.bind(this));
paper.on('element:pointerdown', function(elementView: joint.dia.ElementView,evt: joint.dia.Event) {
clipboard.clear();
keyboard.on({
'ctrl+c': function(evt) {
selection.collection.reset();
//clipboard.clear();
selection.collection.add(elementView.model);
clipboard.copyElements(selection.collection, paper.model);
//console.log(clipboard);
},
'ctrl+v': function(evt) {
//console.log(clipboard);
var pastedCells = clipboard.pasteCells(graph, {
translate: { dx: 20, dy: 20 },
useLocalStorage: true
});
var elements = _.filter(pastedCells, function(cell) {
return cell.isElement();
});
//console.log(elements);
// Make sure pasted elements get selected immediately. This makes the UX better as
// the user can immediately manipulate the pasted elements.
selection.collection.reset(elements);
},
});
});
onSelectionChange() {
const { paper, selection,clipboard } = this;
const { collection } = selection;
//console.log(collection.models.child);
// collection.models.forEach(function(model: joint.dia.Element) { if(!model.collection) { clipboard.clear();}});
paper.removeTools();
joint.ui.Halo.clear(paper);
joint.ui.FreeTransform.clear(paper);
joint.ui.Inspector.close();
if(collection.first() == undefined){
clipboard.clear();
}
if (collection.length === 1) {
var primaryCell = collection.first();
var primaryCellView = paper.requireView(primaryCell);
selection.destroySelectionBox(primaryCell);
this.selectPrimaryCell(primaryCellView);
} else if (collection.length === 2) {
collection.each(function(cell) {
selection.createSelectionBox(cell);
});
}
}
selectPrimaryCell(cellView) {
var cell = cellView.model
if (cell.isElement()) {
this.selectPrimaryElement(cellView);
} else {
this.selectPrimaryLink(cellView);
}
//this.createInspector(cell);
}
selectPrimaryElement(elementView) {
var element = elementView.model;
console.log(element.collection);
new joint.ui.FreeTransform({
cellView: elementView,
allowRotation: false,
preserveAspectRatio: !!element.get('preserveAspectRatio'),
allowOrthogonalResize: element.get('allowOrthogonalResize') !== false
}).render();
}
I have different thing like resetting the clipboard , resetting the selection and resetting the keyboard but nothing seems to be working.

Cannot find namespace 'NodeJS'

If i run this code, i get an error, Cannot find namespace 'NodeJS'.
public exportExcel(jsonData: any[], excelFileName: string): void {
//Excel Title, Header, Data
const header: string[] = Object.keys(jsonData[0]);
const data = jsonData;
//Create workbook and worksheet
let workbook = new Workbook();
let worksheet = workbook.addWorksheet(excelFileName);
//Add Header Row
let headerRow = worksheet.addRow(header);
// Cell Style : Fill and Border
headerRow.eachCell((cell, number) => {
cell.fill = {
type: 'pattern',
pattern: 'solid',
fgColor: { argb: 'FFFFFF00' },
bgColor: { argb: 'FF0000FF' }
}
cell.border = { top: { style: 'thin' }, left: { style: 'thin' }, bottom: { style: 'thin' }, right: { style: 'thin' } }
})
// Add Data and Conditional Formatting
data.forEach((element) => {
let eachRow = [];
header.forEach((headers) => {
eachRow.push(element[headers])
})
if (element.isDeleted === "Y") {
let deletedRow = worksheet.addRow(eachRow);
deletedRow.eachCell((cell, number) => {
cell.font = { name: 'Calibri', family: 4, size: 11, bold: false, strike: true };
})
} else {
worksheet.addRow(eachRow);
}
})
...
ERROR in node_modules/exceljs/index.d.ts(1648,34): error TS2503: Cannot find namespace 'NodeJS'.
Solution targetting Angular8+ Projects:
This is a known bug, caused due to the incompatibility of exceljs with the version of #types/node. I faced similar issue with Angular 10.
2 possible solutions exists:
Recommended: Update your tsconfig.app.json file with "types": ["node"]
If you are okay without having type support, then you can simply use the below import:
import * as Excel from "exceljs/dist/exceljs.min.js";
Just Open index.d.ts file from yours exceljs node_modules
and replace this line
dictionary: Buffer | NodeJS.TypedArray | DataView | ArrayBuffer; // deflate/inflate only, empty dictionary by default
with this
dictionary: Buffer | DataView | ArrayBuffer; // deflate/inflate only, empty dictionary by default
and then just ng serve

How to load multiple sliders with values and tooltips with noUISlider?

I'm trying to load multiple sliders using noUISlider and it's not working. When using the first slider, the values changes for the second and third. How do I go about refactoring the code for one slider so I can easily add additional sliders with different options?
Here's a fiddle and below is my code.
// noUISlider
var actSlider = document.getElementById('act-slider');
noUiSlider.create(actSlider, {
start: [0, 50],
connect: false,
step: 1,
range: {
'min': 0,
'max': 50
},
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
// Connect bar
var connectBar = document.createElement('div'),
connectBase = actSlider.getElementsByClassName('noUi-base')[0],
connectHandles = actSlider.getElementsByClassName('noUi-origin');
// Give the bar a class for styling and add it to the slider.
connectBar.className += 'connect';
connectBase.appendChild(connectBar);
actSlider.noUiSlider.on('update', function (values, handle) {
// Pick left for the first handle, right for the second.
var side = handle ? 'right' : 'left',
// Get the handle position and trim the '%' sign.
offset = (connectHandles[handle].style.left).slice(0, -1);
// Right offset is 100% - left offset
if (handle === 1) {
offset = 100 - offset;
}
connectBar.style[side] = offset + '%';
});
// Value tooltips
var tipHandles = actSlider.getElementsByClassName('noUi-handle'),
tooltips = [];
// Add divs to the slider handles.
for (var i = 0; i < tipHandles.length; i++) {
tooltips[i] = document.createElement('div');
tooltips[i].className += 'value-tooltip';
tipHandles[i].appendChild(tooltips[i]);
}
// When the slider changes, write the value to the tooltips.
actSlider.noUiSlider.on('update', function (values, handle) {
tooltips[handle].innerHTML = values[handle];
});
You can wrap your slider creation in a function, and call it for all elements where you want a slider created.
noUiSlider also supports tooltips (from version 8.1.0) and connect options, so you don't have to implement those yourself if you don't want to make very specific changes.
As for different options for every slider, there are several ways to do this. I've added an example using data attributes for the step option.
The following code initializes a slider on all elements with a .slider class.
function data ( element, key ) {
return element.getAttribute('data-' + key);
}
function createSlider ( slider ) {
noUiSlider.create(slider, {
start: [0, 50],
connect: false,
step: Number(data(slider, 'step')) || 1,
range: {
'min': 0,
'max': 50
},
tooltips: true,
connect: true,
format: {
to: function (value) {
return value + '';
},
from: function (value) {
return value.replace('', '');
}
}
});
}
Array.prototype.forEach.call(document.querySelectorAll('.slider'), createSlider);
Here's a jsFiddle demonstrating this code.

Primefaces chart + jqplot extender - rounded value in the y-axis

Background
I have a primefaces line chart (date on x, integer >= 0 on y) extended with jqplot options:
function extender() {
this.cfg.axes = {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer
},
tickOptions : {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:-40,
formatString:'%b-%y'
},
tickInterval:'2592000000'
},
yaxis : {
min: 0,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer,
},
tickOptions: {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:0,
formatString: '%d'
}
},
};
this.cfg.axes.xaxis.ticks = this.cfg.categories;
}
I'm using the jqplot extender to have custom date interval on the x-axis and this is working fine:
Problem
When I use the option min: 0 in the y-axis the formatting of numbers goes really funky, especially when there are small values:
Note that the minY attribute in primefaces doesn't work (probably because the extender overwrites it)
To fix that, I use formatString: %d. It works but it creates problem with the number of ticks:
As you see on the screenshot, there are several times the line for the value 1.
Question
How can make sure I don't get several times the same value on the y-axis?
I can't really have a static number of ticks because when the data grows large (let's say around 100), I do want several values on the y-axis (e.g 20, 40, etc...)
I managed to solve my issue using ideas from Mehasse's post.
Defining the max value like suggested by Mehasse didn't remove the unwanted tick lines but helped me to find the answer.
By default, primefaces/jqplot wants to have 4 y-axis tick lines. Thus, if the max value is below 4, there will be duplication in the y-axis label when they are rounded up (formatString: '%d').
What I basically want, is the tick interval to be either Max(y) \ 4 when Max(y) > 4, or 1 otherwise:
function actionPlanExtender() {
var series_max =maxSeries(this.cfg.data);
var numberOfTicks =4;
var tickInterval = Math.max(1, Math.ceil(series_max/numberOfTicks));
this.cfg.axes = {
xaxis : {
renderer : $.jqplot.DateAxisRenderer,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer
},
tickOptions : {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:-40,
formatString:'%b-%y'
},
tickInterval:'2592000000'
},
yaxis : {
min: 0,
rendererOptions : {
tickRenderer:$.jqplot.CanvasAxisTickRenderer,
},
tickOptions: {
fontSize:'10pt',
fontFamily:'Tahoma',
angle:0,
formatString: '%d',
},
tickInterval: tickInterval
},
};
this.cfg.axes.xaxis.ticks = this.cfg.categories;
}
To compute the y-max value, I'm getting the plot value using this.cfg.data which is of the form [series_1,..., series_n] with series_i = [[x_1, y_1],..., [x_m, y_m]]
The maxSeries function looks like:
function maxSeries(datas) {
var maxY = null;
var dataLength = datas.length;
for ( var dataIdx = 0; dataIdx < dataLength; dataIdx++) {
var data = datas[dataIdx];
var l = data.length;
for ( var pointIdx = 0; pointIdx < l; pointIdx++) {
var point = data[pointIdx];
var y = point[1];
if (maxY == null || maxY < y) {
maxY = y;
}
}
}
return maxY;
}
Note that in my case I know my case I don't have value below 0. This code should be updated if this is not the case.
I was surprised when I first started using JQPlot that it doesn't pick reasonable axis labels out of the box. It's actually easy to fix.
I'm going to assume that you want your y axis to start at zero. If that's not true, you'll need to modify this code a bit.
// This is YOUR data set
var series = [882, 38, 66, 522, 123, 400, 777];
// Instead of letting JQPlot pick the scale on the y-axis, let's figure out our own.
var series_max = Math.max.apply(null, series);
var digits = max.toString().length;
var scale = Math.pow(10, max_digits - 1);
var max = (Math.ceil(series_max / scale)) * scale;
$.jqplot(
'foo',
[series],
{
axes: {
yaxis: {
min: 0,
max: max
}
}
// Put your other config stuff here
}
)
The basic idea here is that we want to round up to some nice, round value near the maximum value in our series. In particular, we round up to the nearest number that has zeroes in all digits except the left-most. So the max 882 will result in a y-axis max of 1000.

Resources