How to render custom line with echarts? - javascript

Been struggling to find this, and have even resorted to logging output of echarts' various objects in the console to try to see what's going on. It would seem that visualMap doesn't work properly when you specify a different dimension in your data, so I've been trying to write a simple renderItem function for my line series. I can't find any documentation or examples on specifics for rendering a line - specifically, when data is passed into it, how do I get coordinate points for both the start and end of the line? I can get the values of the point (the data point which would give you the coordinates of the current data point), but a line consists of 2 points (start and end). What am I missing here?
Codepen example to play with: https://codepen.io/WorldWideWebb/pen/JjbJpRJ
visualMap that didn't work (it changes the color of the point, NOT the line; the point colors do change just fine, but I want to color the line)
visualMap: {
dimension: 3,
seriesIndex: 2,
show: false,
pieces: [{
gt: 0,
lte: 50,
color: '#93CE07'
}, {
gt: 50,
lte: 100,
color: '#FBDB0F'
}, {
gt: 100,
lte: 150,
color: '#FC7D02'
}, {
gt: 150,
lte: 200,
color: '#FD0100'
}, {
gt: 200,
lte: 300,
color: '#AA069F'
}, {
gt: 300,
color: '#AC3B2A'
}],
outOfRange: {
color: '#999'
}
},
You can see the points in the different colors if you uncomment the visualMap in the codepen example and change "showSymbol" in the last item in the series to true.
This one was close, but I haven't been able to figure out how to get both the origin and end to create the line properly (x2 and y2 are both static); also, this seems to produce a bunch of separate lines, rather than a line series:
renderItem: function (params, api) {
var coord = api.coord([api.value(0), api.value(1)]);
return {
type: 'line',
shape: {
x1: coord[0],
y1: coord[1],
x2: 200,
y2: 100
},
style: { stroke: formatDirectionLabel(api.value(1)), lineWidth: 2 }
}
}
Example of the data (this is time, wind speed, wind gust, wind direction, and temp); I use map to transform that into simple arrays when it's pulled:
{"dt":"2021-02-18 06:33:10","w":"7.38","g":"9.84","dir":"343","f":"47.70"}
My goal is to display a line - time is the X axis, wind speed is the y axis, and color the line based on wind direction. Like I said, all of it would work if I just wanted to color the points, but that would make the graph really cluttered (not what I'm going for).
How do I color each line segment based on wind direction? Can someone provide a simple example of passing data in to render a custom line using renderItem?

With a whole bunch of trial and error, I got it working. The solution was using params.dataIndexInside+1 to produce the next item in the series. renderItem contents:
let coord1 = api.coord([api.value(0, params.dataIndexInside), api.value(1, params.dataIndexInside)]),
coord2 = api.coord([api.value(0, params.dataIndexInside+1), api.value(1, params.dataIndexInside+1)]);
return {
type: 'line',
shape: {
x1: coord1[0],
y1: coord1[1],
x2: coord2[0],
y2: coord2[1]
},
style: {
stroke: customFormattingFunction(api.value(3))
}
},
Hope that saves someone some time

Related

How to order bubbles according their size and not by the order of their datasets?

I have a bubble chart with multiple datasets. Two points of two different datasets may have the same coordinates (x and y-value) and lay on the same place in the chart. Because the display order of the points is determined according the order of the datasets, the smaller point could be completely covered by the bigger point in front of it.
Is there a option or a way, to display the points in order of their bubble size?
Simplified example of four points. The solution must also work for multiple datasets with each 30+ points.
I am searching a solution to draw the blue point in front of the red point, for the left pair and let the right pair as it is. This order must be independent of the order of the datasets, as it is per point and not per dataset.
Sorting the datasets seems to be no option for me, as the order cannot be determined per dataset, but instead must be determined for every coordinate/point. When drawing a point, it must be checked for this particular coordinate, if any other point with the same coordinates exists and if this point is greater than the current point (if true, the greater point must be drawn before, to not cover up the current point).
const config = {
type: 'bubble',
data: {
datasets: [{
label: 'Dataset 1',
data: [{
x: 1,
y: 1,
r: 20
},
{
x: 2,
y: 1,
r: 15
}
],
borderColor: 'red',
backgroundColor: 'red'
},
{
label: 'Dataset 2',
data: [{
x: 1,
y: 1,
r: 15
},
{
x: 2,
y: 1,
r: 20
}
],
borderColor: 'blue',
backgroundColor: 'blue'
}
]
},
options: {
responsive: true,
scales: {
x: {
suggestedMin: 0,
suggestedMax: 3
}
},
plugins: {
legend: {
position: 'top',
}
}
}
};
var ctx = document.getElementById('chartJSCanvas').getContext('2d');
const chart = new Chart(ctx, config);
<body>
<canvas id="chartJSCanvas" width="300" height="100"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.1.0/chart.js" integrity="sha512-LlFvdZpYhQdASf4aZfSpmyHD6+waYVfJRwfJrBgki7/Uh+TXMLFYcKMRim65+o3lFsfk20vrK9sJDute7BUAUw==" crossorigin="anonymous"></script>
</body>
The easiest way would be to just sort the data in the datasets and then the datasets themselves before drawing them.
An easy way to do this is provided by Array.prototype.forEach and Array.prototype.sort
First sort the data within each dataset like this:
config.data.datasets.forEach(function(element){
element.data.sort(function (a, b) {
return a.r - b.r;
});
});
Then you can sort the data sets by their smallest element like this:
config.data.datasets.sort(function (a, b) {
return a.data[0].r - b.data[0].r;
});
After that, you can regularly pass your config object with ordered datasets to your library call just the way you do it above:
const chart = new Chart(ctx, config);

Format (same) line to different styles between specific marker points

Have been struggling with something that should be pretty straightforward. I have a line chart showing sports teams attendances over a number of seasons. This is easy to do, except I want to format the line to a dash when a team is relegated to the division below e.g. division 1 normal line, division 2 dash. An example that someone else has created (unfortunately not in Plotly) can be viewed here.
So far the best I have managed is by setting two variables for a team - one for division 1 (tier 1), one for division 2 - to appear as separate variables, which would be OK but for the large gap that appears - see Link to attendanceDiv chart.
Would appreciate any help with this. Should really be an option to format lines between markers using selectedpoints. Code below. Thanks.
var bristol1 = {
x: ['2000-01', '2001-02', '2002-03', '2003-04', '2004-05'],
y: [4639, 5316, 7023, null, null],
name: 'Bristol (tier 1)',
mode: 'lines+markers',
line: {
color: 'blue',
width: 2
}
};
var bristol2 = {
x: ['2000-01', '2001-02', '2002-03', '2003-04', '2004-05'],
y: [null, null, null, 3684, 5234],
name: 'Bristol (tier 2)',
mode: 'lines+markers',
line: {
color: 'blue',
width: 2,
dash: 'dash'
}
};
var data = [bristol1, bristol2];
var layout = {
title: 'First Tier Rugby Union Clubs: Average Attendance',
xaxis: {
title: 'Season',
type: 'category',
tickvals: ['2000-01', '2001-02', '2002-03', '2003-04', '2004-05']
},
yaxis: {
title: 'Attendance',
range: [0, 8000]
}
};
Plotly.newPlot('attendanceDiv', data, layout, {showSendToCloud: true});

Draw horizontal target line using EChart.JS

I would like to draw a horizontal target line showing threshold limits on a line, bar and pie chart using EChart.JS (https://ecomfe.github.io/echarts-doc/public/en/index.html).
There are other threads - "Chart.js - draw horizontal line" which detail how to do it with Chart.JS. Has anyone out there got particular experience on this with EChart?
Thanks in advance.
[Edit] Since Echarts v3 came up and was passed to the Apache Foundation, the documentation has been sclattered through different URLs, some options have gone away, some are not shown in all documentation resources, and so on. Links provided below have been updated (as of 24/02/2020) but might break again. I haven't fully tried v3 but provided code below should still work.[/Edit]
The option markLine is designed for that, see documentation here:
https://echarts.apache.org/en/option.html#series-line.markLine
Note that there are different uses for it, and different options to provide, depending on what you want to draw:
arbitrary line on the canvas (any size, any direction, any style)
lines matching data caracteristics (min, max, average)
horizontal/vertical lines
You have to use the attribute markLine.data in all cases, and description of specifics is described here:
https://echarts.apache.org/en/option.html#series-line.markLine.data
Here's how I go, with a line curve on a time serie. Note that I couldn't get, within markLine.data[0], yAxis to be enough to draw a horizontal line: xAxis must be specified too (start and end points).
xAxis: {
type: 'time',
},
yAxis: {
type: 'value'
},
series: [{
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0,
data: [
[1509762600, 7.11376],
[1509832800, 7.54459],
[1509849000, 7.64559]
],
markLine: {
data: [
// 1st line we want to draw
[
// start point of the line
// we have to defined line attributes only here (not in the end point)
{
xAxis: 1509762600,
yAxis: 3,
symbol: 'none',
lineStyle: {
normal: {
color: "#00F"
}
},
label: {
normal: {
show: true,
position: 'end',
formatter: 'my label'
}
}
},
// end point of the line
{
xAxis: 1509849000,
yAxis: 3,
symbol: 'none'
}
]
]
}
}]
Here's a fiddle I found: https://jsfiddle.net/381510688/hff93ska/
Note that ECharts really like to display markLines with arrow symbols in the end of it, hence my use of symbol: 'none' in above code, to have just the line drawn.

HighCharts: Bar columns don't reach x-Axis on drill up

I am struggling with a HighChart/HighStock problem. I have created a JSFiddle to explain my problem! When the user uses a drill down on one of the bar colums, the y-axis may shrink which causes the x-axis to get higher. This is no problem, but when the user goes back to the overview through a drill up, the previous x-axis length is implemented for the bar columns, while the x-axis gets lower. I can't find anything in the documentation to help my problem and I haven't found a similar problem.
The drilldown which I am using:
drilldown: {
drillUpButton: {
relativeTo: 'spacingBox',
position: {
y: 0,
x: 0
},
theme: {
fill: 'white',
'stroke-width': 1,
stroke: 'silver',
r: 0,
states: {
hover: {
fill: '#D2D2D2'
},
select: {
stroke: '#039',
fill: '#D2D2D2'
}
}
}
},
series: [{"data":......}]
}
Could someone please help me adjust the code so that on the drill-up event the bar columns are re-configured to reach the x-axis
It looks like it is a bug with drilldown animation which appears only when a navigator is enabled. Reported here.
Should work without the animation:
drilldown: {
animation: false,
example: http://jsfiddle.net/3e3xqv7e/47/
In general, I think a navigator was not meant to work with drilldowns, so making it work correctly might be tricky. An option series.showInLegend works, though, except the min/max of the navigator are changed after drillup - so you need to set it properly.
drillup: function (e) {
this.navigator.xAxis.setExtremes(0, 4, true, false);
/* this.navigator.xAxis.update({
min: 0,
max: 4
}, true);*/
}
example: http://jsfiddle.net/c1nqpz7d/2/

Highcharts Speedometer, dataLabel for mileage counter

There are several examples with the Speedometer in Highcharts.
Is there a way, to show an additional dataLabel only, without dial in the gauge?
It could show a trip recorder, mileage counter or day counter.
I tried additional series and dataLabels, but could not get it running.
http://jsfiddle.net/uqa0t3xw
series: [{
name: 'mileage counter',
data: [],
dataLabels: {
x: 0, y: 20,
format: '{y:.0f} km',
}
}]
If you want to have an additional data label by adding another series and hiding the dial you can do so by setting the color of the dial to "transparent" (JSFiddle):
series: [
// Our "hidden" series
{
name: 'mileage counter',
data: [0],
dataLabels: {
x: 0, y: 50,
format: '{y:.0f} km',
},
dial: {
backgroundColor: 'transparent'
}
},
// ... Other series
]
Also note how the y value has to be big enough to not overlap with the other data labels. If it overlaps it will be hidden, since gauge has allowOverlap: false by default. Alternatively you could set that to true, but overlapping might not be pretty.
It should be noted that this can also be solved by creating your own div and placing it in the correct spot or perhaps copying the data label from the first series and moving it slightly.

Categories

Resources