Highstock dual x-axis with scrollbar - highcharts

I have a chart with the dual x-axis and grouped categories as labels and I need a working scrollbar. I have tried multiple ways of how to achieve that but I am not successful so far... This is the nearest I have gone, there are 10 "rows" from which I have displayed 5, there is a scrollbar, but I cannot move the scrollbar.
var count = 10;
var dataArray = [];
for (var i = 0; i < count; i++) {
dataArray[i] = [i + 1, i + 2, i + 3, i + 4, i + 5];
}
var categories1Array = [];
for (var i = 0; i < count; i++) {
categories1Array[i] = i + 1;
}
var categories2Array = [];
for (var i = 0; i < count; i++) {
categories2Array[i] = {
name: "3rd",
categories: [{
name: "2nd",
categories: ['1st']
}]
};
}
Highcharts.chart('container', {
chart: {
inverted: true
},
series: [{
type: 'boxplot',
data: dataArray,
showInLegend: false
}],
xAxis: [{
categories: categories1Array,
max: 4,
gridLineWidth: 1
},
{
opposite: true,
linkedTo: 0,
categories: categories2Array,
max: 9,
scrollbar: {
enabled: true
},
labels: {
formatter: function() {
return `<div style="width:30px">${this.value}</div>`;
},
useHTML: true
}
},
],
credits: {
enabled: false
},
title: {
text: null
},
yAxis: {
title: {
text: null
}
}
});
#container {
min-width: 310px;
max-width: 800px;
height: 300px;
margin: 0 auto
}
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://blacklabel.github.io/grouped_categories/grouped-categories.js"></script>
<div id="container"></div>
Any ideas?

You need to add a scrollbar to the first xAxis. See: https://jsfiddle.net/wchmiel/vrheuwqc/
xAxis: [{
categories: categories1Array,
max: 4,
gridLineWidth: 1,
scrollbar: {
enabled: true
}
}, {
opposite: true,
linkedTo: 0,
categories: categories2Array,
min: 0,
max: 9,
labels: {
formatter: function() {
return `<div style="width:30px">${this.value}</div>`;
},
useHTML: true
}
}]
To align scrollbar to the right side of the chart overwrite H.Scrollbar.prototype.position function and add there an additional offset:
(function(H) {
H.Scrollbar.prototype.position = function(x, y, width, height) {
var scroller = this,
options = scroller.options,
vertical = options.vertical,
xOffset = height,
yOffset = 0,
method = scroller.rendered ? 'animate' : 'attr',
customOffset = 133;
scroller.x = x;
scroller.y = y + this.trackBorderWidth;
scroller.width = width; // width with buttons
scroller.height = height;
scroller.xOffset = xOffset;
scroller.yOffset = yOffset;
// If Scrollbar is a vertical type, swap options:
if (vertical) {
scroller.width = scroller.yOffset = width = yOffset = scroller.size;
scroller.xOffset = xOffset = 0;
scroller.barWidth = height - width * 2; // width without buttons
scroller.x = x = x + scroller.options.margin;
} else {
scroller.height = scroller.xOffset = height = xOffset =
scroller.size;
scroller.barWidth = width - height * 2; // width without buttons
scroller.y = scroller.y + scroller.options.margin;
}
// Set general position for a group:
scroller.group[method]({
translateX: x + customOffset, // add additional offset here
translateY: scroller.y
});
// Resize background/track:
scroller.track[method]({
width: width,
height: height
});
// Move right/bottom button ot it's place:
scroller.scrollbarButtons[1][method]({
translateX: vertical ? 0 : width - xOffset,
translateY: vertical ? height - yOffset : 0
});
}
})(Highcharts);
Demo:
https://jsfiddle.net/wchmiel/9yf58pd6/

Related

How to show mouse pointer coordinates on mouse move in angular highchart?

