Individual shape and position of annotations in highcharts - reactjs

I have figured out how to set the size for an annotation individually:
labels: [
{
point: {
x: chart.xAxis[0].max - 0.1,
y: 50,
xAxis: 0,
yAxis: 0
},
height: 100,
shape: "rect",
text: "test",
verticalAlign: "bottom"
}
]
I would like it to position between 50 and 150. How can I achieve that?
And additionally, I would like the text to be aligned in the center of the box?!

You can calculate the height by using toPixels method. You have to also take a padding into account. To center the text you can use asynchronous function, because annotations do not exist in load event yet.
chart: {
events: {
load: function() {
const chart = this;
const height =
chart.yAxis[0].toPixels(50) - chart.yAxis[0].toPixels(150);
chart.addAnnotation({
labels: [
{
point: {
x: chart.xAxis[0].max - 0.1,
y: 150,
xAxis: 0,
yAxis: 0
},
y: 0,
padding: 0,
height: height,
shape: "rect",
text: "test",
verticalAlign: "top"
}
]
});
}
}
}
Live demo: https://codesandbox.io/s/qqqkx2zr49
API: https://api.highcharts.com/class-reference/Highcharts.Axis#toPixels

Related

Creating chart overlays with Plotly.js

I have been trying to create overlays with Plotly.js, e.g. Week over Week, Month over Month etc., and I am required to render a similar looking chart as below. I believe the candleStick chart can get me somewhat near to it, but just wanted to explore if anyone has got a better idea.
Year Over Year, chart sample
The candleStick plots are a good option indeed, but they are somewhat limited in Plotly (see below). Another one is to use fill between two curves, something that'd look like this:
Here is the code to produce this:
<html>
<head>
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div class="item-graph" id="plotly_graph">
</div>
</body>
<script>
// Some random data
const date = ["2022/01/01", "2022/01/07", "2022/01/13", "2022/01/18", "2022/01/25", "2022/02/01", "2022/02/07", "2022/02/13", "2022/02/18", "2022/02/25"]
const new_date = date.map(function (d) { return new Date(d) })
const bluecurve = [450, 550, 460, 450, 530, 440, 340, 345, 290, 270]
const graycurve = [390, 410, 320, 490, 470, 380, 480, 410, 190, 310]
const min = [350, 430, 420, 410, 480, 350, 320, 310, 230, 190]
const max = [500, 600, 520, 490, 540, 500, 450, 390, 350, 360]
// Setting range of Forecast for hoverinfo
var hovertemplate = []
for (let i = 0; i < min.length; i++) {
hovertemplate.push(min[i] + ' - ' + max[i])
}
// Setting up the traces:
traces = [
{
x: new_date,
y: max,
// name: 'Forecast',
yaxis: 'y',
showlegend: false,
line: { width: 1, shape: 'hvh', color: "lightblue" },
hoverinfo: 'skip',
mode: 'lines',
},
{
x: new_date,
y: min,
name: 'Forecast',
yaxis: 'y',
showlegend: false,
line: { width: 1, shape: 'hvh', color: "lightblue" },
// hoverinfo: 'skip',
hovertemplate: hovertemplate,
mode: 'lines',
fillcolor: "lightblue",
fill: 'tonexty',
},
{
x: new_date,
y: bluecurve,
name: "This Year",
yaxis: 'y',
type: 'scatter',
showlegend: false,
mode: 'markers',
marker: {
size: 20,
color: "blue",
line: {
width: 2,
color: 'DarkSlateGrey'
},
},
},
{
x: new_date,
y: graycurve,
name: "Last Year",
yaxis: 'y',
type: 'scatter',
showlegend: false,
mode: 'markers',
marker: {
size: 20,
color: "lightgray",
line: {
width: 2,
color: 'DarkSlateGrey'
},
},
},
]
// Setting up layout
const layout = {
yaxis: {
rangemode: 'nonnegative',
range: [0, 700]
},
hovermode: "x unified",
};
// Creating the plots
Plotly.react("plotly_graph", traces, layout);
</script>
</html>
If you want to use candlesticks, you can change the layout and the first two elements on the traces to, respectively:
const layout= {
xaxis: {
type: 'date',
rangeslider: {
visible: false,
},
},
yaxis: {
rangemode: 'nonnegative',
range: [0,700]
},
hovermode: "x unified",
};
and
{
x: new_date,
low: min,
open: min,
high: max,
close: max,
decreasing: {line: {color: "lightblue" }},
increasing: {line: {color: "lightblue" }},
yaxis: 'y',
type: 'candlestick',
showlegend: false,
// text: hovertemplate,
hoverinfo: 'skip',
},
The hoverinfo of the candlesticks seem to always include high, low, open and close (I couldn't find a way to edit it, as text just adds to those, so I deactivated it). Here is how it looks like:
There's also no control over the width, apart from the number of sticks in the figure.

Multiple Gauge Chart

Is it possible to Draw this type of gauges in the left and right of the circle using Highcharts?
Basically left side gauge is representing the shorts' %age at left, the right side gauge is representing the shorts' %age at right, and the center is one simple round circle with the %age of center shots.
Series variable pie it's looks fit better for this case.
Tooltip we built setting useHTML:true, circle at the center we rendered by SVG renderer.
Highcharts.chart('container', {
chart: {
events: {
render() {
const chart = this;
if (!chart.customCenterCircle) {
chart.customCenterCircle = chart.renderer.circle(
chart.plotLeft + chart.plotSizeX / 2,
chart.plotTop + chart.plotSizeY / 2,
0
).add().toFront();
}
if (!chart.customCenterText) {
chart.customCenterText = chart.renderer.text('50%', 0, 0).css({
fontSize: '24px',
color: '#d4d4d4'
}).add().toFront();
}
chart.customCenterCircle.animate({
x: chart.plotLeft + chart.plotSizeX / 2,
y: chart.plotTop + chart.plotSizeY / 2,
r: chart.series[0].center[3] / 2,
fill: 'rgba(31, 112, 31, 0.5)',
stroke: 'rgba(154, 214, 154, 1)',
'stroke-width': 4
});
chart.customCenterText.attr({
x: chart.plotLeft + chart.plotSizeX / 2 -
chart.customCenterText.getBBox().width / 2,
y: chart.plotTop + chart.plotSizeY / 2 -
chart.customCenterText.getBBox().y -
chart.customCenterText.getBBox().height / 2
});
}
}
},
tooltip: {
backgroundColor: '#ffffff',
borderWidth: 0,
useHTML: true,
formatter: function() {
return `<p><h1 style="color:${this.color};">${this.y}</h1></br>${this.key}</p>`
}
},
series: [{
type: 'variablepie',
minPointSize: 0,
innerSize: '30%',
startAngle: 30,
dataLabels: {
enabled: false
},
borderWidth: 3,
zMin: 0,
data: [{
y: 80,
z: 100,
name: 'other',
color: 'black'
}, {
y: 30,
z: 100,
name: 'missed right',
color: 'red'
}, {
y: 50,
z: 0
}, {
y: 25,
z: 80,
name: 'missed right',
color: 'red'
}, {
y: 75,
z: 80,
name: 'other',
color: 'black'
}, {
y: 60,
z: 0,
name: 'other',
}]
}]
});
Live demo:
https://jsfiddle.net/BlackLabel/sc9vwzjt/2/
API References:
https://www.highcharts.com/docs/chart-and-series-types/variable-radius-pie-chart
https://api.highcharts.com/highcharts/series.variablepie
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer

Mouse over on line chart data active other data-set in Chart.js

I'm creating a line chart using Chart.js. The chart has two datasets. The x-axis is date, and y-axis is the value. When I hover the first data in dataset 1, the first data in dataset 2 is also active(zoom). That isn't I expected. Is there any way to active only the hovered data. And is there any way to active all data by their y value, not by index.
I've tried edit the tooltips mode but the result is not I expected. It shows the tooltips in difference dataset with same index.
https://www.chartjs.org/docs/latest/general/interactions/modes.html
var ctx = document.getElementById("myChart");
var barChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Dataset 1',
data: [{
x: '2019-01-15',
y: 100
}, {
x: '2019-02-03',
y: 300
}],
backgroundColor: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(255, 0, 0, 1)',
borderWidth: 1
}, {
label: 'Dataset 2',
data: [{
x: '2019-01-03',
y: 150
}, {
x: '2019-01-15',
y: 200
}, {
x: '2019-02-06',
y: 250
}],
backgroundColor: 'rgba(0, 0, 0, 0)',
borderColor: 'rgba(0, 255, 255, 1)',
borderWidth: 1
}],
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}],
xAxes: [{
type: 'time',
position: 'bottom',
time: {
min: "2019-1-1",
max: "2019-2-28",
unit: "month",
displayFormats: {
"month": "YYYY-MM",
}
}
}]
}
}
});
https://jsfiddle.net/t1gmrujo/2/
I've tried edit the tooltips mode but the result is not I expected. It shows the tooltips in difference dataset with same index.
The tooltip configuration controls display of the tooltip popup, not the dataset points. Points are controlled by the hover configuration. This is mentioned on the page you linked (emphasis mine):
When configuring interaction with the graph via hover or tooltips, a number of different modes are available.
If you only want the single point you are hovering over to be highlighted, use:
options: {
hover: {
mode: 'point'
}
}
If you want the whole dataset highlighted when hovering any single dataset point, use:
options: {
hover: {
mode: 'dataset'
}
}
If you want to highlight the dataset and see all dataset values in the tooltip, use:
options: {
hover: {
mode: 'dataset'
},
tooltips: {
mode: 'dataset'
}
}

