Can i use crosshairs with OHLC/candlestick charts using ChartJS - javascript

I have installed the crosshair plugin and am using chartJS 3.0 to take advantage of the candlestick charts but the crosshair does not appear. are these things compatible together? my data appear no problem but the crosshair never appears. how do i use these two things together? are there any working examples?
the tags i am using
<script src="https://cdn.jsdelivr.net/npm/luxon#1.24.1"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.0.0-beta.9/dist/chart.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon#0.2.1"></script>
<script src="https://dd7tel2830j4w.cloudfront.net/f1614793727236x392906938665549250/chartjs-chart-financial.js"></script>
<script scr="https://cdn.jsdelivr.net/npm/chartjs-plugin-crosshair"></script>
and the chart code which also works
var divID = "chartContainer" + properties.chartid
var chartID = "myChart" + properties.chartid
instance.canvas.append('<div id="' + divID + '"></div>')
document.getElementById(divID).innerHTML = ' ';
document.getElementById(divID).innerHTML = '<canvas id=' + chartID + ' width="' + properties.bubble.width() + '" height="' + properties.bubble.height() + '"></canvas>';
var ctx = document.getElementById(chartID).getContext('2d');
var chart = new Chart(ctx, {
type: 'candlestick',
data: {
datasets: [{
label: 'CHRT - Chart.js Corporation',
data: getData()
}]
},
options: {
scales: {
y: {
min: 0,
max: 500
}
},
tooltips: {
mode: "interpolate",
intersect: false
},
plugins: {
crosshair: {
line: {
color: '#F66', // crosshair line color
width: 3, // crosshair line width
dashPattern: [5, 5] // crosshair line dash pattern
},
sync: {
enabled: true, // enable trace line syncing with other charts
group: 1, // chart group
suppressTooltips: false // suppress tooltips when showing a synced tracer
},
zoom: {
enabled: true, // enable zooming
zoomboxBackgroundColor: 'rgba(66,133,244,0.2)', // background color of zoom box
zoomboxBorderColor: '#48F', // border color of zoom box
zoomButtonText: 'Reset Zoom', // reset zoom button text
zoomButtonClass: 'reset-zoom', // reset zoom button class
},
callbacks: {
beforeZoom: function(start, end) { // called before zoom, return false to prevent zoom
return true;
},
afterZoom: function(start, end) { // called after zoom
}
}
}
}
}
});
function getData() {
var dates = properties.time.get(0, properties.time.length())
var opens = properties.open.get(0, properties.open.length())
var highs = properties.high.get(0, properties.high.length())
var lows = properties.low.get(0, properties.low.length())
var closes = properties.close.get(0, properties.close.length())
let data = []
for (i = 0; i < dates.length; i++) {
data.push({
t: dates[i].valueOf(),
o: opens[i],
h: highs[i],
l: lows[i],
c: closes[i]
})
}
console.log(data)
return data
}
chart.update()

The crosair plugin is not yet compatible with the new beta of version 3. They have a pr to be up to date with beta 11 but after that there have been breaking changes again. So you will have to update the plugin yourself or wait till it has been updated to support v3

Related

Highcharts sparklines from ajax-inserted data

