Draw a moving vertical line representing the current date in amcharts gantt chart? - amcharts4

I am using amCharts4 and is able to plot a vertical line on my Gantt chart representing the current date time as described in the following : Draw a vertical line representing the current date in amcharts gantt chart?. However, how do I make the vertical line move every sec on the chart based on the current time? Here is the code :
var range = dateAxis.axisRanges.create();
range.date = new Date("2020-10-29 07:04:56");
range.grid.stroke = am4core.color("red");
range.grid.strokeWidth = 2;
range.grid.strokeOpacity = 1;

You can add a setInterval that runs every second to update the date on your range, like this:
// First, create your range marker
var range = dateAxis.axisRanges.create();
range.grid.stroke = am4core.color("red");
range.grid.strokeWidth = 2;
range.grid.strokeOpacity = 1;
range.date = new Date();
// Then, update the position of your range marker every second
range.date = new Date(2018, 0, 1, 8, 0, 0, 0);
var timeout = window.setInterval(() => {
range.date = new Date(range.date.getTime() + 1000);
}, 1000);
chart.events.on('beforedisposed', () => {
clearTimeout(timeout);
});
Here is an example
UPDATE
One thing you want to do with the timeout is to also clear it when you no longer need it--- for example, when you dispose the chart or the marker.
I have updated the code above to clear it before the chart is disposed.

Related

Chartjs unexpected visual animation effect when adding data

I have a long array with data that I slice with Javascript in order to display data of different date ranges in my chart. This way the backend only needs to get the data once, and I can the just slice it on the client side.
// All data
var allLabels = [
// data here
];
var allData = [
// data here
];
Then I do:
var labelsCount = allLabels.length;
var dataCount = allData.length;
var updatedLabels;
var updatedData;
if($date_range === 'last_7_days')
{
updatedLabels = allLabels.slice(labelsCount - 7);
updatedData = allData.slice(labelsCount - 7);
}
if($date_range === 'last_30_days')
{
updatedLabels = allLabels.slice(labelsCount - 30);
updatedData = allData.slice(labelsCount - 30);
}
scoreChart.data.labels = updatedLabels;
scoreChart.data.datasets[0].data = updatedData;
scoreChart.update({
duration: 1000,
easing: 'easeInOutExpo'
});
This all works as expected. When switching from 30 to 7 days the points on the right of the 7 days disappear, and the graph scales and grows nicely to the new 7 days x-axis.
The other way around, when you have the graph of 7 days and then switch to 30, produces an ugly visual effect where the first point of the graph sticks to the side, overlaps the new data points and then animates.
After the animation the graph looks as expected, it's just the animation that's ugly. It's a little tricky to explain so hopefully the screenshots help. Green arrows indicate the animation direction. I've set the animation duration to 10s so I can take this screenshot, the red circle highlights the point that starts on the right of the graph and then animates to the left.
I've also tried adding this:
scoreChart.data.labels.pop();
scoreChart.data.datasets[0].data.pop();
scoreChart.update();
and this:
scoreChart.data.labels = [];
scoreChart.data.datasets[0].data = [];
scoreChart.update();
Before the line scoreChart.data.labels = updatedLabels; but that gives the same result.
Another thing I can do is only update the labels. The result is that the chart just zooms on the timeline when changing date ranges, without the nice animation as they have in the example.
You could try to first remove all labels and the data when switching to 'last_30_days'.
if($date_range === 'last_30_days')
{
scoreChart.data.labels = [];
scoreChart.data.datasets[0].data = [];
scoreChart.update({
duration: 500,
easing: 'easeInOutExpo'
});
updatedLabels = allLabels.slice(labelsCount - 30);
updatedData = allData.slice(labelsCount - 30);
}

Sending data to ChartJsLineChart in ChartJs.Blazor

