I have just started exploring highcharts API. I am trying to create a highstock chart where I can select some points from the chart and edit/delete the values. However, even though I have got the selected points, I could not see them marked on the chart. The following code is working fine for highcharts, but not for highstock:
var option = {
chart: {
renderTo: 'container',
defaultSeriesType: 'line',
width: 800,
height:500,
events: {
selection: function(event) {
for (var i = 0; i < this.series[0].data.length; i++) {
var point = this.series[0].data[i];
console.log("Point:",point.y,point.x);
if (point.x >= event.xAxis[0].min &&
point.x <= event.xAxis[0].max &&
point.y >= event.yAxis[0].min &&
point.y <= event.yAxis[0].max) {
console.log("selecting");
this.series[0].data[i].select(true,true);
}
}
return false;
}
},
zoomType: 'xy'
},
title: {
text: "Test",
margin: 100,
backgroundColor: '#FCFFC5'
},
rangeSelector: {
inputBoxStyle: {
right: '-280px'
},
//selected: 0
},
xAxis: {
type: 'datetime',
tickInterval: 14 * 24 * 3600 * 1000, // one week
tickWidth: 0,
gridLineWidth: 1,
labels: {
align: 'left',
x: 3,
y: -3
}
},
yAxis: [{
title: {
text: yAxisTitle
},
labels: {
align: 'left',
x: 3,
y: 16,
formatter: function() {
return Highcharts.numberFormat(this.value, 0);
}
},
showFirstLabel: false
}, {
linkedTo: 0,
gridLineWidth: 0,
opposite: true,
title: {
text: "Target Steps"
},
labels: {
align: 'right',
x: 0,
y: 16,
formatter: function() {
return Highcharts.numberFormat(this.value, 0);
}
},
showFirstLabel: false
}],
legend: {
align: 'left',
verticalAlign: 'top',
y: 20,
floating: true,
borderWidth: 0
},
tooltip: {
shared: true,
crosshairs: true
},
plotOptions: {
series: {
allowPointSelect: true,
cursor: 'pointer',
marker: {
enabled: true,
},
point: {
events: {
click: function() {
(this).select(true,true);
hs.htmlExpand(null, {
pageOrigin: {
x: this.pageX,
y: this.pageY
},
headingText: ''+Highcharts.dateFormat('%e. %b %Y', this.x) +':<br/>',
maincontentText:"Test",
width: 400,
height:220
});
}
}
},
marker: {
lineWidth: 1
}
}
},
series: [{
name: seriesName[0],
lineWidth: 4,
marker: {
radius: 4
}
},{
name: seriesName[1]
}],
};
var series = {
data: []
};
options.series[0].data = myArray[0];
options.series[1].data = myArray[1];
window.historic_chart = new Highcharts.StockChart(options);
I would really appreciate if anyone helps me find out a solution to this problem and explains why the selected points are not marked on the highstock charts.
Thanks.
Most probably you are using sometimes dataGrouping, so you have empty series.data array. In that case use series groupedData to list points, see: http://jsfiddle.net/awGwn/2/
events: {
selection: function (event) {
console.log(this);
var points = this.series[0].data;
if(points.length == 0 ) {
points = this.series[0].groupedData;
}
for (var i in points) {
var point = points[i];
console.log("Point:", point.y, point.x);
if (point.x >= event.xAxis[0].min && point.x <= event.xAxis[0].max && point.y >= event.yAxis[0].min && point.y <= event.yAxis[0].max) {
console.log("selecting");
point.select(true, true);
}
}
return false;
}
},
zoomType: 'xy'
If this won't help, recrate issue by upgrading my jsFiddle, please.
Related
Here is a sample fiddle (1) that shows the series name along the line body
(Sessions, Users). How do I make similar label for a highstock chart?
(The label seems to be appearing due to the data module that does the csv processing)
(1) https://jsfiddle.net/4restw8a/9/
Highcharts.chart('container', {
chart: {
scrollablePlotArea: {
minWidth: 700
}
},
data: {
csvURL: 'https://cdn.rawgit.com/highcharts/highcharts/' +
'057b672172ccc6c08fe7dbb27fc17ebca3f5b770/samples/data/analytics.csv',
beforeParse: function (csv) {
return csv.replace(/\n\n/g, '\n');
}
},
title: {
text: 'Daily sessions at www.highcharts.com'
},
subtitle: {
text: 'Source: Google Analytics'
},
xAxis: {
tickInterval: 7 * 24 * 3600 * 1000, // one week
tickWidth: 0,
gridLineWidth: 1,
labels: {
align: 'left',
x: 3,
y: -3
}
},
yAxis: [{ // left y axis
title: {
text: null
},
labels: {
align: 'left',
x: 3,
y: 16,
format: '{value:.,0f}'
},
showFirstLabel: false
}, { // right y axis
linkedTo: 0,
gridLineWidth: 0,
opposite: true,
title: {
text: null
},
labels: {
align: 'right',
x: -3,
y: 16,
format: '{value:.,0f}'
},
showFirstLabel: false
}],
legend: {
align: 'left',
verticalAlign: 'top',
borderWidth: 0
},
tooltip: {
shared: true,
crosshairs: true
},
plotOptions: {
series: {
cursor: 'pointer',
point: {
events: {
click: function (e) {
hs.htmlExpand(null, {
pageOrigin: {
x: e.pageX || e.clientX,
y: e.pageY || e.clientY
},
headingText: this.series.name,
maincontentText: Highcharts.dateFormat('%A, %b %e, %Y', this.x) + ':<br/> ' +
this.y + ' sessions',
width: 200
});
}
}
},
marker: {
lineWidth: 1
}
}
},
series: [{
name: 'All sessions',
lineWidth: 4,
marker: {
radius: 4
}
}, {
name: 'New users'
}]
});
This comes from the series label module, which you can use by including series-label.js:
<script src="https://code.highcharts.com/modules/series-label.js"></script>
See this JSFiddle example of a Highstock chart with it included.
See this API documentation for its settings.
I am trying to have responsive Highcharts with Angular5 using responsive configuration from https://www.highcharts.com/docs/chart-concepts/responsive like this:
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
enabled: false
}
}
}]
}
I am using angular-highcharts library for doing this along with typescript.
Below is my code with the responsive configuration exactly as mentioned on Highcharts website:
import {Component, OnInit} from '#angular/core';
import {Chart} from 'angular-highcharts';
import * as Highcharts from 'highcharts';
#Component({
selector: 'historical-health-data',
templateUrl: './historical-health-data.component.html',
styleUrls: ['./historical-health-data.component.less']
})
export class HistoricalHealthDataComponent {
chart: Chart;
ngOnInit() {
this.chart = new Chart({
chart: {
type: 'column',
height: this.height,
style: {fontFamily: 'inherit'}
},
title: {
text: null
},
exporting: {
enabled: false
},
legend: {
enabled: false
},
credits: {
enabled: false
},
lang: {
noData: null
},
plotOptions: {
series: {
animation: true,
connectNulls: true,
marker: {
symbol: 'circle',
lineWidth: 1,
lineColor: '#fff'
}
},
column: {
states: {
hover: {
enabled: false
}
},
pointPadding: 0,
borderWidth: 0.1,
pointWidth: 20,
dataLabels: {
enabled: false
}
}
},
xAxis: {
type: 'datetime',
tickInterval: 24 * 3600 * 1000,
labels: {
rotation: -60
}
},
yAxis: {
min: 0,
title: {
text: null
}
},
series: [{
data: [{
x: Date.UTC(2012, 0, 1),
y: 1
}, {
x: Date.UTC(2012, 0, 8),
y: 3
}, {
x: Date.UTC(2012, 0, 15),
y: 2
}, {
x: Date.UTC(2012, 0, 22),
y: 4
}],
pointRange: 24 * 3600 * 1000
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
enabled: false
}
}
}]
}
});
});
}
}
historical-health-data.component.html:
<div [chart]="chart"></div>
By adding the responsive configuration exactly as mentioned in Highcharts documentation : https://www.highcharts.com/demo/responsive i am getting the following error:
error TS2345: Argument of type '{ chart: { type: string; height: number; style: { fo
ntFamily: string; }; events: { click: () => v...' is not assignable to parameter of type 'Options'.
Types of property 'responsive' are incompatible.
Type '{ rules: { condition: { maxWidth: number; }; chartOptions: { legend: { enabled: boolean; }; }; }[...' is not assignable to type 'ResponsiveOptions[]'.
Object literal may only specify known properties, and 'rules' does not exist in type 'ResponsiveOptions[]'.
What am i doing wrong here ? Is there a better way to achieve responsive charts ?
I am aware that a chart has to be by default responsive but in my case this is how the x-axis is behaving when the browser is minimized to < 700px :
The x-axis is expanding and going underneath the next panel on the page.
This is how it has to be or similar to:
I faced same issue and This is my solution and hope it will help to anyone.
It may have performance issue on large data set.
ngOnInit() {
this.innerWidth = window.innerWidth;
this.chartOptions = {
chart: {
type: 'line',
height: 120,
width: this.innerWidth - 50
},.....
};
this.chart = new Chart(this.chartOptions);
}
Direct screen change and redrew it.
#HostListener('window:resize', ['$event'])
onResize(event) {
this.innerWidth = window.innerWidth;
this.chartOptions.chart.width = this.innerWidth - 50;
this.chart = new Chart(this.chartOptions);
}
Using BreakpointObserver fixed my issue, the other little change i have done is to use chartConfig to build the config first using highcharts Options and then bind the data to the Chart object. This way i can always reload config whenever i need to redraw the chart. Here is the complete code:
import {Component, OnInit} from '#angular/core';
import {Chart} from 'angular-highcharts';
import * as Highcharts from 'highcharts';
import {Options} from 'highcharts/highstock';
import {BreakpointObserver} from '#angular/cdk/layout';
#Component({
selector: 'historical-health-data',
templateUrl: './historical-health-data.component.html',
styleUrls: ['./historical-health-data.component.less']
})
export class HistoricalHealthDataComponent {
chart: Chart;
chartConfig: Options;
constructor(private bm: BreakpointObserver) {
super();
}
media() {
// responsive chart
this.mediaSubscription = this.bm.observe('(max-width: 1200px)').subscribe(result => {
//change these values to your desired values as per requirement
const height = result.matches ? 190 : 300;
if (!this.height) {
// initial display
this.height = height;
this.load();
} else if (this.height !== height && this.chart && this.chart.ref) {
// redraw
this.height = height;
this.chartConfig.chart.height = this.height;
this.chart = new Chart(this.chartConfig);
} else {
// do nothing
}
});
}
ngOnInit() {
this.media();
this.chartConfig = {
chart: {
type: 'column',
height: this.height,
style: {fontFamily: 'inherit'}
},
title: {
text: null
},
exporting: {
enabled: false
},
legend: {
enabled: false
},
credits: {
enabled: false
},
lang: {
noData: null
},
plotOptions: {
series: {
animation: true,
connectNulls: true,
marker: {
symbol: 'circle',
lineWidth: 1,
lineColor: '#fff'
}
},
column: {
states: {
hover: {
enabled: false
}
},
pointPadding: 0,
borderWidth: 0.1,
pointWidth: 20,
dataLabels: {
enabled: false
}
}
},
xAxis: {
type: 'datetime',
tickInterval: 24 * 3600 * 1000,
labels: {
rotation: -60
}
},
yAxis: {
min: 0,
title: {
text: null
}
},
series: [],
};
//assign/bind the data here after the config is initialized
this.chartConfig.series = [{
data: [{
x: Date.UTC(2012, 0, 1),
y: 1
}, {
x: Date.UTC(2012, 0, 8),
y: 3
}, {
x: Date.UTC(2012, 0, 15),
y: 2
}, {
x: Date.UTC(2012, 0, 22),
y: 4
}],
pointRange: 24 * 3600 * 1000
}];
//finally create the Chart object here with the config
this.chart = new Chart(this.chartConfig);
});
}
}
I have this chart. I want to add some check icons in the rectangle from the legend, when it is selected.
How can I do this?
var chart = new Highcharts.Chart({
chart: {
renderTo: this,
type: 'pie'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: false
},
showInLegend: true
}
},
series: [{
data: jsonChart
}],
legend: {
symbolWidth: 40,
align: 'right',
layout: 'vertical',
verticalAlign: 'top',
x: 40,
y:0,
width: 150,
},
});
});The chart
You can use Renderer to render an image in the chart.
function drawTicks() {
const {
translateX: tx,
translateY: ty
} = this.legend.group;
this.series[0].points.forEach(p => {
let img = p.img;
if (!img) {
p.img = img = this.renderer.image('http://icons.iconarchive.com/icons/visualpharm/must-have/256/Check-icon.png', -9999, 0, 15, 15).attr({
zIndex: 10
}).add();
}
const bbox = p.legendSymbol.getBBox();
const x = p.legendGroup.translateX + tx;
const y = p.legendGroup.translateY + ty;
img.attr({
x: x,
y: y
});
});
}
on load/redraw draw ticks
chart: {
events: {
load: drawTicks,
redraw: drawTicks
}
},
on legendItemClick change the img's visibility
series: [{
type: 'pie',
name: 'Browser share',
point: {
events: {
legendItemClick: function() {
this.img.attr({
visibility: !this.visible ? 'visibile' : 'hidden'
});
}
}
},
example: http://jsfiddle.net/3348yjrq/
Im trying to create plotbands but does not work correctly.
Here is my fiddle and code.
https://jsfiddle.net/z0h85fku/
Javascript
$(function() {
categories = ["09/07/2016 00:00", "09/07/2016 00:01", "09/07/2016 00:02", "09/07/2016 00:03", "09/07/2016 00:04"]
rate_1 = [0.8, 0.54, 0.6, 0.3, 0.4]
rate_2 = [0.33, 0.16, 0.33, 0.3, 0.38]
rate_3 = [0.03, 0.04, 0.05, 0.03, 0.01]
var addCallout = function(chart) {
$('.callout').remove();
var xAxis = chart.xAxis[0],
yAxis = chart.yAxis[0],
series = chart.series[0],
point = series.data[0];
console.log('xAxis == ', xAxis)
console.log('yAxis == ', yAxis.toPixels)
console.log('series == ', series)
console.log('point == ', point)
console.log(point.plotY)
console.log(point.plotX)
var a = chart.renderer.label('<div class="callout top">This is the callout text!</div>', point.plotX + chart.plotLeft - 20,
point.plotY + chart.plotTop - 70, 'callout', null, null, true).add();
};
$('#container').highcharts({
chart: {
// type: 'bar',
events: {
load: function() {
addCallout(this);
},
redraw: function() {
addCallout(this);
},
}
},
title: {
text: 'Spikes Graph',
x: -20 //center
},
subtitle: {
text: '',
x: -20
},
events: {
load: function() {
// addCallout(this);
},
redraw: function() {
addCallout(this);
},
},
series: [{
turboThreshold: 2000 // to accept point object configuration
}],
xAxis: {
categories: categories,
<!-- tickInterval: 60,-->
plotBands: [{
color: 'orange', // Color value
// from: Date.UTC(09/07/2016 02:00), // Start of the plot band
// Date.UTC(year,month,day,hours,minutes,seconds,millisec)
from: Date.UTC(2016,9,7,0,0),
to: Date.UTC(2016,9,7,4,0)
// to: '09/07/2016 05:00' // End of the plot band
}],
type:'datetime'
},
yAxis: {
title: {
text: 'Error Rate'
},
min: 0,
max: 5,
plotLines: [{
value: 0,
width: 1,
color: '#808080'
}],
labels: {
format: '{value} %'
}
},
tooltip: {
valueSuffix: '°C'
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle',
borderWidth: 0
},
series: [
// {turboThreshold: 2000 },
{
name: 'Rate-1',
data: rate_1,
turboThreshold: 2000,
lineWidth: 1,
dataLabels: {
enabled: true,
useHTML: true,
style: {
fontWeight: 'bold'
},
},
}, {
name: 'Rate-2',
data: rate_2,
turboThreshold: 2000,
lineWidth: 1
}, {
name: 'Rate-3',
data: rate_3,
turboThreshold: 2000,
lineWidth: 1
}
]
});
});
I am using Area chart with navigator, what I am trying to do is highlight high and Low point markers (only two points ) in the current visible chart, and on top of these markers I want to display fixed tooltips displaying the point information.
And as user navigates through navigator these point markers should be recalculated and tooltips should follow them.
[This is what I am trying to accomplish][1]
So far I have been able to calculate high and low points and highlight corrosponding markers in chart, and I have also been able to display two tooltips, but they are not ACURATELY positioned along with point markers.
![So far this has been accomplished][2]
Here is my Code:
function customTooltip(point) {
console.log(chart);
var text = chart.renderer.text(
'Max',
point.plotX + chart.plotLeft + 10,
point.plotY + chart.plotTop - 10
).attr({
zIndex: 5
}).add();
var box = text.getBBox();
chart.renderer.rect(box.x - 5, box.y - 5, box.width + 10, box.height + 10, 5)
.attr({
fill: '#FFFFEF',
stroke: 'gray',
'stroke-width': 1,
zIndex: 4
})
.add();
}
var labelArr = [], // keeps Tooltips for High and Low
chart = $('#container').highcharts('StockChart', {
chart: {
type: 'line',
width: 900
},
scrollbar: {
enabled: false
},
navigator: {
top: -1,
height: 25,
handles: {
backgroundColor: 'transparent',
borderColor: 'transparent'
}
},
rangeSelector: {
inputPosition: {
align: 'left',
x: 10,
y: 30
},
buttons: [{
type: 'year',
count: 1,
text: ''
}],
buttonTheme: { // styles for the buttons
fill: 'none',
stroke: 'none',
'stroke-width': 0,
states: {
hover: {
fill: 'none'
},
select: {
fill: 'none'
}
}
},
inputDateFormat: '%m-%d-%Y',
inputStyle: {
fontSize: '14px',
borderColor: '#FFF'
},
selected: 0
},
yAxis: {
labels: {
align: 'right',
x: -5,
formatter: function () {
return "$" + this.value;
}
}
},
xAxis: {
type: 'datetime',
tickWidth: 0,
labels: {
y: 20
},
dateTimeLabelFormats: {
month: '%B'
},
events: {
setExtremes: function () {
var pointMax, pointMin, labelLength = labelArr.length;
// Flush out Old Tooltips for High and Low
if (labelLength > 0) {
for (var i = 0; i < labelLength; i++) {
var popVal = labelArr.pop();
this.chart.container.firstChild.removeChild(popVal);
}
}
$.each(this.series[0].points, function (i, point) {
if (!pointMax && !pointMin) pointMax = pointMin = point;
// If marker is enabled for any point, disable it
if (typeof point.marker != 'undefined') point.marker.enabled = false;
// Calculate Highest point
if (pointMax.y < point.y) pointMax = point;
// Calculate Lowest point
if (pointMin.y > point.y) pointMin = point;
});
pointMax.update({
marker: {
enabled: true
}
}, false, false);
//customTooltip( pointMax );
pointMin.update({
marker: {
enabled: true
}
}, false, false);
//customTooltip( pointMin );
}
}
},
tooltip: {
crosshairs: false
/*useHTML: true,
borderRadius: 0,
backgroundColor: '#000',
shadow: false,
borderWidth: 0,
enabled: true,
formatter: function(){
/* Temp Disable Custom tool-Tip
var arr = [];
$.each(this.points, function(k, obj){
arr.push( "<span style='color:#FFF'>Low price w/o sales charge</span>" );
arr.push( "<br>" );
arr.push( "<span style='font-weight:bold;color:#FFF'>$" + obj.y + "</span>" );
arr.push( "<br>" );
});
return arr.join(' ');
} */
},
plotOptions: {
area: {
marker: {
fillColor: '#f7941e',
states: {
hover: {
enabled: false
}
}
}
},
series: {
point: {
events: {
update: function (event) {
event.target.series.chart.tooltip.refresh([event.target]);
var cloneToolTip = event.target.series.chart.tooltip.label.element.cloneNode(true);
event.target.series.chart.container.firstChild.appendChild(cloneToolTip);
labelArr.push(cloneToolTip);
}
}
}
}
},
series: [{
name: 'Quarterly Returns w/o sales charge',
data: [
[1149120000000, 62.17],
[1149206400000, 61.66],
[1369699200000, 441.44],
[1369785600000, 444.95]
]
// pointWidth: 14,
}]
}).highcharts();
});
Can you please guide me on how to proceed from here?