Get max of x axis in highcharts using react

I am trying to get the max value of the x axis and set an annotation just at the end:
y: chart.xAxis[0].max-1
What is the right syntax to get it working in react? See a live demo here.
You can not use values from the chart in options. You should add your annotations dynamically in addAnnotation method:
chart: {
events: {
load: function(){
const chart = this;
chart.addAnnotation({
labels: [
{
point: {
x: 3,
y: chart.xAxis[0].max - 1,
xAxis: 0,
yAxis: 0
},
text: "x: {x}<br/>y: {y}"
},
{
point: {
x: 0,
y: 0
},
text: "x: {point.plotX} px<br/>y: {point.plotY} px"
},
{
point: {
x: 5,
y: 100,
xAxis: 0
},
text: "x: {x}<br/>y: {point.plotY} px"
}
],
labelOptions: {
x: 40,
y: -10
}
})
}
}
}
Live demo: https://codesandbox.io/s/537kz8xwyx

Custom component not displaying on an Ext.panel.Panel

I have extended a component and I can't get it to render to a panel. Seems like I am missing something pretty basic since the debugger in Chrome actually shows that the panel has the data, it just isn't showing up.
Here is the fiddle and here are parts of the code:
Custom Component:
Ext.define('StoplightControl', {
extend: 'Ext.draw.Component',
alias: 'widget.Stoplight',
constructor: function (config) {
this.initConfig(config);
this.callParent(arguments);
},
initComponent: function () {
var kpiData; // = Ext.data.StoreManager.get('KPIStore').getById(this.model.get('KPI_ID'));
if (typeof (kpiData) === 'undefined' || kpiData == null) {
kpiData = Ext.create('KPIModel', {
ControlBackground: '#000000',
Caution_label: 'On',
Good_label: 'Ahead',
Poor_label: 'Behind',
Good_color: '#00FF00',
Poor_color: '#ff0000',
Caution_color: '#550000',
Header: 'Test'
});
}
this.setGradients(kpiData.get('ControlBackground'));
this.drawItems(this.model, kpiData);
},
setGradients: function (controlColor) {
this.gradients = [{
id: 'middleGradient',
angle: 180,
stops: {
0: {
color: controlColor,
opacity: 1
},
50: {
color: controlColor,
opacity: .6
},
100: {
color: controlColor,
opacity: 1
}
}
}, {
id: 'lightGradient1',
angle: -90,
stops: {
0: {
color: '#ffffff',
opacity: 0.01
},
100: {
color: '#ffffff',
opacity: .8
}
}
}]
},
drawItems: function (model, kpiData) {
var cautionValueX = -22.5 * (model.get('cautionValue').toString().length) + 227.5,
goodValueX = -22.5 * (model.get('goodValue').toString().length) + 227.5,
poorValueX = -22.5 * (model.get('poorValue').toString().length) + 227.5,
maxLineLength = 15,
changeOfY = -50,
cautionLabel = linebreaks(kpiData.get('Caution_label'), maxLineLength),
goodLabel = linebreaks(kpiData.get('Good_label'), maxLineLength),
poorLabel = linebreaks(kpiData.get('Poor_label'), maxLineLength),
cautionChangeY = (cautionLabel.split("\n").length - 1) * changeOfY,
goodChangeY = (goodLabel.split("\n").length - 1) * changeOfY,
poorChangeY = (poorLabel.split("\n").length - 1) * changeOfY,
headerFontSize = '100px arial,sans-serif',
textFontSize = '80px arial,sans-serif';
var drawItems = [{
type: 'rect',
x: 1.6620979,
y: 52.362183,
radius: 90,
width: 448.10959,
height: 1000,
fill: 'url(#middleGradient)',
stroke: 'none'
}, {
type: "circle",
radius: 140,
x: 224,
y: 896,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Good_color')
}, {
type: "circle",
x: 224,
y: 214,
radius: 140,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Poor_color')
}, {
type: "circle",
x: 224,
y: 555,
radius: 140,
stroke: "#000000",
'stroke-width': 1,
fill: kpiData.get('Caution_color')
}, {
type: "text",
id: "svg-stoplight-poorValue",
text: model.get('poorValue'),
x: poorValueX,
y: 220,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-cautionValue",
text: model.get('cautionValue'),
x: cautionValueX,
y: 560,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-goodValue",
text: model.get('goodValue'),
x: goodValueX,
y: 900,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-poorLabel",
text: poorLabel,
x: 500,
y: 220 + poorChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-cautionLabel",
text: cautionLabel,
x: 500,
y: 560 + cautionChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-goodLabel",
text: goodLabel,
x: 500,
y: 900 + goodChangeY,
fill: "Black",
font: textFontSize
}, {
type: "text",
id: "svg-stoplight-headerLabel",
text: kpiData.get('Header'),
x: 145,
y: -40,
fill: "Black",
font: headerFontSize
}, {
type: "text",
id: "svg-stoplight-totalLabel",
text: "Total = " + model.get('total'),
x: 100,
y: 1250,
fill: "Black",
font: textFontSize
}];
//don't add gradients if IE is > 10 or documentMode is less than 9
if (!(ie > 10 || document.documentMode < 9)) {
drawItems.push({
type: "ellipse",
id: 'test1',
radiusX: 112,
radiusY: 80,
x: 224,
y: 156,
fill: 'url(#lightGradient1)'
}, {
type: "ellipse",
radiusX: 112,
radiusY: 80,
x: 224,
y: 498,
fill: 'url(#lightGradient1)'
}, {
type: "ellipse",
radiusX: 112,
radiusY: 80,
x: 224,
y: 838,
fill: 'url(#lightGradient1)'
});
}
},
width: 210,
height: 250
});
Creation of the Panel and adding the component:
var displayPanel = Ext.create('widget.panel', {
width: 600,
height: 800,
title: 'Cost & Schedule Variance',
renderTo: 'WorkstreamStoplights',
pack: 'center',
shrinkWrap: 3,
layout: {
type: 'table',
column: 2
},
});
stoplightStore.each(function (model, idx) {
var stoplight = Ext.create('StoplightControl', {
model: model
});
displayPanel.add(stoplight);
});
displayPanel.doLayout();
As you'll be able to see from the fiddle, the Title displays properly and I have even added an item to the displayPanel on creation, but doing a .add() doesn't seem to have any effect even with the .doLayout()
Haven't dabbled in ExtJS for a long time, but the 4.2 doc states, for this method:
This method needs to be called whenever you change something on this
component that requires the Component's layout to be recalculated.
Ah, silly me. I needed to add items to my component. I needed to make the assignment in the initComponents of
this.items = drawItems;
Working fiddle

Resources