Related
I am currently working with two datasets, both in meters, but the left hand axis displays a dataset with an offset of 11.74m along the y-axis. The right hand axis ignores this offset, hence y1 == y2 when y1 = 11.74 and y2 = 0.
This being the case, is there a way to keep integer tick values on both axes despite the decimal offset between the two? Not sure if I've got the Y2 offset correct in the graph below, but I think this is roughly what I'm trying to achieve - basically fixed gridline/tick intervals of Y1 for both axes, except for Y2:
The live code I'm working on is a bit too unwieldly for Stack Overflow, but the code below roughly achieves what I'm after - would be nice if there was a way to cleanly declare an offset of -0.26 without then also having to explicitly declare the rest of the ticks:
var ticks = [5, 4, 3, 2, 1, -0.26];
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
datasets: [{
data: [0, 0.1, 0.5, 5, 3.5, 3, 3.25, 2, 1.5, 1]
}]
},
options: {
scales: {
yAxes: [{
ticks: {
autoSkip: false,
min: ticks[ticks.length - 1],
max: ticks[0]
},
afterBuildTicks: function(scale) {
scale.ticks = ticks;
return;
},
beforeUpdate: function(oScale) {
return;
}
}]
}
}
});
https://jsfiddle.net/wxp1fLk0/5/
Solution below after much fiddling. offset in the getTickArray() function specifies the left-hand axis value that coincides with 0 on the right hand axis. I think the afterBuildTicks and beforeUpdate keys then allow you to position ticks with more precision (I think).
https://jsfiddle.net/zjxukf57/47/
function getRandomDataset(lowerBound, upperBound, count) {
let output = [];
for (let index = 0; index < count; index++) {
let newPoint = Math.floor((Math.random() * upperBound) + lowerBound);
output.push(newPoint);
}
return output;
}
function arrayMin(arr) {
var len = arr.length, min = Infinity;
while (len--) {
if (arr[len] < min) {
min = arr[len];
}
}
return min;
}
function arrayMax(arr) {
var len = arr.length, max = -Infinity;
while (len--) {
if (arr[len] > max) {
max = arr[len];
}
}
return max;
}
function getTickArray(offset, increment, leftData, rightData) {
let ticksLeft = [];
let ticksRight = [];
let leftMin = arrayMin(leftData);
let leftMax = arrayMax(leftData);
let rightMin = arrayMin(rightData);
let rightMax = arrayMax(rightData);
let tick = leftMin;
let tickRight = tick - offset;
let wholeTick = Math.ceil(tick); // ? Gets first left-hand integer above minimum tick value
let wholeTickRight = Math.ceil(tickRight); // ? Gets first right-hand integer above minimum tick value
let maxValue = leftMax > rightMax + offset ? leftMax : rightMax + offset;
// ? Push minimum decimal ticks
ticksLeft.push(tick);
ticksRight.push(tickRight);
while (wholeTick < maxValue) {
ticksLeft.push(wholeTick);
ticksRight.push(wholeTickRight);
wholeTick = wholeTick + 1*increment;
wholeTickRight = wholeTickRight + 1*increment;
}
// ? Push minimum decimal ticks
ticksLeft.push(maxValue);
ticksRight.push(maxValue - offset);
return [ ticksLeft, ticksRight ];
}
let datasetOne = getRandomDataset(8, 15, 10); // ? Ten random numbers between 8 and 15
let datasetTwo = getRandomDataset(0, 7, 10); // ? Ten random numbers between 0 and 7
var ticks = getTickArray(11.76, 2, datasetOne, datasetTwo);
console.log(ticks)
var ticks1 = ticks[0];
var ticks2 = ticks[1];
console.log(datasetOne);
console.log(datasetTwo);
// ? Chart Config
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"],
datasets: [{
data: datasetOne,
yAxisID: 'A',
label: "left",
borderColor: "#FF0000",
backgroundColor: 'rgba(0, 0, 0, 0)'
},
{
data: datasetTwo,
yAxisID: 'B',
label: "right",
borderColor: "#348632",
backgroundColor: 'rgba(0, 0, 0, 0)'
}]
},
options: {
scales: {
yAxes: [{
id: 'A',
ticks: {
autoSkip: false,
min: ticks1[ticks1.length - 1],
max: ticks1[0]
},
afterBuildTicks: function(scale) {
scale.ticks = ticks1;
return;
},
beforeUpdate: function(oScale) {
return;
},
gridLines: {
color: "#FF0000"
}
},
{
id: 'B',
ticks: {
autoSkip: false,
min: ticks2[ticks2.length - 1],
max: ticks2[0],
callback: function(value, index, values) {
return value;
}
},
afterBuildTicks: function(scale) {
scale.ticks = ticks2;
return;
},
beforeUpdate: function(oScale) {
return;
},
position: "right",
gridLines: {
color: "#348632"
}
}]
}
}
});
with this code I managed to make a video. I am not a very expert on the subject, but I would think that my problem occurs because I do not know how many frames I should use. for example I want my video to last 15 seconds (I don't know how to set it, I don't know how many frames I should indicate)
var queue = d3.queue(1);
d3.range(240).forEach(function (frame) {
queue.defer(drawFrame, frame / 240);
});
queue.awaitAll(function (err, frames) {
recorder.start();
drawFrame();
function drawFrame() {
if (frames.length) {
context.drawImage(frames.shift(), 0, 0, width, height);
requestAnimationFrame(drawFrame);
} else {
recorder.stop();
}
}
});
how can I improve my code to get a smooth video?
const progressbar = document.getElementById('progressbar');
d3.select("#visualization").append('svg');
const vis = d3.select("svg").attr("width", 800).attr("height", 150).attr("xmlns", "http://www.w3.org/2000/svg").style("border", "1px solid red").style("fill", "white").style("background", "white");
const rectangle = vis.append("rect")
const circle = vis.append("circle");
let second = 0;
let interval;
const rectValues = {
"delay": 0000,
"duration": 5000,
"begin": {
"x": 0,
"y": 0,
"height": 70,
"width": 100,
"opacity": 1,
"fill": "red"
},
"destiny": {
"x": 250,
"y": 1,
"height": 100,
"width": 120,
"opacity": 0.8,
"fill": "green"
}
};
const circleValues = {
"delay": 4000,
"duration": 3000,
"begin": {
"cx": 250,
"r": 20,
"fill": "blue"
},
"destiny": {
"cx": 0,
"fill": "orange"
}
}
function startAnimation() {
//rectangle properties
startShapeAnimation(rectangle, rectValues);
//circle properties
startShapeAnimation(circle, circleValues);
}
function startShapeAnimation(shape, shapeValues) {
shape.attrs(shapeValues.begin)
.transition()
.duration(0)
.attrs(shapeValues.begin)
.transition()
.delay(shapeValues.delay)
.duration(shapeValues.duration)
.ease(d3.easeLinear)
.attrs(shapeValues.destiny);
}
startAnimation(0);
/***** CREATION OF VIDEO *******/
var canvas = document.createElement("canvas"),
width = 800,
height = 150,
context = canvas.getContext("2d");
var data = [],
stream = canvas.captureStream(),
recorder = new MediaRecorder(stream, {
mimeType: "video/webm"
});
recorder.ondataavailable = function(event) {
if (event.data && event.data.size) {
data.push(event.data);
}
};
recorder.onstop = () => {
var url = URL.createObjectURL(new Blob(data, {
type: "video/webm"
}));
//d3.selectAll("canvas, svg").remove();
d3.select("body")
.append("video")
.attr("src", url)
.attr("controls", true)
.attr("autoplay", true);
};
var queue = d3.queue(1);
d3.range(240).forEach(function(frame) {
queue.defer(drawFrame, frame / 240);
});
queue.awaitAll(function(err, frames) {
recorder.start();
drawFrame();
function drawFrame() {
if (frames.length) {
context.drawImage(frames.shift(), 0, 0, width, height);
requestAnimationFrame(drawFrame);
} else {
recorder.stop();
}
}
});
function drawFrame(t, cb) {
var img = new Image(),
serialized = new XMLSerializer().serializeToString(vis.node()),
url = URL.createObjectURL(new Blob([serialized], {
type: "image/svg+xml"
}));
img.onload = function() {
cb(null, img);
};
img.src = url;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<div id="visualization"></div>
<div id="contenedor_canvas"></div>
Instead of limiting yourself to 240 frames, try to get as many as possible using requestAnimationFrame. Using this answer as inspiration, I was able to generate a much smoother video.
const progressbar = document.getElementById('progressbar');
d3.select("#visualization").append('svg');
const vis = d3.select("svg").attr("width", 800).attr("height", 150).attr("xmlns", "http://www.w3.org/2000/svg").style("border", "1px solid red").style("fill", "white").style("background", "white");
const rectangle = vis.append("rect")
const circle = vis.append("circle");
let second = 0;
let interval;
const rectValues = {
"delay": 0000,
"duration": 5000,
"begin": {
"x": 0,
"y": 0,
"height": 70,
"width": 100,
"opacity": 1,
"fill": "red"
},
"destiny": {
"x": 250,
"y": 1,
"height": 100,
"width": 120,
"opacity": 0.8,
"fill": "green"
}
};
const circleValues = {
"delay": 4000,
"duration": 3000,
"begin": {
"cx": 250,
"r": 20,
"fill": "blue"
},
"destiny": {
"cx": 0,
"fill": "orange"
}
}
function startAnimation() {
//rectangle properties
startShapeAnimation(rectangle, rectValues);
//circle properties
startShapeAnimation(circle, circleValues);
}
function startShapeAnimation(shape, shapeValues) {
shape.attrs(shapeValues.begin)
.transition()
.duration(0)
.attrs(shapeValues.begin)
.transition()
.delay(shapeValues.delay)
.duration(shapeValues.duration)
.ease(d3.easeLinear)
.attrs(shapeValues.destiny);
}
startAnimation(0);
/***** CREATION OF VIDEO *******/
var canvas = document.createElement("canvas"),
width = 800,
height = 150,
context = canvas.getContext("2d");
var data = [],
stream = canvas.captureStream(),
recorder = new MediaRecorder(stream, {
mimeType: "video/webm"
});
recorder.ondataavailable = function(event) {
if (event.data && event.data.size) {
data.push(event.data);
}
};
recorder.onstop = () => {
var url = URL.createObjectURL(new Blob(data, {
type: "video/webm"
}));
//d3.selectAll("canvas, svg").remove();
d3.select("body")
.append("video")
.attr("src", url)
.attr("controls", true)
.attr("autoplay", true);
};
var lengthInSeconds = 15;
var lengthInMS = lengthInSeconds * 1000;
var startTime = Date.now();
startRecording();
drawFrame();
function startRecording() {
recorder.start();
drawFrame();
}
function drawFrame() {
var elapsedTime = Date.now() - startTime;
if (elapsedTime > lengthInMS) {
stopRecording();
return;
}
console.log(((elapsedTime / lengthInMS) * 100).toFixed(2) + '%');
requestAnimationFrame(drawFrame);
var img = new Image(),
serialized = new XMLSerializer().serializeToString(vis.node()),
url = URL.createObjectURL(new Blob([serialized], {
type: "image/svg+xml"
}));
img.onload = function() {
context.drawImage(img, 0, 0, width, height);
};
img.src = url;
}
function stopRecording() {
recorder.stop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.js"></script>
<script src="https://d3js.org/d3-selection-multi.v1.min.js"></script>
<div id="visualization"></div>
<div id="contenedor_canvas"></div>
I'm creating a Stacked bar chart. Everything is working as expected except the tooltips. One bar is behind the other one (Kinda like a progress bar) and the problem is that once one bar is getting closer to the other one, the tooltips overlap. So, my question is if I can set "yAlign" position for each data(or each bar) so that I can display the tooltips on the top for one set of bars, and on the bottom to the other set of bars.
Here's my code:
<script>
var ctx = document.getElementById("examples").getContext('2d');
var data = {
labels:[
"A", "B", "C",],
datasets: [{
label: false,
data: [40, 110, 18],
backgroundColor: [
'rgba(255, 99, 132, 0.7)',
'rgba(158, 112, 225, 0.7)',
'rgba(174, 122, 215, 0.7)',
]
},
{
label: false,
data: [100, 200, 50],
backgroundColor: [
'rgb(128,128,128)',
'rgb(128,128,128)',
'rgb(128,128,128)',
]
},
]
};
var currentX = null;
var currentY = null;
var customTooltips = function (tooltip) {
var helpers = Chart.helpers;
var ctx = this._chart.ctx;
var vm = this._view;
if (vm == null || ctx == null || helpers == null || vm.opacity === 0) {
return;
}
var tooltipSize = this.getTooltipSize(vm);
var pt = {
x: vm.x,
y: vm.y
};
if (currentX == vm.x && currentY == vm.y) {
return;
}
currentX = vm.x;
currentY = vm.y;
// IE11/Edge does not like very small opacities, so snap to 0
var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;
// Draw Background
var bgColor = helpers.color(vm.backgroundColor);
ctx.fillStyle = bgColor.alpha(opacity * bgColor.alpha()).rgbString();
helpers.drawRoundedRectangle(ctx, pt.x, pt.y, tooltipSize.width, tooltipSize.height, vm.cornerRadius);
ctx.fill();
// Draw Caret
this.drawCaret(pt, tooltipSize, opacity);
// Draw Title, Body, and Footer
pt.x += vm.xPadding;
pt.y += vm.yPadding;
// Titles
this.drawTitle(pt, vm, ctx, opacity);
// Body
this.drawBody(pt, vm, ctx, opacity);
// Footer
this.drawFooter(pt, vm, ctx, opacity);
};
Chart.plugins.register({
beforeRender: function (chart) {
if (chart.config.options.showAllTooltips) {
// create an array of tooltips
// we can't use the chart tooltip because there is only one tooltip per chart
chart.pluginTooltips = [];
chart.config.data.datasets.forEach(function (dataset, i) {
chart.getDatasetMeta(i).data.forEach(function (sector, j) {
chart.pluginTooltips.push(new Chart.Tooltip({
_chart: chart.chart,
_chartInstance: chart,
_data: chart.data,
_options: chart.options.tooltips,
_active: [sector]
}, chart));
});
});
// turn off normal tooltips
chart.options.tooltips.enabled = false;
}
},
afterDraw: function (chart, easing) {
if (chart.config.options.showAllTooltips) {
// we don't want the permanent tooltips to animate, so don't do anything till the animation runs atleast once
if (!chart.allTooltipsOnce) {
if (easing !== 1)
return;
chart.allTooltipsOnce = true;
}
// turn on tooltips
chart.options.tooltips.enabled = true;
Chart.helpers.each(chart.pluginTooltips, function (tooltip) {
// This line checks if the item is visible to display the tooltip
if(!tooltip._active[0].hidden){
tooltip.initialize();
// tooltip._options.position = "outer";
// tooltip._options.displayColors = false;
// tooltip._options.bodyFontSize = tooltip._chart.height*0.025;
//tooltip._options.yPadding = tooltip._options.bodyFontSize*0.30;
// tooltip._options.xPadding = tooltip._options.bodyFontSize*0.30;
//tooltip._options.caretSize = tooltip._options.bodyFontSize*0.5;
//tooltip._options.cornerRadius = tooltip._options.bodyFontSize*0.50;
tooltip.update();
// we don't actually need this since we are not animating tooltips
tooltip.pivot();
tooltip.transition(easing).draw();
}
});
chart.options.tooltips.enabled = false;
}
}
})
var myPieChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
showAllTooltips: true,
legend: {
display: false
},
tooltips: {
titleFontSize: 10,
bodyFontSize: 10,
pointHitDetectionRadius : 3,
yAlign: 'top',
responsive: false,
customTool: customTooltips,
callbacks: {
title: function() {}
},
},
scales:{
xAxes: [{
stacked: true,
ticks: {
beginAtZero: true
},}]
},
}
});
</script>
JSFiddle: https://jsfiddle.net/560gortq/2/
I'm using Vue JS and I have 2 canvases in my component (I'm trying to recreate this answer).
Template part of component:
<template>
<div class="d-flex flex-column">
<div class="d-flex flex-column" style="height: 300px;">
<canvas ref="overlay" id="overlay" style="position: absolute; pointer-events: none"></canvas>
<canvas ref="canvas" :id="canvasId"></canvas>
</div>
<vue-slider #drag-end="selectRange" class="w-100 mb-3 mx-3 p-0 pr-3" ref="slider" v-model="sliderValue" v-bind="sliderOptions"></vue-slider>
</div>
</template>
Script part of component:
<script>
import chartjs from "chart.js";
import vueSlider from "vue-slider-component";
import {Line} from "vue-chartjs";
const props = {
dataset: {
type: Array,
required: true
},
index: {
type: Number,
required: true
},
sliderShow: {
type: Boolean,
required: true
}
};
export default {
components: { vueSlider },
extends: Line,
name: "rhythmogram",
props,
data() {
return {
canvasId: "",
sliderValue: [],
sliderOptions: {
tooltip: "hover",
"tooltip-dir": "bottom",
overlapFormatter: "{value1} - {value2}",
tooltipStyle: {
"borderRadius": "0px"
},
useKeyboard: true,
data: []
},
chartData: [],
xLabels: []
};
},
mounted() {
this.canvasId = `areachart${this.index}`;
this.$nextTick(() => {
// ...
// filling this.chartData and this.xLabels
// ...
this.renderChart({
labels: this.xLabels,
datasets: [{
label: this.name,
data: this.chartData
}]
}, {
maintainAspectRatio: false,
elements: {
line: {
tension: 0.2,
borderWidth: 1,
borderColor: "rgba(24, 81, 154, .95)",
backgroundColor: "rgba(24, 81, 154, .5)"
},
point: {
pointStyle: "circle",
radius: 0
}
},
tooltips: {
enabled: false
},
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
min: minValueToDisplay,
max: maxValueToDisplay
}
}],
xAxes: [{
ticks: {
stepSize: 10
}
}]
}
});
// Overlay
var canvas = this.$refs.canvas;
var overlay = this.$refs.overlay;
var chart = this._data._chart;
var startIndex = 0;
var endIndex = 0;
overlay.width = canvas.width;
overlay.height = canvas.height;
console.log(canvas); //this returns the correct element with width and height > 0
console.log("Width:\t" + canvas.width); //this returns 0
console.log("Height:\t" + canvas.height); // this returns 0
var selectionContext = overlay.getContext('2d');
var selectionRect = {
w: 0,
startX: 0,
startY: 0
};
var drag = false;
canvas.addEventListener('pointerdown', evt => {
const points = chart.getElementsAtEventForMode(evt, 'index', {
intersect: false
});
startIndex = points[0]._index;
const rect = canvas.getBoundingClientRect();
selectionRect.startX = evt.clientX - rect.left;
selectionRect.startY = chart.chartArea.top;
drag = true;
});
canvas.addEventListener('pointermove', evt => {
const rect = canvas.getBoundingClientRect();
if (drag) {
const rect = canvas.getBoundingClientRect();
selectionRect.w = (evt.clientX - rect.left) - selectionRect.startX;
selectionContext.globalAlpha = 0.5;
selectionContext.clearRect(0, 0, canvas.width, canvas.height);
selectionContext.fillRect(selectionRect.startX, selectionRect.startY, selectionRect.w, chart.chartArea.bottom -
chart.chartArea.top);
} else {
selectionContext.clearRect(0, 0, canvas.widht, canvas.height);
var x = evt.clientX - rect.left;
if (x > chart.chartArea.left) {
selectionContext.fillRect(x, chart.chartArea.top, 1, chart.chartArea.bottom - chart.chartArea.top);
}
}
});
canvas.addEventListener('pointerup', evt => {
const points = chart.getElementsAtEventForMode(evt, 'index', {
intersect: false
});
drag = false;
console.log('selected: ' + this.sliderOptions.data[startIndex] + ', ' + this.sliderOptions.data[points[0]._index]);
});
});
},
methods: {
selectRange() {
// stuff
}
},
watch: {
sliderShow(val) {
// stuff
}
}
};
</script>
I have commented the lines where it returns 0 for the width and height.
I found out that it works when I give my canvas a set width and height as an HTML attribute and set the ChartJS chart to responsive: false in its options.
But I need a responsive chart. And in the answer of the stackoverflow post I linked above it is working with a responsive chart.
I also tried getting the element with pure JS and jQuery to see if thats the culprit but to no avail.
Any help is appreciated. If any information is missing please tell me.
First I am a beginner in JS
I am using Amcharts to display some sensor values.
First i wrote it s´traight forward as in the Amcharts documentation.
var chart = AmCharts.makeChart("chartdiv", {
"type": "serial",
"theme": "light",
"marginRight": 40,
"marginLeft": 200,
"autoMarginOffset": 20,
"mouseWheelZoomEnabled":true,
"dataDateFormat": "YYYY-MM-DD-JJ:NN:SS",
"valueAxes": [{
"id": "v1",
"axisAlpha": 1,
"position": "left",
"ignoreAxisWidth":true,
"precision": 2,
"axisColor": PosColor1,
}],
"balloon": {
"borderThickness": 1,
"shadowAlpha": 0
},
"graphs": [{
"valueAxis": "v1",
"id": "Graph1",
"lineColor": PosColor1,
"negativeLineColor": NegColor1,
//"bullet": "round",
//"bulletBorderThickness": 1,
//"hideBulletsCount": 30,
"title": ChartValue1,
"valueField": ChartValue1,
//"fillAlphas": 0,
"balloonText": "<span style='font-size:22;'>[[Heizkurve]]</span>",
"balloonFunction": function(item, graph) {
var result = graph.balloonText;
for (var key in item.dataContext) {
if (item.dataContext.hasOwnProperty(key) && !isNaN(item.dataContext[key])) {
var formatted = AmCharts.formatNumber(item.dataContext[key], {
precision: chart.precision,
decimalSeparator: chart.decimalSeparator,
thousandsSeparator: chart.thousandsSeparator
}, 2);
result = result.replace("[[" + key + "]]", formatted);
}
}
return result;
}
}],
"chartScrollbar": {
"graph": "g1",
"oppositeAxis":false,
"offset":10,
"scrollbarHeight": 40,
"backgroundAlpha": 0,
"selectedBackgroundAlpha": 0.1,
"selectedBackgroundColor": "#888888",
"graphFillAlpha": 0,
"graphLineAlpha": 0.5,
"selectedGraphFillAlpha": 0,
"selectedGraphLineAlpha": 1,
"autoGridCount":true,
"color":"#AAAAAA"
},
"chartCursor": {
//"pan": true,
//"valueLineEnabled": true,
//"valueLineBalloonEnabled": true,
"categoryBalloonDateFormat": "MMM DD JJ:NN",
"cursorAlpha":1,
"cursorColor":"#258cbb",
"limitToGraph":"g1",
"valueLineAlpha":0.2,
//"valueZoomable":true
},
"categoryField": "date",
"categoryAxis": {
"parseDates": true,
"minPeriod": "fff",
"dashLength": 1,
"minorGridEnabled": true
},
"export": {
"enabled": true
},
"dataLoader": {
"url": file,
"format": "csv",
"showCurtain": true,
"showErrors": true,
"async": true,
"reload": 0,
//"timestamp": true,
"delimiter": ",",
"useColumnNames": true
},
........;
Now I tried to generate the chart object based, cause I want to update it dynamically with different data.
But when I added the "categoryAxis.oarseDate = true" then no chart will be displayed.
If i comment it out, graph is drawn but X axis is not formatted as date like before.
chart.dataProvider = chartData;
chart.categoryField = "date";
chart.addListener("dataUpdated", zoomChart);
var categoryAxis = chart.categoryAxis;
categoryAxis.minPeriod="fff";
categoryAxis.parseDates = true;
Using the same .csv als data source.
Just load it with the Amcharts function "AmChartsLoadCSV"
function AmChartsLoadCSV(file,chart){
var newchart = new AmCharts.AmSerialChart();
newchart = chart;
AmCharts.loadFile(file, {}, function(data) {
var chartData = AmCharts.parseCSV(data, {
"delimiter": ",",
"useColumnNames": true,
"showCurtain": true,
"showErrors": true
});
var chart1 = MakeChart(chartData);
AddGraphtoChart(chart1,6);
return chart1;
});
solved!
according to the samples and democode I had a double definition for the Date axis.
I defined a general DateFormat for the Chart chart.dataDateFormat="YYYY-MM-DD-JJ:NN:SS";cause it was in the Amcharts doc.
After deleting this, the categoryAxis.parseDates = true; works fine