I am using ChartJsLineChart in ChartJs.Blazor nuget, and I am stuck at sending data to ChartJsLineChart.
All the examples including this one
http://blazorhelpwebsite.com/Blog/tabid/61/EntryId/4363/Adding-Charts-To-Server-Side-Blazor-Using-ChartJs-Blazor.aspx
uses TimeTuple as a way to add data to dataset
_WeightDataSet = new LineDataset<TimeTuple<int>>
{
BackgroundColor = ColorUtil.FromDrawingColor(System.Drawing.Color.White),
BorderColor = ColorUtil.FromDrawingColor(System.Drawing.Color.Red),
Label = "Weight per Day",
Fill = false,
BorderWidth = 2,
PointRadius = 2,
PointBorderWidth = 2,
SteppedLine = SteppedLine.False,
Hidden = false
};
I am wondering what would be an alternative to TimeTuple. I tried using Tuple but that resulted with a blank chart ie. no YValues where not recognized.
You can use any reference type supported by ChartJs.Blazor to add data to the chart. I identified 3 main categories of types of data that are used with line charts.
1) If you simply want to use a (double/int) value type along both x-axis and y-axis then you can use the ChartJs.Blazor.ChartJS.Common.Point data type. For e.g.
_WeightDataSet = new LineDataset<ChartJs.Blazor.ChartJS.Common.Point>
{
BackgroundColor = ColorUtil.FromDrawingColor(System.Drawing.Color.White),
BorderColor = ColorUtil.FromDrawingColor(System.Drawing.Color.Red),
Label = "Weight per Day",
Fill = false,
BorderWidth = 2,
PointRadius = 2,
PointBorderWidth = 2,
SteppedLine = SteppedLine.False,
Hidden = false
};
You might also have to configure the xAxes in the config to a LinearCartesianAxis object for this to work.
2) If you want the x-axis to have a time value whereas the y-axis to have a double value then you need to use TimeTuple as mentioned in the example quoted by you. You might also have to configure the xAxes object in the config to be a TimeAxis object.
3) If you want double (or int) value to be plotted along y-axis against string labels on the x-axis then you need to use Wrappers provided in the ChartJs.Blazor.ChartJS.Common.Wrappers namespace and configure the xAxes to a CategoryAxis object in the config. An example of this is provided in the code hosted on https://github.com/LearnC0de/BlazorAppLineChart/blob/master/BlazorAppLineChart/BlazorAppLineChart/Pages/LineChart.razor

Change bar color depending on value

I'm using chart-js/ng2-charts for an angular 2 app.
I can display a bar graph, but at the moment, all the bars are the same color. I'd like to have a different color depending on the value.
Can that be done?
After you create your chart, you can use the following function to loop through the dataset and change the color depending on the data value.
In this example, if the value is above a 50, the color changes to red.
var colorChangeValue = 50; //set this to whatever is the deciding color change value
var dataset = myChart.data.datasets[0];
for (var i = 0; i < dataset.data.length; i++) {
if (dataset.data[i] > colorChangeValue) {
dataset.backgroundColor[i] = chartColors.red;
}
}
myChart.update();
JSFiddle Demo: https://jsfiddle.net/6d0jsyxu/1/

amchart regular numeric scale on category axis in x-axis

I'm new to programming and now I want to give custom label on categoryAxies in line chart.
But that label should be regular(like 0,50,100,150).
This is my format of data.
59.0472,0.0318
69.071,0.0271
72.0913,0.0271
81.0674,0.0334
81.0734,0.0382
83.0596,0.0717
83.0894,0.0605
85.0817,0.035
85.1053,0.0287
86.0675,0.0318
87.1001,0.0287
90.6657,0.0382
I want x-axis as 0, 50 , 60, etc.
Also i have mentioned the category axis code in below
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = false;
categoryAxis.autoGridCount =false;
categoryAxis.dashLength = 1;
categoryAxis.gridCount = 6;
categoryAxis.gridAlpha = 0.15;
categoryAxis.minorGridEnabled = true;
categoryAxis.axisColor = "#DADADA";
If you X axis should be numeric, than I would recommend you using XY chart instead of Serial, for example: http://www.amcharts.com/javascript-charts/scatter/

