custom ticks based on selected range from rangeSelector in Highstock - reactjs

I am trying to get my Highcharts/Highstock chart to display a custom tick when the rangeSelector is set to All, I have it setup this way, but is throwing me errors when I try to use the interactive portion of the graph
Received below answer from Highstock Change tick interval on range selector change
componentDidMount() {
// Timezone Offset for PST standard is UTC timezone
Highcharts.setOptions({
global: {
timezoneOffset: 8 * 60
},
lang: {
thousandsSep: ','
}
});
Highcharts.stockChart('chart', {
chart: {
backgroundColor:'rgba(255, 255, 255, 0.0)',
height: 400,
zoomType: 'xy'
},
title: {
text: 'Bitcoin Chart',
style: {
color: 'white'
}
},
navigator: {
trigger: "navigator",
triggerOp: "navigator-drag",
rangeSelectorButton: undefined,
handles: {
backgroundColor: 'white',
borderColor: 'black'
}
},
scrollbar: {
enabled: false
},
rangeSelector: {
buttons: [{
type: 'day',
count: 1,
text: '1d'
}, {
type: 'day',
count: 7,
text: '7d'
}, {
type: 'month',
count: 1,
text: '1m'
}, {
type: 'month',
count: 3,
text: '3m'
}, {
type: 'year',
count: 1,
text: '1y'
}, {
type: 'all',
text: 'All'
}],
selected: 6,
// styles for the buttons
buttonTheme: {
fill: 'black',
// stroke: 'none',
'stroke-width': 0,
r: 8,
style: {
color: 'white',
fontWeight: 'bold'
},
states: {
hover: {
},
select: {
fill: 'white',
style: {
color: 'black'
}
}
}
},
// Date Selector box
inputBoxBorderColor: 'black',
inputBoxWidth: 120,
inputBoxHeight: 18,
inputStyle: {
color: 'black',
fontWeight: 'bold'
},
labelStyle: {
color: 'silver',
fontWeight: 'bold'
},
},
series: [{
name: 'Bitcoin Price',
color: 'black',
data: this.props.data.all_price_values,
type: 'area',
threshold: null,
tooltip: {
valuePrefix: '$',
valueSuffix: ' USD',
valueDecimals: 2
}
}],
plotOptions: {
series: {
fillColor: {
linearGradient: [0, 0, 0, 0],
stops: [
[0, '#FF9900'],
[1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
]
}
}
},
xAxis: {
events: {
setExtremes: function(e) {
if (e.trigger === "rangeSelectorButton" && e.rangeSelectorButton.text === "All") {
var range = e.max - e.min;
// ticks spaced by one day or one hour
var ticksSpacing = range >= 86400 * 1000 ? 86400 : 3600;
this.update({
tickPositioner: function() {
var positions = [],
info = this.tickPositions.info;
for (var x = this.dataMin; x <= this.dataMax; x += ticksSpacing * 1000) { // Seconds * 1000 for ticks
positions.push(x);
};
positions.info = info;
return positions;
}
}, false);
}
}
},
title: {
enabled: true,
text: 'Date (Timezone: PST)',
style: {
color: 'white'
}
},
labels: {
style: {
color: 'white'
}
},
type: 'datetime',
dateTimeLabelFormats: {
day: '%b %e, %Y'
},
tickInterval: 1
},
yAxis: {
floor: 0,
labels: {
formatter: function () {
return '$' + this.axis.defaultLabelFormatter.call(this);
},
format: '{value:,.0f}',
align: 'left',
style: {
color: 'white'
},
},
},
// Mobile Design
responsive: {
rules: [{
condition: {
maxWidth: 600
},
chartOptions: {
chart: {
height: 400
},
subtitle: {
text: null
},
navigator: {
enabled: false
}
}
}]
}
});
}
I am talking about the blue highlighted section, when I move it, it throws an error
I am trying to get the charts to have 2 plots per day on ALL rangeSelector, displaying the first point in the day and the last point in a day. What am I doing wrong?
EDIT 1 : Updated to full config, X Axis is now being disrupted by the original answer, ticks on custom range selector is still in works. Added images to show what's going on

The setExtremes event is raised each time you change the range to be displayed on the graph. It can have several origins:
A button click in the range selector
An handle drag in the navigator
etc..
The actual properties of the event depend on its origin. If you output the event with console.log(e), you'll see that it's not the same for these two origins:
Button click in the range selector
{
trigger: "rangeSelectorButton",
rangeSelectorButton: {
text: "2Hour",
type: "hour",
count: 2,
},
...
}
Handle drag in the navigator
{
trigger: "navigator",
triggerOp: "navigator-drag",
rangeSelectorButton: undefined
}
If you drag the handle in the navigator, there's no rangeSelectorButton attached to the event, because it doesn't make sense: in that case, no button is pressed.
To fix your error, you can add a check on the trigger property:
xAxis: {
events: {
setExtremes: function(e) {
if (e.trigger === "rangeSelectorButton" && e.rangeSelectorButton.text === "All") {
...
}
}
}
How to solved the actual issue
Now, the REAL issue. You want to change the ticks based on what is displayed: either the beginning and end of each day, or hours if not a complete day. You can do that with e.min and e.max, that represent the selected time range.
Like so:
setExtremes: function(e) {
var range = e.max - e.min;
// ticks spaced by one day or one hour
var ticksSpacing = range >= 86400 * 1000 ? 86400 : 3600;
this.update({
tickPositioner: function() {
var positions = [],
info = this.tickPositions.info;
for (var x = this.dataMin; x <= this.dataMax; x += ticksSpacing * 1000) { // Seconds * 1000 for ticks
positions.push(x);
};
positions.info = info;
return positions;
}
}, false);
}

Related

Why does my chart plot extra x-axis width?

I am using antd Charts in my project to plot timeseries data. My data has datapoints only till 18:30 pm but antd Line Chart plots extra x-axis width which makes it look like the data is missing.
This is my config:
const config = {
width: window.innerWidth - 100,
data: res,
xField: 'time',
yField: 'value',
seriesField: 'key',
yAxis: {
title: { position: 'center', text: labelText, autoRotate: true },
grid: {
line: {
style: {
stroke: '#ddd',
},
},
},
},
xAxis: {
type: 'time',
mask: 'HH:mm Z',
label: {
formatter: (value) => {
if (timezone === 'utc') {
return moment(value, 'HH:mm ZZ').utc().format('HH:mm Z');
}
return moment(value, 'HH:mm').format('HH:mm Z');
},
},
grid: {
line: {
style: {
stroke: '#ddd',
},
},
},
},
tooltip: {
customItems: (originalItems) => {
return originalItems.sort(function (a, b) {
return b.value - a.value;
});
},
},
};
How do I remove the extra x-axis part between 18:30 and 18:47

How to get specific bar or line color applied to its data series in subscribeCrosshairMove event

i want to create a tooltip with specific color for example todays date have red color then tooltip text going to be red and next line or bar is green then tooltip color will change to green
i am able to get the current price of each series and its static option but as you see in the data first two data set have color green and rest have default color red from options.enter image description here
below is my basic code for creating line chart for example
const chart = LightweightCharts.createChart(document.getElementById("chartContainer2"), {
width: jQuery('#chartContainer2').width(),
height: jQuery('#chartContainer2').height(),
layout: {
background: {
type: LightweightCharts.ColorType.Solid,
color: '#212529'
},
textColor: '#FFFFFF'
},
crosshair: {
mode: 0
},
grid: {
vertLines: {
visible: false
},
horzLines: {
visible: false
}
}
});
seriesList = [];
seriesList['SMA-10'] = chart.addLineSeries({
customTitle: 'SMA-10',
lastValueVisible: false,
priceLineVisible: false,
color: 'red',
lineStyle: 0,
lineWidth: 1, //in px
crosshairMarkerVisible: false
});
seriesList['SMA-10'].setData([{
time: '2019-04-11',
value: 80.01,
color: 'green'
},
{
time: '2019-04-12',
value: 96.63,
color: 'green'
},
{
time: '2019-04-13',
value: 76.64
},
{
time: '2019-04-14',
value: 81.89
},
{
time: '2019-04-15',
value: 74.43
},
{
time: '2019-04-16',
value: 80.01
},
{
time: '2019-04-17',
value: 96.63
},
{
time: '2019-04-18',
value: 76.64
},
{
time: '2019-04-19',
value: 81.89
},
{
time: '2019-04-20',
value: 74.43
},
]);
chart.subscribeCrosshairMove((param) => {
if (param.time) {
for (var key in seriesList) {
console.log(seriesList[key].options(), param.seriesPrices.get(seriesList[key]));
}
}
});

Highchart: Break y-axis doest work in react app but is working in js fiddle

using same options in js-fiddle and react app y-axis break is not working in react app but is working fine in js-fiddle.
highchart version i am using is 7.2.1
[enter link description here][1] jsfiddle where break is working
Highcharts.chart('container', {
chart: {
height: 250,
animation: false,
borderColor: '#EFF3F5',
plotBorderColor: '#EFF3F5',
plotBorderWidth: 1,
style: {
},
marginLeft: undefined,
},
legend: {
enabled: false,
},
credits: {
enabled: false,
},
title: {
text: '',
},
subtitle: {
text: '',
},
xAxis: [{
categories: [],
type: 'datetime',
crosshair: {
color: '#96abb6',
width: 1,
snap: false,
},
labels: {
style: {
fontSize: '10px',
color: '#334252',
fontFamily: 'DecimaMono',
textTransform: 'uppercase',
lineHeight: '12px',
whiteSpace: 'nowrap',
},
formatter: function() {
return this.value;
},
},
alternateGridColor: '#F7F9FA',
}, ],
yAxis: [{
tickPositioner: function() {
const positions = [];
let tick = Math.floor(this.dataMin);
const max = Math.min(200, this.dataMax);
const increment = Math.ceil((max - this.dataMin) / 6);
if (this.dataMax !== null && this.dataMin !== null) {
for (tick; tick - increment <= max; tick += increment) {
positions.push(tick);
}
}
if (this.dataMax > 200) {
positions.push(this.dataMax);
}
return positions;
},
title: {
text: null,
},
labels: {
style: {
fontSize: '10px',
textAlign: 'right',
},
},
breaks: [{
from: 200,
to: 1700,
}],
}, ],
series: [{
name: 'Attraction 1',
data: [-0.3543, 5.4184, -31.3792, 95.2435, 135.5852, 104.7914, 84.5844, 8.5129, -38.4724, -54.1816, -13.1134, 677.986, 1763, 1420.0503, 760.9013, 100.8341, 10.4576, 89.8975, 97.4758, 55.4993, 51.4611, 24.1278, 9.9771, 26.9394, 22.042, 32.9894, 145.3526, 88.1315, 135.0617, 119.6472, 29.8568, 43.94, 26.4247, 43.4719, 128.6346, 119.7356, 33.2159, 58.6534, -7.6348, 2.1865, 31.7992],
color: '#e63c45',
lineWidth: 3,
}, ]
});
[enter image description here][2]
[2]: https://i.stack.imgur.com/TIKkO.png screenshot from react app
I reproduce your code in the React environment and everything looks fine, same as in the jsFiddle.
Demo: https://codesandbox.io/s/highcharts-react-demo-83jnr?file=/demo.jsx

Highcharts Showing negative values on tooltip

I have set min:0, in y-axis. But in tooltip i want to show negative values also and also it should start with value y=0 only.
if i will remove min:0 in y axis it will show negative values with tooltip in chart. But i only want to see negative values on tooltip not on chart.
but it is not allowing me to show negative values.
below is sample code.
$(id).highcharts({
chart: {
zoomType: 'xy',
marginLeft: 45,
marginRight: rightval - 10
},
title: { text: title },
exporting: { enabled: false },
credits: { enabled: false },
legend: { enabled: false, align: 'left', x: 10, verticalAlign: 'bottom', y: 3, shadow: false },
xAxis: {
min: minimum,
max: maximum,
scrollbar: {
enabled: scroobarVal
},
fontWeight: 'bold',
categories: Data['categories'],
labels: {
y: 20,
rotation: 0,
style: {
color: 'gray',
//fontSize:'1px !important;'
}
}
},
yAxis: [{
min: 0,
allowDecimals: false,
endOnTick: false,
gridLineWidth: 0,
labels: {
formatter: function () {
if (optionSelected == 'Day') {
return this.value;
} else {
return this.value / 1000000 + 'M';
}
},
style: {
color: '#767676'
}
},
offset: -10,
title: {
text: 'Inv ' + val_qty,
"textAlign": 'top',
"rotation": 0,
x: 60,
y: yaxisVal,
style: {
color: '#767676',
fontWeight: 'bold'
}
}
}, {
allowDecimals: false,
min: 0,
endOnTick: false,
gridLineWidth: 0,
title: {
text: y2axisname,
"textAlign": 'top',
"rotation": 0,
x: -75,
y: yaxisVal,
style: {
color: '#767676',
fontWeight: 'bold'
}
},
offset: -10,
labels: {
format: '{value}',
style: {
color: '#767676'
}
},
opposite: true
}],
labels: {
items: [{
html: ' ',
style: {
color: (Highcharts.theme && Highcharts.theme.textColor) || 'black'
}
}]
},
tooltip: {
style: { fontSize: '7pt' },
formatter: function () {
var s = '<b>' + this.x + '</b>';
$.each(this.points, function (i, point) {
s += '<br/><span style="color:' + point.series.color + '">\u25CF</span> ' + point.series.name + ': <b>' + CurrencySymbol + '</b>' + point.y.toString().replace(/,/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ", ");
});
return s;
},
shared: true
},
series: Data['series'],
});
I don't think there is a simple way to do this on Highchart.
One hacky way I found (don't judge me!) is to have a "ghost" series and set the tooltip.shared option to true.
Check it here: http://jsfiddle.net/arryx9rf/

Integrating Highcharts Sparkline with Angular JS UI Grid

I am trying to integrate highcharts sparkline with angular ui-grid directive but unable to plot the sparkline. When we try to dynamically plot the sparklines using ui-grid nothing gets plotted. I have made necessary changes to the sparkline code as well yet unable to find what is the issue. We need age column to have highcharts sparkline. Any pointer will be of great help.
$scope.gridOptions = {
enableFiltering: false,
enableSorting: true,
}
$scope.gridOptions.columnDefs = [{
name: 'id'
}, {
name: 'name'
}, {
name: 'age',
cellTemplate: '<div id="table-sparkline" data-sparkline="71, 78, 39, 66"></div>'
}, {
name: 'address.city'
}];
$http.get('https://cdn.rawgit.com/angular-ui/ui-grid.info/gh-pages/data/500_complex.json')
.success(function(data) {
$scope.gridOptions.data = data;
console.log(JSON.stringify(data));
/**
* 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: {
backgroundColor: null,
borderWidth: 0,
shadow: false,
useHTML: true,
hideDelay: 0,
shared: true,
padding: 0,
positioner: function(w, h, point) {
return {
x: point.plotX - w / 2,
y: point.plotY - h
};
}
},
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 = $('div[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('div').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;
}
}
}
doChunk();
Plunker

Resources