Could this graph be made using Highstock?
I'm currently using Highstock, but never saw this kind.
Before I waste weeks trying, the question needs to be asked...
If yes, how can this be made? by shifting the stock chart, and create another Xaxis at the right?
Stock projection
According to the comments - a similar result could be achieved by adding additional series with proper data.
Demo: https://jsfiddle.net/BlackLabel/mkpj71n4/
chart: {
events: {
load() {
let chart = this;
function addNewSeries(y, color) {
let data = [],
xValue = startDay,
yData = 420; // last candle
for (let i = 0; i < 20; i++) {
xValue = xValue + 30 * 60 * 1000;
yData = yData + i * y
data.push([xValue, yData])
}
chart.addSeries({
data: data,
color: color
})
}
for (let i = 0; i < 4; i++) {
if (i === 0) {
addNewSeries(0.1, 'orange')
} else if (i === 2) {
addNewSeries(-0.1, 'orange')
} else if (i === 3) {
addNewSeries(0.2, 'red')
} else {
addNewSeries(-0.2, 'red')
}
}
}
}
},
API: https://api.highcharts.com/highcharts/chart.events.load
API: https://api.highcharts.com/class-reference/Highcharts.Chart#addSeries
Related
I want to display X and Y coordinates of a multiple lineseries on hovering any lineseries in qml chartview. The X and Y coordinates displaying should be the plotted values only.
Please go through the attachment.
I came across mapToValue() function of ChartView. But, I did not get how to use it. Could some one please help me on this.
I have implemented a sample code below, but could not able to print the x and y coordinates of each lineseries.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtCharts 2.3
Window {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property var x1Val : [0,1,2,3,4,5,6,7,8,9]
property var y1Val : [0,1,2,3,4,5,6,7,8,9]
property var x2Val : [0,1,2,3,4,5,6,7,8,9]
property var y2Val : [1,2,3,4,5,6,7,8,9,10]
property var lineSeries: 0
Component.onCompleted: {
var xVal, yVal
for(let i = 0; i < 2; i++) {
lineSeries = chartView.createSeries(ChartView.SeriesTypeLine, "strend" + i)
lineSeries.hovered.connect(
function(point, state) {
if (state) {
for(let i = 0; i < 2; i++) {
console.log("Name = ", chartView.series(i).name)
//console.log("x = ", point.x + ", y = ", point.y)
//console.log("x = ", chartView.series(i).at(i).x + ", y = ", chartView.series(i).at(i).y)
// How to get x and Y coordinates for each lineseries here ??
}
}
})
lineSeries.axisX.min = 0
lineSeries.axisX.max = 10
lineSeries.axisY.min = 0
lineSeries.axisY.max = 10
lineSeries.pointsVisible = true;
if(i === 0) {
xVal = x1Val
yVal = y1Val
}
else {
xVal = x2Val
yVal = y2Val
}
for(var iLoop = 0; iLoop < x1Val.length; iLoop++) {
lineSeries.append(xVal[iLoop], yVal[iLoop])
}
}
}
ChartView {
id: chartView
anchors.fill: parent
antialiasing: true
legend.visible: true
}
}
I have a graph where I am using underlays to draw vertical lines between the points. I have a line of code that restricts these vertical lines to NOT draw outside the active canvas. But when I use this underlayCallback, the 'points' are still drawn outside the canvas. If I remove my underlayCallback, the points are restricted to the canvas as one would expect. Here is what they look like and my code. (Sorry, the site is too secure to provide working sample.)
g[i] = new Dygraph(thisdiv, mylines, {
labels: graphlbls[i],
ylabel: graphunits[i].capitalizeFirstLetter(),
xlabel: '',
xLabelHeight:15,
yLabelWidth:15,
rightGap: 5,
labelsDivStyles: {
'text-align': 'right',
'background': 'none'
},
colors: ['#D48513','#1D6EB5'],
title: graphtitles[i],
titleHeight:23,
drawPoints: true,
showRoller: false,
drawXGrid: false,
drawYGrid: true,
strokeWidth: 0,
pointSize: 4,
highlightCircleSize: 6,
gridLineColor: "#ddd",
axisLabelFontSize: 12,
xAxisHeight: 20,
valueRange: [minval, maxval],
rangeSelectorHeight: 30,
showRangeSelector: true,
rangeSelectorPlotFillColor: '#ffffff',
rangeSelectorPlotStrokeColor: '#ffffff',
interactionModel: Dygraph.defaultInteractionModel,
axes: {
x: {
valueFormatter: function (ms) {
var d = new Date(ms);
var day = "0"+d.getDate();
var month = "0"+(d.getMonth()+1);
var year = d.getFullYear();
var hour = "0"+ d.getHours();
var min = "0"+d.getMinutes();
var p = "AM";
if (hour > 12) { p = "PM"; hour = hour - 12; }
if (df == 0) var dd = month.slice(-2)+"/"+day.slice(-2)+"/"+year;
if (df == 1) var dd = day.slice(-2)+"/"+month.slice(-2)+"/"+year;
if (tf == 0) var tt = hour.slice(-2)+":"+min.slice(-2)+" "+p+" ";
if (tf == 1) var tt = hour.slice(-2)+":"+min.slice(-2)+" ";
return dd + " - " + tt;
}
}
},
underlayCallback: function(ctx, area, g) {
//if (typeof(g[i]) == 'undefined') return; // won't be set on the initial draw.
var range = g.xAxisRange();
var rows = g.numRows();
// get max and min y
for (var i = 0; i < rows; i++) {
miny = 99999;
maxy = -99999;
xx = g.getValue(i,0);
if (xx < range[0] || xx > range[1]) continue; // constrain to graph canvas
for (var j=1; j<= range.length; j++) {
if (g.getValue(i,j) <= miny) miny = g.getValue(i,j);
if (g.getValue(i,j) >= maxy) maxy = g.getValue(i,j);
}
p1 = g.toDomCoords(xx, miny);
p2 = g.toDomCoords(xx, maxy);
ctx.strokeStyle = "rgba(192,192,224,1)";
ctx.lineWidth = 1.0;
ctx.beginPath();
ctx.moveTo(p1[0], p1[1]);
ctx.lineTo(p2[0], p2[1]);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
}
});
You're calling ctx.restore() many times without corresponding calls to ctx.save(). This pops off dygraphs' own drawing context, including the clipping rectangle. Make one call to save at the top of your underlayCallback and one to restore at the end.
Stepping back a bit, what you're doing might be easier with a custom plotter, rather than an underlayCallback.
i need help with my Chart.js interactivity. When I click on the label, I need to return the column(index) number at which I clicked.
I tried to use getElementsAtEvent but it only work if I click directly at chart.
This http://jsfiddle.net/yxz2sjam/ is pretty much what I am looking for but getPointsAtEvent is no longer available in the new versions.
canvas.onclick = function (evt) {
var points = chart.getPointsAtEvent(evt);
alert(chart.datasets[0].points.indexOf(points[0]));
};
I also found this http://jsfiddle.net/1Lngmtz7/ but it isn't working with bar chart.
var ctx = document.getElementById("myChart").getContext("2d");
var myRadarChart = new Chart(ctx, {
type: 'radar',
data: data
})
$('#myChart').click(function (e) {
var helpers = Chart.helpers;
var eventPosition = helpers.getRelativePosition(e, myRadarChart.chart);
var mouseX = eventPosition.x;
var mouseY = eventPosition.y;
var activePoints = [];
helpers.each(myRadarChart.scale.ticks, function (label, index) {
for (var i = this.getValueCount() - 1; i >= 0; i--) {
var pointLabelPosition = this.getPointPosition(i, this.getDistanceFromCenterForValue(this.options.reverse ? this.min : this.max) + 5);
var pointLabelFontSize = helpers.getValueOrDefault(this.options.pointLabels.fontSize, Chart.defaults.global.defaultFontSize);
var pointLabeFontStyle = helpers.getValueOrDefault(this.options.pointLabels.fontStyle, Chart.defaults.global.defaultFontStyle);
var pointLabeFontFamily = helpers.getValueOrDefault(this.options.pointLabels.fontFamily, Chart.defaults.global.defaultFontFamily);
var pointLabeFont = helpers.fontString(pointLabelFontSize, pointLabeFontStyle, pointLabeFontFamily);
ctx.font = pointLabeFont;
var labelsCount = this.pointLabels.length,
halfLabelsCount = this.pointLabels.length / 2,
quarterLabelsCount = halfLabelsCount / 2,
upperHalf = (i < quarterLabelsCount || i > labelsCount - quarterLabelsCount),
exactQuarter = (i === quarterLabelsCount || i === labelsCount - quarterLabelsCount);
var width = ctx.measureText(this.pointLabels[i]).width;
var height = pointLabelFontSize;
var x, y;
if (i === 0 || i === halfLabelsCount)
x = pointLabelPosition.x - width / 2;
else if (i < halfLabelsCount)
x = pointLabelPosition.x;
else
x = pointLabelPosition.x - width;
if (exactQuarter)
y = pointLabelPosition.y - height / 2;
else if (upperHalf)
y = pointLabelPosition.y - height;
else
y = pointLabelPosition.y
if ((mouseY >= y && mouseY <= y + height) && (mouseX >= x && mouseX <= x + width))
activePoints.push({ index: i, label: this.pointLabels[i] });
}
}, myRadarChart.scale);
var firstPoint = activePoints[0];
if (firstPoint !== undefined) {
alert(firstPoint.index + ': ' + firstPoint.label);
}
});
Thank for response.
I solve the problem with
document.getElementById("chart").onclick = function(e)
{
var activeElement = weatherMainChart.lastTooltipActive;
console.log(activeElement[0]._index);
};
this solution register clicks on chart and label, then I restricted it with e.layerY to register only clicks on label section.
document.getElementById("chart").onclick = function(e)
{
var activeElement = weatherMainChart.lastTooltipActive;
if(e.layerY > 843 && e.layerY < 866 && activeElement[0] !== undefined)
console.log(activeElement[0]._index);
};
If you add a click handler through the onClick option you can use the following code using the getElementsAtEventForMode() call:
function handleClick(evt) {
var col;
switch(chartType) {
case "horizontalBar":
this.getElementsAtEventForMode(evt, "y", 1).forEach(function(item) { col = item._index });
break;
case "bar":
this.getElementsAtEventForMode(evt, "x", 1).forEach(function(item) { col = item._index });
break;
}
if (!col) {
return;
}
alert("Column " + col + " was selected");
};
You'll probably need to add extra switch checks for other chart types but I'm sure you get the idea.
Using version 2.4.0, i created an onClick Event, and inside it
var activeIndex = localChart.tooltip._lastActive[0]._index;
var clickCoordinates = Chart.helpers.getRelativePosition(e, localChart.chart);
if (clickCoordinates.y >= 530) { //custom value, depends on chart style,size, etc
alert("clicked on " + localChart.data.labels[activeIndex]);
}
I Solved this problem with single or multiple label click you will be find using true/false
First you need to set your chartJs Id click
below code SessionChart = Your ChartJs ID e.g. ("myChart") I was replace it for my Id
document.getElementById("SessionChart").onclick = function (evt) {
var meta = SubscriberSessionChart.getDatasetMeta(0);
if (meta.$filler.chart.legend.legendItems[0].text.toLowerCase() "sessions")
{
if (meta.$filler.chart.legend.legendItems[0].hidden) {
sessionHidden = true;
}
}
}
here "sessions" = first label text
meta.$filler.chart.legend.legendItems[0].text.toLowerCase() = is your first label
from Array so you can get multiple label's click here true / false
if (meta.$filler.chart.legend.legendItems[0].hidden) = your label is not active then
you will get hidden true otherwise you will get false if not tick on label
by default label tick hidden is false in chart js
I tried writing this on my own, but I failed miserably. Right now I have a script checking the score in my game. I check for every 100 points and change a variable depending on the score, but I'm doing it the wrong and tedious way:
if(gameController.speed == 1) {
if(score >= 200) {
squishyController.gravity = -25;
}
if(score >= 300) {
squishyController.gravity = -50;
}
if(score >= 400) {
squishyController.gravity = -75;
}
if(score >= 500) {
squishyController.gravity = -100;
gamePause = true;
// Spawn First Boss
}
if(score >= 600) {
squishyController.gravity = -125;
}
if(score >= 700) {
squishyController.gravity = -150;
}
}
You get the point. What I want to do in word form is this:
For every 100 points
Change gravity by -25
if the points are 500, 1000, etc
spawn boss
That's it in a nutshell. Here's what I'm thinking it would look like but don't kill me.
for (var i = 0; i += pointValue) {
// Check if points are being added then add to score depending on point value
if(getPoints == true) {
i++;
}
// For every 100 points change the gravity value
if(i >= incrementsOf100) {
gravity = gravity -= 25;
}
// For every 500 points, spawn a boss more difficult than the last
if(i = incrementsOf500) {
bossDifficulty = bossDifficulty += 100; // Just adding this because I will add more hitpoints to boss.
spawnBoss = true;
}
}
How about using the modus operator to find the remainder of dividing by 100, then divide the score minus that remainder to get the number of times you need to change gravity
var score = 550;
var extra = score % 100;
var gravityTimes = (score - extra) / 100;
gravity = gravity -= (25 * gravityTimes);
Based on googleAPI documentation:
https://developers.google.com/chart/interactive/docs/gallery/columnchart?hl=en
As you can see in "labeling columns" section each column is labeled with a static value. I want to know if it is possible to label a column with a specific value resulting of the sum of all.
// Set chart options
var options = {
width: 400,
height: 300,
calc:????
};
Should i set this "calc" field with a specific function?
JSFIDDLE: Total Labeling Column
I can't figure out how can i customize a label with the sum values of each stacked column.
You can use getNumberOfRows(), getNumberOfColumns() and getValue() functions to calculate total and set that value instead of string total:
function drawChart() {
// Create the data table.
var data = new google.visualization.arrayToDataTable(array);
for (var i = 0; i < data.getNumberOfRows(); i++) {
var total = 0;
for (var j = 1; j < data.getNumberOfColumns() - 2; j++) {
// console.log(data.getValue(i, j));
total += data.getValue(i, j);
}
data.setValue(i, data.getNumberOfColumns() - 1, '' + total);
}
...
You will have to change or size of chart or size of fonts to get values properly displayed on columns. Labels are displayed correctly.
This is my answer.. i hope it helps someone with the same issue.
function getValueAt(column, dataTable, row) {
return dataTable.getFormattedValue(row, column);
}
function setLabelTotal(dataTable) {
//dataTable must have role: annotation
var SumOfRows = 0;
for (var row = 0; row < dataTable.getNumberOfRows(); row++) {
SumOfRows = 0;
for (var col = 0; col < dataTable.getNumberOfColumns(); col++) {
if (dataTable.getColumnType(col) == 'number') {
SumOfRows += dataTable.getValue(row, col);
}
if(dataTable.getColumnRole(col) == 'annotation')
{dataTable.setValue(row, col, SumOfRows.toString());}
}
}
}
Notice that you must call these methods on main function (e.g. "drawChart").