You have a html table and you want to show sparkline charts from your data, exactly as in this example (from highcharts demos):
https://codepen.io/_dario/pen/rNBOGVR
Highcharts suggested code follows:
/**
* Create a constructor for sparklines that takes some sensible defaults and merges in the individual
* chart options. This function is also available from the jQuery plugin as $(element).highcharts('SparkLine').
*/
Highcharts.SparkLine = function(a, b, c) {
var hasRenderToArg = typeof a === 'string' || a.nodeName,
options = arguments[hasRenderToArg ? 1 : 0],
defaultOptions = {
chart: {
renderTo: (options.chart && options.chart.renderTo) || this,
backgroundColor: null,
borderWidth: 0,
type: 'area',
margin: [2, 0, 2, 0],
width: 120,
height: 20,
style: {
overflow: 'visible'
},
// small optimalization, saves 1-2 ms each sparkline
skipClone: true
},
title: {
text: ''
},
credits: {
enabled: false
},
xAxis: {
labels: {
enabled: false
},
title: {
text: null
},
startOnTick: false,
endOnTick: false,
tickPositions: []
},
yAxis: {
endOnTick: false,
startOnTick: false,
labels: {
enabled: false
},
title: {
text: null
},
tickPositions: [0]
},
legend: {
enabled: false
},
tooltip: {
hideDelay: 0,
outside: true,
shared: true
},
plotOptions: {
series: {
animation: false,
lineWidth: 1,
shadow: false,
states: {
hover: {
lineWidth: 1
}
},
marker: {
radius: 1,
states: {
hover: {
radius: 2
}
}
},
fillOpacity: 0.25
},
column: {
negativeColor: '#910000',
borderColor: 'silver'
}
}
};
options = Highcharts.merge(defaultOptions, options);
return hasRenderToArg ?
new Highcharts.Chart(a, options, c) :
new Highcharts.Chart(options, b);
};
var start = +new Date(),
$tds = $('td[data-sparkline]'),
fullLen = $tds.length,
n = 0;
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
$td = $($tds[i]);
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
doChunk();
However, in my use case, the data in the table (and the data-sparkline attribute) are not hard-coded like in the example, but loaded and displayed via an AJAX call, similar to below.
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#wordstable tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
This breaks the example logic and I can't have Highcharts "see" the data.
No particular error is returned (as the data, as far as Highcharts is concerned, just isn't there, so there's nothing to do).
The doChunk bit just does all the processing in advance, and when you add your row it is no longer processing. One way of dealing with this is pulling out the part that creates a single chart into a separate function (makeChart) and when you are doing your processing you use that part directly to create your sparkline.
For example, doChunk with split out makeChart:
function makeChart(td) {
$td = td;
stringdata = $td.data('sparkline');
arr = stringdata.split('; ');
data = $.map(arr[0].split(', '), parseFloat);
chart = {};
if (arr[1]) {
chart.type = arr[1];
}
$td.highcharts('SparkLine', {
series: [{
data: data,
pointStart: 1
}],
tooltip: {
headerFormat: '<span style="font-size: 10px">' + $td.parent().find('th').html() + ', Q{point.x}:</span><br/>',
pointFormat: '<b>{point.y}.000</b> USD'
},
chart: chart
});
}
// Creating 153 sparkline charts is quite fast in modern browsers, but IE8 and mobile
// can take some seconds, so we split the input into chunks and apply them in timeouts
// in order avoid locking up the browser process and allow interaction.
function doChunk() {
var time = +new Date(),
i,
len = $tds.length,
$td,
stringdata,
arr,
data,
chart;
for (i = 0; i < len; i += 1) {
makeChart($($tds[i]));
n += 1;
// If the process takes too much time, run a timeout to allow interaction with the browser
if (new Date() - time > 500) {
$tds.splice(0, i + 1);
setTimeout(doChunk, 0);
break;
}
// Print a feedback on the performance
if (n === fullLen) {
$('#result').html('Generated ' + fullLen + ' sparklines in ' + (new Date() - start) + ' ms');
}
}
}
And then a basic example of your ajax-code:
function ajaxIsh() {
var word = {
name: 'Bird', // is the word
id: 'bird',
sparkline: '1, 2, 3, 4, 5'
};
//here a table row gets compiled
var tableRow = '<tr id="row_' + word.id + '">';
//this is where the sparkline data go
tableRow += '<th>'+word.name+'</th><td class="has-sparkline"></td></tr>';
//the row gets appended to tbody
$('#table-sparkline tbody').append(tableRow);
//finally the sparkline data are attached
//data are a simple string such as "1,2,3,4,5"
var rowId = '#row_'+word.id;
var rowIdTd = rowId + ' td.has-sparkline';
$(rowIdTd).data('sparkline',word.sparkline);
makeChart($(rowIdTd));
}
See this JSFiddle demonstration of it in action.

Highstock/Highchart substep maximum?

example
I want my maximum step count to cap at a dynamic integer. In this case it's 4. I went through the documentation but can't find anything that suits my needs. Does someone have an idea about this?
Ideally; I want the white space shown in red gone.
xAxis: {
min: 1.1,
ordinal: false,
max: 2,
labels: {
formatter: function () {
return 'Lap ' + this.value;
},
},
},
http://jsfiddle.net/d54uae3s/4/
You can use breaks from the broken-axis Highcharts module:
function createBreaks() {
var breaks = [];
for (var i = 1; i < 8; i++) {
breaks.push({
from: i + 0.4,
to: i + 1.1,
breakSize: 0.1
})
}
return breaks;
}
var chart = Highcharts.chart({
...,
xAxis: {
...
breaks: createBreaks()
}
});
Live demo: http://jsfiddle.net/BlackLabel/sjLdfegp/
API Reference: https://api.highcharts.com/highstock/xAxis.breaks

Highstock charts give "Uncaught TypeError: Cannot read property 'addPoint' of undefined" error