raphaeljs: drag and apply transformation to Paper.set()

I started to play a little bit with raphaeljs, however I'm having a small problem when dragging and applying a transformation to a Paper.set()
Here is my example: http://jsfiddle.net/PQZmp/2/
1) Why is the drag event added only to the marker and not the slider?
2) The transformation is supposed to be relative(i.e. translate by and not translate to), however if I drag the marker twice, the second dragging starts from the beginning and not from the end of the first.
EDIT:
After the response of Zero, I created a new JSFiddle example: http://jsfiddle.net/9b9W3/1/
1) It would be cool if this referenced the set instead of the first element of the set. Can't this be done with dragger.apply(slider)? I tried it, but only works on the first execution of the method (perhaps inside Raphael it is already being done but to the first element inside the set instead of the set)
2) According to Raphael docs the transformation should be relative to the object position (i.e. translate by and not translate to). But it is not what is happening according to the jsfiddle above (check both markers drag events).
3) So 2) above creates a third question. If a transform("t30,0") is a translation by 30px horizontally, how is the origin calculated? Based on attr("x") or getBBox().x?
The drag event is actually being added to both the marker and the slider -- but your slider has a stroke-width of 1 and no fill, so unless you catch the exact border, the click "falls through" to the canvas.
Behind that is another issue: the drag is being applied to both elements, but this in your drag handler references a specific element, not the set -- so both elements will drag independently from each other.
Lastly: the reason that each drag is starting from the initial position is because the dx, dy parameters in dragger are relative to the coordinates of the initial drag event, and your transform does not take previous transforms into account. Consider an alternative like this:
var r = new Raphael(0, 0, 400, 200);
var marker = r.path("M10,0L10,100").attr({"stroke-width": 5});
var button = r.rect(0, 0, 20, 20, 1).attr( { 'stroke-width': 2, fill: 'white' } );
var slider = r.set( marker, button );
var startx, starty;
var startDrag = function(){
var bbox = slider.getBBox();
startx = bbox.x;
starty = bbox.y;
console.log(this);
}, dragger = function(dx, dy){
slider.transform("t" + ( startx + dx ) + "," + starty );
}, endDrag = function(){
};
slider.drag(dragger, startDrag, endDrag);
To address your updates:
I believe you can specify the context in which the drag function will be executed as optional fourth, fifth, and six parameters to element.drag. I haven't tried this myself, but it looks like this should work great:
slider.drag( dragger, startDrag, endDrag, slider, slider, slider );
The transformation is relative to the object position. This works great for the first slider because its starting position is 0, but not so great for the second slider because...
...the transformation for min/max sliders should actually be relative to the scale, not the individual markers. Thus you will notice that your max slider (the red one) returns to its initial position just as you drag the mouse cursor back over the zero position. Make sense?
var position;
var rect = paper.rect(20, 20, 40, 40).attr({
cursor: "move",
fill: "#f00",
stroke: "#000"
});
t = paper.text(70,70, 'test').attr({
"font-size":16,
"font-family":
"Arial, Helvetica, sans-serif"
});
var st = paper.set();
st.push(rect, t);
rect.mySet = st;
rect.drag(onMove, onStart, onEnd);
onStart = function () {
positions = new Array();
this.mySet.forEach(function(e) {
var ox = e.attr("x");
var oy = e.attr("y");
positions.push([e, ox, oy]);
});
}
onMove = function (dx, dy) {
for (var i = 0; i < positions.length; i++) {//you can use foreach but I want to
// show that is a simple array
positions[i][0].attr({x: positions[i][1] + dx, y: positions[i][2] + dy});
}
}
onEnd = function() {}