I want to show tooltip on mouse hover of every coordinate in angular-highchart, it should show x and y axis value in tooltip or label.
how we can show the tooltip on every coordinate of high chart.
It can be add scatter series and enabled markers, to imitate showing tooltip when axiss are crossing. Additionally, I added wrapp and extend to get a possibility to chart coordinate inside tooltip.formatter callback function.
(function(H) {
H.Tooltip.prototype.getAnchor = function(points, mouseEvent) {
var ret,
chart = this.chart,
inverted = chart.inverted,
plotTop = chart.plotTop,
plotLeft = chart.plotLeft,
plotX = 0,
plotY = 0,
yAxis,
xAxis;
points = H.splat(points);
// Pie uses a special tooltipPos
ret = points[0].tooltipPos;
// When tooltip follows mouse, relate the position to the mouse
if (this.followPointer && mouseEvent) {
if (mouseEvent.chartX === undefined) {
mouseEvent = chart.pointer.normalize(mouseEvent);
}
ret = [
mouseEvent.chartX - chart.plotLeft,
mouseEvent.chartY - plotTop
];
}
// When shared, use the average position
if (!ret) {
H.each(points, function(point) {
yAxis = point.series.yAxis;
xAxis = point.series.xAxis;
plotX += point.plotX + (!inverted && xAxis ? xAxis.left - plotLeft : 0);
plotY += (point.plotLow ? (point.plotLow + point.plotHigh) / 2 : point.plotY) +
(!inverted && yAxis ? yAxis.top - plotTop : 0); // #1151
});
plotX /= points.length;
plotY /= points.length;
ret = [
inverted ? chart.plotWidth - plotY : plotX,
this.shared && !inverted && points.length > 1 && mouseEvent ?
mouseEvent.chartY - plotTop : // place shared tooltip next to the mouse (#424)
inverted ? chart.plotHeight - plotX : plotY
];
}
// Add your event to Tooltip instances
this.event = mouseEvent;
return H.map(ret, Math.round);
}
})(Highcharts)
Highcharts.chart('container', {
title: {
text: 'Logarithmic axis demo'
},
xAxis: {
tickInterval: 0.1,
gridLineWidth: 1,
type: 'logarithmic',
accessibility: {
rangeDescription: 'Range: 1 to 10'
}
},
yAxis: [{
type: 'logarithmic',
minorTickInterval: 0.1,
accessibility: {
rangeDescription: 'Range: 0.1 to 1000'
}
}],
tooltip: {
followTouchMove: true,
followPointer: true,
formatter: function(mouseEvent) {
let event = mouseEvent.event
return `chartX:${event.chartX} <br> chartY:${event.chartY}`;
}
},
series: [{
data: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512],
pointStart: 1
},
{
type: 'scatter',
data: [{
x: 1,
y: 10
}, {
x: 2,
y: 10
}, {
x: 5,
y: 10
}, {
x: 4,
y: 10
}, {
x: 8,
y: 10
}],
}
],
plotOptions: {
scatter: {
states: {
inactive: {
enabled: false
}
},
marker: {
enabled: false
},
enableMouseTracking: true,
showInLegend: false
},
}
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/accessibility.js"></script>
<div id="container"></div>
Demo: https://jsfiddle.net/BlackLabel/t05uqfvm/

How to set the background of clicked or selected label on y axis gantt chart Highcharts?

I want to highlight the selected Y-axis label in Gantt charts. Also is there any way through which we can give some background color to the y-axis title?
yAxis: {
className: "highcharts-color-0",
uniqueNames: true,
title: {
text: "Data"
},
labels: {
events: {
click: function () {
alert("hellowww");
var chart = this,
series = chart.series,
plotLeft = chart.plotLeft,
plotTop = chart.plotTop,
plotWidth = chart.plotWidth;
if (chart.myBackground) {
chart.myBackground.destroy();
}
chart.myBackground = chart.renderer
.rect(10, plotTop, 500, 30, 1)
.attr({
"stroke-width": 2,
stroke: "red",
fill: "yellow",
opacity: 0.5,
zIndex: -1
})
.add();
}
}
}
}
enter image description here
link to code pen https://codepen.io/mehrotrarohit07/pen/PoKxvQp?editors=1010
Try to use this approach:
yAxis: {
labels: {
events: {
click: function() {
const chart = this.chart;
const axis = this.axis;
const labelPos = this.pos;
const tick = axis.ticks[labelPos]
const x = chart.marginRight;
const width = tick.slotWidth;
const height = axis.height / (axis.tickPositions.length);
const y = axis.top + labelPos * height;
chart.renderer
.rect(x, y, tick.slotWidth, height)
.attr({
fill: 'yellow',
zIndex: 0
})
.add();
}
}
}
},
I hope that everything is clear from the code - in case of any doubts feel free to ask.
Demo: https://jsfiddle.net/BlackLabel/qyj327Lx/
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#rect

How to put shadow inside of bar chart in highcharts?

How to put shadow inside of bar chart like box-shadow inset(css) in hightcharts as image below.
Thank you. Have a good day~
enter image description here
You can use two overlap series, one with default shadow property and translate both of them by a few pixels in load event:
Highcharts.chart('container', {
chart: {
...,
events: {
load: function() {
this.series[0].points[0].graphic.attr({
translateX: -2
});
this.series[1].points[0].graphic.attr({
translateX: -2
});
}
}
},
...,
series: [{
...,
data: [100],
shadow: {
color: 'gray',
opacity: 0.8,
width: 2
}
}, {
data: [50]
}]
});
Live demo: http://jsfiddle.net/BlackLabel/b7hp0r6s/
API Reference: https://api.highcharts.com/highcharts/series.bar.shadow
Unfortunately, Highcharts doesn't have an inset shadow implemented in the core. However, it can be done by adding custom logic to Highcharts.SVGElement.prototype.shadow method. Check the code and demo posted below and let me know if something is unclear for you.
Additionally, to add a partial fill to columns with the inner shadow you have to make a custom column elements and insert them to the DOM between shadows and particular points.
Code:
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
(function(H) {
H.SVGElement.prototype.shadow = function(shadowOptions, group, cutOff) {
var shadows = [],
i, shadow, element = this.element,
strokeWidth, shadowWidth, shadowElementOpacity,
// compensate for inverted plot area
transform,
elemBBox = element.getBBox(),
translateX,
translateY;
if (!shadowOptions) {
this.destroyShadows();
} else if (!this.shadows) {
shadowWidth = H.pick(shadowOptions.width, 3);
shadowElementOpacity = (shadowOptions.opacity || 0.15) /
shadowWidth;
transform = this.parentInverted ?
'(' + H.pick(shadowOptions.offsetY, 1) * -1 + ', ' +
H.pick(shadowOptions.offsetX, 1) * -1 + ')' :
'(' + H.pick(shadowOptions.offsetX, 1) + ', ' +
H.pick(shadowOptions.offsetY, 1) + ')';
if (!shadowOptions.inside) {
for (i = 1; i <= shadowWidth; i++) {
shadow = element.cloneNode(0);
strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * i,
'stroke-width': strokeWidth,
transform: 'translate' + transform,
fill: 'none'
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
element.parentNode.insertBefore(shadow, element);
}
shadows.push(shadow);
}
} else {
for (i = shadowWidth; i >= 1; i--) {
shadow = element.cloneNode(0);
translateX = i / 2 - shadowOptions.offsetY;
translateY = i / 2 - shadowOptions.offsetX;
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * (shadowWidth - i + 1),
'stroke-width': i,
transform: 'translate(' + translateX + ',' + translateY + ')',
fill: 'none'
});
H.css(shadow, {
width: elemBBox.width - i,
height: elemBBox.height - i,
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
insertAfter(shadow, element);
}
shadows.push(shadow);
}
}
this.shadows = shadows;
}
return this;
};
})(Highcharts)
Highcharts.chart('container', {
chart: {
type: 'column',
inverted: true,
events: {
render: function() {
var chart = this,
yAxis = chart.yAxis[0],
partialFillWidth,
elem,
bBox;
if (chart.customElements && chart.customElements.length) {
chart.customElements.forEach(custElem => {
custElem.parentNode.removeChild(custElem);
})
chart.customElements.length = 0;
} else {
chart.customElements = [];
}
chart.series[0].points.forEach(point => {
bBox = point.graphic.getBBox();
elem = point.graphic.element.cloneNode(0);
partialFillWidth = yAxis.toPixels(point.partialFill);
Highcharts.attr(elem, {
fill: point.partialFillColor,
transform: 'translate(0, ' + (bBox.height - (point.partialFill / point.y) * bBox.height) + ')'
});
Highcharts.css(elem, {
height: (point.partialFill / point.y) * bBox.height
});
insertAfter(elem, point.graphic.element);
chart.customElements.push(elem);
});
}
}
},
title: {
text: 'Efficiency Optimization by Branch'
},
xAxis: {
categories: [
'Seattle HQ',
'San Francisco',
'Tokyo'
]
},
yAxis: [{
min: 0,
title: {
text: 'Employees'
}
}, {
title: {
text: 'Profit (millions)'
},
opposite: true
}],
legend: {
shadow: false
},
tooltip: {
shared: true
},
plotOptions: {
column: {
grouping: false,
shadow: false,
borderWidth: 0,
pointPadding: 0,
groupPadding: 0
}
},
series: [{
color: '#efefef',
id: 'main',
data: [{
y: 120,
partialFill: 100,
partialFillColor: '#bbb'
}, {
y: 50,
partialFill: 10,
partialFillColor: '#bbb'
}, {
y: 70,
partialFill: 20,
partialFillColor: '#bbb'
}],
pointPadding: 0.4,
shadow: {
color: 'rgba(0, 0, 0, 0.5)',
opacity: 0.3,
width: 5,
offsetX: 0,
offsetY: 0,
inside: true
}
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
Demo:
https://jsfiddle.net/BlackLabel/kvrjd48w/
API reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement
https://api.highcharts.com/class-reference/Highcharts#.attr

JSFiddle becomes unresponsive after continuous zooming in the chart

When we continuously zoom in the chart around after 8 or 10 times, the JSFiddle becomes unresponsive.
JSFiddle
HTML
<script src="https://code.highcharts.com/stock/highstock.js"></script>
<div id="container"></div>
CSS
#container {
max-width: 800px;
height: 400px;
margin: 1em auto;
}
JavaScript + jQuery 1.7.2
$(function () {
/**
* Experimental Highcharts plugin to implement chart.alignThreshold option. This primary axis
* will be computed first, then all following axes will be aligned to the threshold.
* Author: Torstein Hønsi
* Last revision: 2015-05-18
*/
(function (H) {
var Axis = H.Axis,
inArray = H.inArray,
wrap = H.wrap;
wrap(Axis.prototype, 'adjustTickAmount', function (proceed) {
var chart = this.chart,
primaryAxis,
primaryThreshold,
primaryIndex,
index,
newTickPosLow,
threshold,
newTickPositionsHigh,
max,
nextStep;
// Find the index and return boolean result
function isAligned(axis) {
index = inArray(threshold, axis.tickPositions); // used in while-loop
return axis.tickPositions.length === axis.tickAmount && index === primaryIndex;
}
for(var i = chart[this.coll].length - 1; i >= 0; i--){
chart[this.coll][i].removePlotLine('zero-point-plotline');
if(chart[this.coll][i].hasVisibleSeries){
primaryAxis = chart[this.coll][i];
}
}
primaryThreshold = (primaryAxis.series[0] && primaryAxis.series[0].options.threshold) || 0;
threshold = 0;
for(var i = 0; i < this.series.length; i++){
if(this.series[i].visible){
threshold = this.series[i].options.threshold;
break;
}
}
primaryIndex = primaryAxis.tickPositions && inArray(primaryThreshold, primaryAxis.tickPositions);
if(primaryIndex > 0 && primaryIndex < primaryAxis.tickPositions.length - 1){
primaryAxis.addPlotLine({
color: 'black',
value: 0,
width: 0,
id: 'zero-point-plotline',
zIndex: 3
})
}
if (chart.options.chart.alignThresholds && primaryAxis && this !== primaryAxis && this.hasVisibleSeries) {
if (this.tickPositions && primaryIndex >= 0 && primaryIndex <= primaryAxis.tickPositions.length - 1) {
if (this.tickAmount) {
while (!isAligned(this)) {
if (index < primaryIndex) {
// fill up the tick positions, so that we can calculate the new interval-steps
while (this.tickPositions.length < primaryAxis.tickPositions.length) {
var nextStep = Math.abs(Math.abs(this.tickPositions[this.tickPositions.length - 1]) - Math.abs(this.tickPositions[this.tickPositions.length - 2]));
this.tickPositions.push(this.tickPositions[this.tickPositions.length - 1] + nextStep);
}
newTickPositionsHigh = [];
for(var i = 0; i < primaryAxis.tickPositions.length; i++){
max = this.tickPositions[this.tickPositions.length - 1];
nextStep = max / (primaryAxis.tickPositions.length - 1 - primaryIndex);
newTickPositionsHigh.push(max - i * nextStep);
}
this.tickPositions = newTickPositionsHigh.reverse();
this.max = this.tickPositions[this.tickPositions.length - 1];
this.min = this.tickPositions[0];
} else {
newTickPosLow = this.tickPositions[this.tickPositions.length - 1] + this.tickInterval;
this.tickPositions.push(newTickPosLow);
this.max = newTickPosLow;
}
proceed.call(this);
}
}
}
} else {
proceed.call(this);
}
});
}(Highcharts));
$('#container').highcharts({
chart: {
alignThresholds: true,
type: 'area',
zoomType:'xy'
},
title: {
text: 'The <em>alignThreshold</em> option is true'
},
xAxis: {
categories: ['Flags(1)','Flags(2)','Flags(3)','Shopping (4)','Shopping(5)','Shopping(6)','Shopping(7)','Town(8)','Town(9)','Town(10)','Town(11)','Town(12)','Town(14)','Town(15)','Town(16)','Town(17)','Small(18)','Small(19)','Small(20)','Town(13)'],
scrollbar:
{
enabled:true
}
},
yAxis: [{
title: {
text: 'Traffic',
},
}, {
title: {
text: 'Conversion Rate'
},
opposite: true
},
{
title: {
text: 'ATV'
},
opposite: true
},
{
title: {
text: 'TotalTransaction'
},
opposite: true
},
{
title: {
text: 'Sta'
},
opposite: true
}],
series: [{
data: [8.16,7.6,2.86,2.02,-1.98,-2.83,4.53,-63.35,0],
type: 'spline',
yAxis: 0
}, {
data: [0.9,0.4,-0.4,-2.2,-0.3,0.0,-0.5,1.1,-0.4,3.4,0.8,1.4,2.4,-1.2,3.2,1.7,-0.5,-0.3,2.3,2.8],
type: 'column',
yAxis: 1,
visible: false
}, {
data: [-6.44,6.56,-9.94,35.70,58.07,0.00,103.36,91.03,-84.11,-41.35,25.15,-6.32,4.66,2.93,59.47,-6.39,22.44,17.30,46.46,-14.18],
type: 'column',
yAxis: 2,
visible: false
}]
});
});

Keep Scroll on the Right Highchart

Is there a way to keep the scroll on the most right?
I am trying live update on highchart and it seems that sometimes I am encountering scroll being left behind.
$(function() {
Highcharts.setOptions({
global: {
useUTC: false
}
});
// Create the chart
$('#container').highcharts('StockChart', {
chart: {
events: {
load: function() {
// set up the updating of the chart each second
var series = this.series[0],
hasPlotLine = false,
$button = $('#button'),
chart = $('#container').highcharts(),
yAxis = chart.yAxis[0],
plotLine,
d,
newY;
yAxis.addPlotLine({
value: 66,
color: 'red',
width: 2,
id: 'plot-line-1',
label: {
text: 66,
align: 'right',
y: newY,
x: 0
}
});
setInterval(function() {
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100);
series.addPoint([x, y], true, true);
plotLine = yAxis.plotLinesAndBands[0].svgElem;
d = plotLine.d.split(' ');
newY = yAxis.toPixels(y) - d[2];
plotlabel = yAxis.plotLinesAndBands[0].label;
plotlabel.animate({
translateY:newY,
text:y
},400),
plotLine.animate({
translateY: newY
}, 400);
}, 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: 'Live random data'
},
exporting: {
enabled: false
},
series: [{
name: 'Random data',
data: (function() {
// generate an array of random data
var data = [],
time = (new Date()).getTime(),
i;
for (i = -999; i <= 0; i += 1) {
data.push([
time + i * 1000,
Math.round(Math.random() * 100)
]);
}
return data;
}())
}]
});
});
I know it a little bit hard to explain my concern, but check this image
I have search setExtremes but I am not sure if how it works or how it will be set up on future dated in case this is the function that I am looking for.
Here is the jsfiddle http://jsfiddle.net/kttfv1h3/3/
Appreciate your help
setExtremes() will work - see API http://api.highcharts.com/highcharts/Axis.setExtremes.
The only thing you need to adjust is the min value - you can calculate it from the last point or set some fixed value.
xAxis.setExtremes(x - 1000 * 60, x)
example: http://jsfiddle.net/nmx5hruo/

Resources