I am using the highstock charts library for a set of 4 charts. I used the options object and literal notation as described HERE. The 4 charts have the same set of options by default (the renderCharts() function in the code bellow is responsible for that) and there is a charts type picker (the setChatType() function ) with the help of which the user can change the chart type.
See all togheter HERE.
Can anyone please tell me the cause of and solution for this error in the console:
"Uncaught TypeError: Cannot read property 'addPoint' of undefined"?
Thank you!
/* ============ CHARTS OPTIONS BEGIN ============ */
var options = {
chart : {
zoomType: 'x',
events : {
load : function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime();
var y = Math.round(Math.random() * 100);
series.addPoint([x, y]);
}, 1000);
}
}
},
rangeSelector: {
buttons: [{
count: 1,
type: 'minute',
text: '1M'
}, {
count: 5,
type: 'minute',
text: '5M'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: false,
selected: 0
},
title : {
text: null
},
exporting: {
enabled: false
},
// Disable navigator
navigator : {
enabled : false
},
series : [{
name : '',
data : (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(), i;
for (i = -999; i <= 0; i = i + 1) {
data.push([
time + i * 1000,
Math.round(Math.random() * 100)
]);
}
return data;
}())
}]
}
/* ============ CHARTS OPTIONS END ============ */
/* ============ DRAW CHARTS BEGIN ============ */
function renderCharts(){
$('div.chart-container').each(function(){
var chartId = $(this).attr('id');
var chartIdParts = chartId.split('-');
var chartIdentifier = chartIdParts[1];
//Set chart options dinamically
var chartId = "chart" + chartIdentifier;
var chart = $('#' + chartId);
var renderTo = "chartcontainer-" + chartIdentifier;
//Render Charts for each aech container
options.chart.renderTo = renderTo;
options.chart.type = 'line';
var chart = new Highcharts.StockChart(options);
});
}
function setChatType(){
// Show types list (piker)
$('.current-type').on('click', function(){
$(this).parents('div.chart-options').find('ul.type ul').addClass('clicked');
});
$('.chart-options ul ul li a').on('click', function(){
//Get piked chart type
var type = $(this).parent('li').attr('data-chart-type');
// For text and Title Capitalization
var textAndTitle = type.replace(/^[a-z]/, function(m){ return m.toUpperCase() });
// Show piked type in picker
var currSetClass = 'current-type ' + type;
$(this).parents('.chart-options').find('.current-type')
.text(textAndTitle)
.attr({
class : currSetClass,
title: textAndTitle
});
// Then Hide the types list
$('.chart-options ul ul').removeClass('clicked');
//Identify current chart container by ID
var chartCtnId= $(this).parents('div.chart').find('.chart-container').attr('id');
// Render chart again with new type
options.chart.renderTo = chartCtnId;
options.chart.type = type;
var chart = new Highcharts.StockChart(options);
});
}
/* ============ DRAW CHARTS END ============ */
$(document).ready(function(){
$("article.grid:even").addClass('left')
$("article.grid:odd").addClass('right');
// Draw charts
renderCharts();
// Set/change chart type
setChatType();
});
The solution, suggested by Pawel:
instead of
var chart = new Highcharts.StockChart(options);
use
var chart = new Highcharts.StockChart( $.extend(true, {}, options) );

highlightSeries plugin for jquery flot charts

