chartjs / chartjs/chartjs-chart-financial
Using classic chart from Chart.js and a financial chart: Uncaught TypeError: Class extends value undefined is not a constructor or null
- Dominant language
- JavaScript
- Stars
- 809
- Forks
- 199
- PR merge metrics
- No merged PRs in 30d
Description
Hi mate,
I've run into a problem with employing your financial chart module together with another canvas displaying a chart from chart.js.
The browser console points the "Uncaught TypeError: Class extends value undefined is not a constructor or null" error
to line 235 in chartjs-chart-financial.js:
`class FinancialController extends Chart.BarController { ... }`
Here are two templates being used in node red which are loaded into the front end. Both reference to individual canvasses with different IDs. (As you will see below, I try to destroy any previously existing chart instance)
First script:
```
Bar Type:
Candlestick
OHLC
Scale Type:
Linear
Logarithmic
Color Scheme:
Muted
Neon
Border:
Yes
No
Update
Randomize Data
(function(scope) {
var timer = setInterval(function() { //check that the luxon and other libs are loaded, if not wait
if (!window.luxon) return;
clearInterval(timer);
var barCount = 60;
var initialDateStr = '01 Apr 2017 00:00 Z';
debugger;
var ctx = document.getElementById('candleStickChart').getContext('2d');
ctx.canvas.width = 1000;
ctx.canvas.height = 250;
if (chart)
chart.destroy();
var chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
data: getRandomData(initialDateStr, barCount)
}]
}
});
var getRandomInt = function(max) {
return Math.floor(Math.random() * Math.floor(max));
};
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
function randomBar(date, lastClose) {
var open = randomNumber(lastClose * 0.95, lastClose * 1.05).toFixed(2);
var close = randomNumber(open * 0.95, open * 1.05).toFixed(2);
var high = randomNumber(Math.max(open, close), Math.max(open, close) * 1.1).toFixed(2);
var low = randomNumber(Math.min(open, close) * 0.9, Math.min(open, close)).toFixed(2);
return {
t: date.valueOf(),
o: open,
h: high,
l: low,
c: close
};
}
function getRandomData(dateStr, count) {
var date = luxon.DateTime.fromRFC2822(dateStr);
var data = [randomBar(date, 30)];
while (data.length < count) {
date = date.plus({days: 1});
if (date.weekday <= 5) {
data.push(randomBar(date, data[data.length - 1].c));
}
}
return data;
}
var update = function() {
var dataset = chart.config.data.datasets[0];
// candlestick vs ohlc
var type = document.getElementById('type').value;
dataset.type = type;
// linear vs log
var scaleType = document.getElementById('scale-type').value;
chart.config.options.scales.y.type = scaleType;
// color
var colorScheme = document.getElementById('color-scheme').value;
if (colorScheme === 'neon') {
dataset.color = {
up: '#01ff01',
down: '#fe0000',
unchanged: '#999'
};
} else {
delete dataset.color;
}
var border = document.getElementById('border-color').value;
var defaultOpts = Chart.defaults.elements[type];
if (border === 'true') {
dataset.borderColor = defaultOpts.borderColor;
} else {
dataset.borderColor = {
up: defaultOpts.color.up,
down: defaultOpts.color.down,
unchanged: defaultOpts.color.up
};
}
chart.update();
};
document.getElementById('update').addEventListener('click', update);
document.getElementById('randomizeData').addEventListener('click', function() {
chart.data.datasets.forEach(function(dataset) {
dataset.data = getRandomData(initialDateStr, barCount);
});
update();
});
}, 100); // close out the setInterval
})(scope);
```
Second script:
```
//(function(scope) {
var ctx = document.getElementById("avgPriceChangesChart");
var numberOfSignals = '{{flow.selected_symbol_avgByNumberOfSignals}}';
var shortestPriceSeries = '{{flow.selected_symbol_shortestPriceSeries}}';
var omittedPriceSeries = '{{flow.selected_symbol_omittedPriceSeries}}';
var symbol = '{{flow.selected_symbol}}';
var demoData = {
labels: ["D1", "D2", "D3", "D4", "D5", "D6"],
datasets: [
{
label: "Signal 1",
backgroundColor: 'rgb(255, 99, 132)',
data: [0.2,-0.4,0.6,0.9,0.4,0.5]
},
{
label: "Signal 2",
backgroundColor: 'rgb(132, 99, 255)',
data: [-0.3,0.5,0.6,0.4,0.2,0.6]
},
{
label: "Signal 3",
backgroundColor: 'rgb(132, 255, 99)',
data: [0.1,-0.1,0.4,-0.2,0.4,0.8]
}
]
};
function createChart(someData) {
var avgPriceChangesChart = new Chart(ctx, {
type: "bar",
data: someData,
options: {
animation: {duration: 0},
title: {
responsive: true,
display: true,
text: "Averaged Price Changes (%) after " + numberOfSignals + " signals occurred in " + symbol
+ ".\nShortest price series: " + shortestPriceSeries + "\n"
+ ".\nOmitted price series (due to <20 price changes): " + omittedPriceSeries + "\n",
fontSize: 16,
fontColor: 'rgb(255,255,255)'
},
legend: {
display: true,
fontColor: 'white',
position: 'top'
},
maintainAspectRatio: false,
scales: {
xAxes: [{
barPercentage: 1.0,
barThickness: 6, // number (pixels) or 'flex'
maxBarThickness: 8, // number (pixels)
stacked: false,
gridLines: {
color: 'rgb(96,96,96)',
display: true
},
ticks: {
fontColor: 'white',
autoSkip: false
}
}],
yAxes: [{
stacked: false,
gridLines: {
color: 'rgb(96,96,96)',
display: true
},
ticks: {
beginAtZero: true,
fontColor: 'white',
min: -1,
max: 1
}//,
/*type: 'logarithmic'
afterBuildTicks: function (chartObj) { //Build ticks labelling as per your need
chartObj.ticks = [];
chartObj.ticks.push(0.01);
chartObj.ticks.push(0.1);
chartObj.ticks.push(1);
chartObj.ticks.push(10);
chartObj.ticks.push(100);
}//*/
}]
}
}
});
return avgPriceChangesChart;
}
/*if (avgPriceChangesChart !== undefined && Boolean(avgPriceChangesChart)) {
//alert("Trying to destroy old chart instance...");
debugger;
avgPriceChangesChart.destroy();
}*/
// for simplicity create a chart with simple demo data only. Nothing fancy.
avgPriceChangesChart = createChart(demoData); //msg.payload.data);
/*scope.$watch('msg', function(msg) {
if (msg) {
if (avgPriceChangesChart !== undefined && Boolean(avgPriceChangesChart)) {
//alert("Trying to destroy old chart instance...");
debugger;
avgPriceChangesChart.destroy();
}*/
/* debugger;
avgPriceChangesChart = createChart(msg.payload.data);
//avgPriceChangesChart.data.datasets[0].data[2] = 50; // Would update the first dataset's value of 'March' to be 50
//avgPriceChangesChart.data = msg.payload.data;
//avgPriceChangesChart["data"] = msg.payload.data;
avgPriceChangesChart.update();
}
});*/
//}) (scope);
```
The whole stack trace from the console looks as follows:
```
app.min.js:20 Uncaught TypeError: Class extends value undefined is not a constructor or null
at :238:41
at :14:76
at :15:2
at b (app.min.js:20)
at Function.globalEval (app.min.js:20)
at Object.dataFilter (app.min.js:20)
at app.min.js:20
at l (app.min.js:20)
at XMLHttpRequest. (app.min.js:20)
at Object.send (app.min.js:20)
....
VM2648 chart.js:5161 Uncaught Error: "candlestick" is not a registered controller.
at Registry._get (VM2648 chart.js:5161)
at Registry.getController (VM2648 chart.js:5106)
at Chart.buildOrUpdateControllers (VM2648 chart.js:6188)
at Chart.update (VM2648 chart.js:6227)
at new Chart (VM2648 chart.js:5988)
at :20:21
_get @ VM2648 chart.js:5161
getController @ VM2648 chart.js:5106
buildOrUpdateControllers @ VM2648 chart.js:6188
update @ VM2648 chart.js:6227
Chart @ VM2648 chart.js:5988
(anonymous)
VM2648 chart.js:5945 Uncaught Error: Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused.
at new Chart (VM2648 chart.js:5945)
at :20:21
Chart @ VM2648 chart.js:5945
(anonymous)
VM2648 chart.js:5161 Uncaught Error: "candlestick" is not a registered controller.
at Registry._get (VM2648 chart.js:5161)
at Registry.getController (VM2648 chart.js:5106)
at Chart.buildOrUpdateControllers (VM2648 chart.js:6188)
at Chart.update (VM2648 chart.js:6227)
at Chart._resize (VM2648 chart.js:6053)
at Chart.resize (VM2648 chart.js:6027)
at listener (VM2648 chart.js:6509)
at VM2648 chart.js:1776
at VM2648 chart.js:34
```
I would be very much appreciate any hints to what I'm doing wrong.
Cheers,
Marcel
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.