I'm looking for help with the highlightSeries plugin made by Brian Peiris (http://brian.peiris.name/highlightSeries/). It doesn't appear to be working; I'm positive that the event is firing, because an alert test I performed earlier worked just fine, printing out $(this).text(). I'm trying to get the series on the chart to be highlighted when the user mouses over the series name in the legend (something which works perfectly fine on Mr. Peiris's website).
$('.server-chart').each(function() {
var serv = $(this).attr('id').substr(6);
var plotData = [];
//alert(serv + ": " + $.toJSON(serverStats[serv]));
for (var k in serverStats[serv].StatsByCollection) {
var outlabel = k;
var outdata = serverStats[serv].StatsByCollection[k];
plotData.push({ label: outlabel, data: outdata});
}
plotOptions = {
legend: {
container: $('#legend-' + serv),
labelFormatter: function(label, series) {
return '' + label + '';
},
noColumns: 2
},
series: {
lines: {
show: true,
fill: false
},
points: {
show: false,
fill: false
}
},
colors: colors,
grid: {
hoverable: false
},
highlightSeries: {
color: "#FF00FF"
}
}
$_plot = $.plot(this, plotData, plotOptions);
$plots.push($_plot);
$('#legend-' + serv + ' .legendLabel, #legend-' + serv + ' .legendColorBox').on('mouseenter', function () {
$_plot.highlightSeries($(this).text());
});
$('#legend-' + serv + ' .legendLabel, #legend-' + serv + ' .legendColorBox').on('mouseleave', function () {
$_plot.unHighlightSeries($(this).text());
});
});
I'm not sure what other code to put on here, so tell me if you need more; the charts are all working fine, this is just the part of the ready function setting up all of the plots and their options inside the placeholders.
Also, there's a couple of classes attached to the labels that are extraneous; I was trying different things to get this stuff to work.
The plugin requires a patched version of flot to work (it introduces a public drawSeries method). The last patched version is for an older version of flot (0.7).
With that said, I wouldn't use this plugin. If you just want to highlight a series on legend mouseover it's pretty simple.
$('#legend .legendLabel, #legend .legendColorBox').on('mouseenter', function() {
var label = $(this).text();
var allSeries = $_plot.getData();
// find your series by label
for (var i = 0; i < allSeries.length; i++){
if (allSeries[i].label == label){
allSeries[i].oldColor = allSeries[i].color;
allSeries[i].color = 'black'; // highlight it in some color
break;
}
}
$_plot.draw(); // draw it
});
$('#legend .legendLabel, #legend .legendColorBox').on('mouseleave', function() {
var label = $(this).text();
var allSeries = $_plot.getData();
for (var i = 0; i < allSeries.length; i++){
if (allSeries[i].label == label){
allSeries[i].color = allSeries[i].oldColor;
break;
}
}
$_plot.draw();
});
See example here.

Flot Stacked Bar Chart and displaying bar values on mouse over

I'm trying to understand the tooltip functionality of Flot but not really getting my head around it!
I am trying to achieve a tooltip that displays the label and value of each section of a stacked bar chart
Would someone be able to point my towards an example of this or provide code for doing so?
The following code works for my Flot stacked bar chart, based on the Flot example that shows data point hover. The trick is that the 'item' values in the stacked chart are cumulative, so the 'y' value displayed in the tool tip has to first subtract the datapoint for the bars underneath.
var previousPoint = null;
$("#chart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint != item.datapoint) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, y + " " + item.series.label);
}
}
else {
$("#tooltip").remove();
previousPoint = null;
}
});
I did not find this in the Flot documentation, but the item.datapoint array seemed to contain what I needed in practice.
The code above caused redraw-issues for me.
Here is an improved code:
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
This is the same as Thomas above, except that I shifted the tooltip up to prevent it blocking the hover action.
var previousPoint = [0,0,0];
$("#regionsChart").bind("plothover", function (event, pos, item) {
if (item) {
if (previousPoint[0] != item.datapoint[0]
|| previousPoint[1] != item.datapoint[1]
|| previousPoint[2] != item.datapoint[2]
) {
previousPoint = item.datapoint;
$("#tooltip").remove();
var x = item.datapoint[0],
y = item.datapoint[1] - item.datapoint[2];
showTooltip(item.pageX, item.pageY - 35, item.series.label + " " + y.toFixed(0) );
}
}
else {
$("#tooltip").remove();
previousPoint = [0,0,0];
}
});
The solution is using tooltipOpts -> content method with a callback function to properly return dynamic data to the label.
I figured out that passing a 4th argument to the callback function of the "tooltipOpts" actually gives you the whole data object from which the chart/graph is constructed from.
From here, you can easily extract the X axis labels, using the second argument of this same function as the index of the label to extract.
EXAMPLE:
Data object I'm passing to the plot function:
[
{ data: [[1,137],[2,194],[3,376],[4,145],[5,145],[6,145],[7,146]] }
],
{
bars: { show: true, fill: true, barWidth: 0.3, lineWidth: 1, fillColor: { colors: [{ opacity: 0.8 }, { opacity: 1}] }, align: 'center' },
colors: ['#fcc100'],
series: { shadowSize: 3 },
xaxis: {
show: true,
font: { color: '#ccc' },
position: 'bottom',
ticks: [[1,'Thursday'],[2,'Friday'],[3,'Saturday'],[4,'Sunday'],[5,'Monday'],[6,'Tuesday'],[7,'Wednesday']]
},
yaxis:{ show: true, font: { color: '#ccc' }},
grid: { hoverable: true, clickable: true, borderWidth: 0, color: 'rgba(120,120,120,0.5)' },
tooltip: true,
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}
}
Bar chart rendered from the above data object:
As you can see on the image preview, the logic used to render the label's content dynamically form the actual data is this:
tooltipOpts: {
content: function(data, x, y, dataObject) {
var XdataIndex = dataObject.dataIndex;
var XdataLabel = dataObject.series.xaxis.ticks[XdataIndex].label;
return y + ' stories created about your page on ' + XdataLabel;
},
defaultTheme: false,
shifts: { x: 0, y: -40 }
}

Categories

Resources