eCharts how to get xAxis data - javascript

I have some code with event on click in echart.js like this
mytempChart2.on('click', function (params)
//params.seriesName return aktif/non aktif
{window.open('' + encodeURIComponent(params.dataType) + '.html', '_self');
});
I read documentation echart on https://www.echartsjs.com/en/tutorial.html#Events%20and%20Actions%20in%20ECharts
but i dont find param to get xAxis data, xAxis data on my chart is date.
Look my picture i want to get this value (red circle)
My full code
// ==============================================================
// Line chart
// ==============================================================
var dom2 = document.getElementById("grafik2");
var mytempChart2 = echarts.init(dom2);
var app = {};
option2 = null;
option2 = {
tooltip : {
trigger: 'axis'
},
legend: {
data:['Non-Aktif', 'Aktif Kembali']
},
toolbox: {
show : true,
feature : {
magicType : {show: true, type: ['line', 'bar']},
restore : {show: true},
saveAsImage : {show: true}
}
},
color: ["#EF5350", "#2FBF2F"],
calculable : true,
xAxis : [
{
type : 'category',
boundaryGap : false,
data : [01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,],
}
],
yAxis : [
{
type : 'value',
axisLabel : {
formatter: '{value}'
}
}
],
series : [
{
name:'Non-Aktif',
type:'line',
data:[0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
markPoint : {
data : [
{name: 'tanggal', value: 100},
{type : 'max', name: 'Tertinggi'},
{type : 'min', name: 'Terendah'}
]
},
itemStyle: {
normal: {
lineStyle: {
shadowColor : 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetX: 8,
shadowOffsetY: 8
}
}
},
markLine : {
data : [
{type : 'average', name : 'Rata-rata'}
]
}
},
{
name:'Aktif Kembali',
type:'line',
data:[0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,],
markPoint : {
data : [
{type : 'max', name: 'Tertinggi'},
{type : 'min', name: 'Terendah'}
]
},
itemStyle: {
normal: {
lineStyle: {
shadowColor : 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetX: 8,
shadowOffsetY: 8
}
}
},
markLine : {
data : [
{type : 'average', name : 'Rata-rata'}
]
}
}
]
};
if (option2 && typeof option2 === "object") {
mytempChart2.setOption(option2, true), $(function() {
function resize() {
setTimeout(function() {
mytempChart2.resize()
}, 100)
}
$(window).on("resize", resize), $(".sidebartoggler").on("click", resize)
});
}
mytempChart2.setOption(option2);
mytempChart2.on('click', function (params)
//params.seriesName return aktif/non aktif
{window.open('' + encodeURIComponent(params.name) + '.html', '_self');
});

You can use the params object as specified by you. you need to access the name property which holds the value on x axis.
Please find the working code below:
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
option = {
xAxis: [{
type: 'category',
boundaryGap: false,
data: [01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ],
}],
yAxis: [{
type: 'value',
axisLabel: {
formatter: '{value}'
}
}],
series: [{
name: 'Non-Aktif',
type: 'line',
data: [0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
markPoint: {
data: [{
name: 'tanggal',
value: 100
},
{
type: 'max',
name: 'Tertinggi'
},
{
type: 'min',
name: 'Terendah'
}
]
},
itemStyle: {
normal: {
lineStyle: {
shadowColor: 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetX: 8,
shadowOffsetY: 8
}
}
},
markLine: {
data: [{
type: 'average',
name: 'Rata-rata'
}]
}
},
{
name: 'Aktif Kembali',
type: 'line',
data: [0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ],
markPoint: {
data: [{
type: 'max',
name: 'Tertinggi'
},
{
type: 'min',
name: 'Terendah'
}
]
},
itemStyle: {
normal: {
lineStyle: {
shadowColor: 'rgba(0,0,0,0.3)',
shadowBlur: 10,
shadowOffsetX: 8,
shadowOffsetY: 8
}
}
},
markLine: {
data: [{
type: 'average',
name: 'Rata-rata'
}]
}
}
]
}
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
myChart.on('click', function(params) {
console.log(params.name);
});
<div id="main" style="width: 600px;height:400px;"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.6.0/echarts.min.js"></script>

Related

How can I have common tooltip for a grid in Apache echart?

I have two line charts in a grid so that I can have common zooming. Now, I want to have tooltip such that when I hover on one chart, tooltip popups in other as well. So, I can see, how the values are in both charts at the specific x-axis value.
Below is my code,
let base = +new Date(1968, 9, 3);
let oneDay = 24 * 3600 * 1000;
let date = [];
let values1 = [Math.random() * 300];
let values2 = [Math.random() * 300];
for (let i = 1; i < 20000; i++) {
var now = new Date((base += oneDay));
date.push(i)
// date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));
values1.push(Math.round((Math.random() - 0.5) * 20 + values1[i - 1]));
values2.push(Math.round((Math.random() - 0.5) * 20 + values2[i - 1]));
}
option = {
// tooltip: {
// trigger: 'none',
// // position: function (pt) {
// // return [pt[0], '10%'];
// // }
// },
toolbox: {
feature: {
dataZoom: {
yAxisIndex: 'none'
},
restore: {},
saveAsImage: {}
}
},
grid: [
{
// left: '3%',
// right: '4%',
top: '50%',
containLabel: true,
// show: true
},
{
// left: '3%',
// right: '4%',
bottom: '50%',
containLabel: true,
// show: true
},
],
xAxis: [
{
type: 'category',
boundaryGap: false,
data: date,
gridIndex: 0,
},
{
type: 'category',
boundaryGap: false,
data: date,
gridIndex: 1,
},
],
yAxis: [
{
type: 'value',
boundaryGap: [0, '100%'],
gridIndex: 0,
},
{
type: 'value',
boundaryGap: [0, '100%'],
gridIndex: 1,
},
],
dataZoom: [
{
type: 'inside',
// start: 0,
// end: 10
xAxisIndex: [0, 1],
},
// {
// // start: 0,
// // end: 10
// xAxisIndex: [0, 1],
// }
],
series: [
{
name: 'Fake Data',
type: 'line',
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: 'rgb(255, 70, 131)'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgb(255, 158, 68)'
},
{
offset: 1,
color: 'rgb(255, 70, 131)'
}
])
},
data: values1,
gridIndex: 0,
xAxisIndex: 0,
yAxisIndex: 0,
},
{
name: 'Faker Data',
type: 'line',
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: 'rgb(255, 70, 131)'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgb(255, 158, 68)'
},
{
offset: 1,
color: 'rgb(255, 70, 131)'
}
])
},
data: values2,
gridIndex: 1,
xAxisIndex: 1,
yAxisIndex: 1,
}
]
};
The above code will render 2 charts with common zooming. I tried tooltip with item, axes and none but they didnt work.
How can I do this?
Thank you.
Solution 1
First, when using this kind of chart (with xAxis), it's recommanded to use trigger: "axis".
Then to connect the tooltip, what you actually want to do is to connect the axisPointer :
// add this to your chart option
axisPointer: {
link: [
{
xAxisIndex: 'all'
}
]
},
This being done, your 2 tooltips will be connected. But echart seems to struggle to display the tooltip on large dataset using xAxis.type = 'category' (20K points in your example). If you want to use big dataset with 'date' format on x, I recommand this :
Format you series like a list of [date, value]
Use xAxis.type = 'time'
Remove xAxis.data
Here is the full working code of your example.
Solution 2
Another solution would be to create 2 separate charts and to connect them (zoom, tooltip ...) using
echarts.connect([chart1, chart2]);
Here is what the code would look like with this method :
var myChart1 = echarts.init(document.getElementById('main1'));
var myChart2 = echarts.init(document.getElementById('main2'));
let base = +new Date(1968, 9, 3);
let oneDay = 24 * 3600 * 1000;
let date = [];
let values1 = [Math.random() * 300];
let values2 = [Math.random() * 300];
for (let i = 1; i < 200; i++) {
var now = new Date((base += oneDay));
date.push(i)
// date.push([now.getFullYear(), now.getMonth() + 1, now.getDate()].join('/'));
values1.push(Math.round((Math.random() - 0.5) * 20 + values1[i - 1]));
values2.push(Math.round((Math.random() - 0.5) * 20 + values2[i - 1]));
}
var option1 = {
tooltip: {
trigger: 'axis',
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: date
}
],
yAxis: [
{
type: 'value',
boundaryGap: [0, '100%'],
},
],
dataZoom: [
{
type: 'inside',
},
],
series: [
{
name: 'Fake Data',
type: 'line',
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: 'rgb(255, 70, 131)'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgb(255, 158, 68)'
},
{
offset: 1,
color: 'rgb(255, 70, 131)'
}
])
},
data: values1,
},
]
};
var option2 = {
tooltip: {
trigger: 'axis',
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: date
}
],
yAxis: [
{
type: 'value',
boundaryGap: [0, '100%'],
},
],
dataZoom: [
{
type: 'inside',
},
],
series: [
{
name: 'Faker Data',
type: 'line',
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: 'rgb(255, 70, 131)'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgb(255, 158, 68)'
},
{
offset: 1,
color: 'rgb(255, 70, 131)'
}
])
},
data: values2,
},
]
};
myChart1.setOption(option1)
myChart2.setOption(option2)
echarts.connect([myChart1, myChart2]);
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.2/echarts.min.js"></script>
<div id="main1" style="width: 600px; height:200px;"></div>
<div id="main2" style="width: 600px; height:200px;"></div>
</body>
</html>

Send value from index.php to apex chart .js file

The following is the "dashbaord.js" file in a admin dashboard script.
I want to transfer data from my index.php to display different Apex chart data
instead of the "series1", "series2" and the "categories" I want to send custom values. How can I do that ?
I can manage php, but I know nothing about javascript.
I tried to put <?php.. inside the .js file and it didnt work.
// currently sale
var options = {
series: [{
name: 'series1',
data: [6, 20, 15, 40, 18, 20, 18, 23, 18, 35, 30, 55, 0]
}, {
name: 'series2',
data: [2, 22, 35, 32, 40, 25, 50, 38, 42, 28, 20, 45, 0]
}],
chart: {
height: 240,
type: 'area',
toolbar: {
show: false
},
},
dataLabels: {
enabled: false
},
stroke: {
curve: 'smooth'
},
xaxis: {
type: 'category',
low: 0,
offsetX: 0,
offsetY: 0,
show: false,
categories: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", "Jan"],
labels: {
low: 0,
offsetX: 0,
show: false,
},
axisBorder: {
low: 0,
offsetX: 0,
show: false,
},
},
markers: {
strokeWidth: 3,
colors: "#ffffff",
strokeColors: [ CubaAdminConfig.primary , CubaAdminConfig.secondary ],
hover: {
size: 6,
}
},
yaxis: {
low: 0,
offsetX: 0,
offsetY: 0,
show: false,
labels: {
low: 0,
offsetX: 0,
show: false,
},
axisBorder: {
low: 0,
offsetX: 0,
show: false,
},
},
grid: {
show: false,
padding: {
left: 0,
right: 0,
bottom: -15,
top: -40
}
},
colors: [ CubaAdminConfig.primary , CubaAdminConfig.secondary ],
fill: {
type: 'gradient',
gradient: {
shadeIntensity: 1,
opacityFrom: 0.7,
opacityTo: 0.5,
stops: [0, 80, 100]
}
},
legend: {
show: false,
},
tooltip: {
x: {
format: 'MM'
},
},
};
var chart = new ApexCharts(document.querySelector("#chart-currently"), options);
chart.render();

Change order of polygons within a feature layer? (arcgis js 4.xx)

I have tried using the below in my initial query, and query right before drawing my polygons with class breaks.
query.orderByFields = ["Shape__Area DESC"];
However this did not seem to do anything. I have also tried using grid_value field as well.
Here is my relevant code in which I am querying and then doing the drawing... main problem is occasionally large polygons block out smaller ones.. I can mostly see them, but visibility is not the issue.. I need to be able to click them as well.. if the smaller polygons would draw on top most layer, or even higher grid values on top should solve it. I found orderByFields in the docs but doesn't seem to do anything at all...
query.outFields = ["*"];
//query.orderByFields = ["Shape__Area DESC"];
query.returnDistinctValues = false;
query.returnGeometry = true;
QT.execute(query).then(function (evt) {
evt.features.forEach(function (feature) {
var att = feature.attributes
var test = geometryEngine.convexHull(feature.geometry)
var genpoly = null
if (att.grid_value <= 4.0) {
var rad = att.Shape__Length / 75
genpoly = new Circle({
center: test.centroid,
radius: rad,
radiusUnit: "meters"
})
} else {
genpoly = test
}
var polygonGraphic = new Graphic({
geometry: genpoly,
attributes: att,
type: "polygon"
});
gras.push(polygonGraphic);
});
var renderer = {
type: "class-breaks",
field: "grid_value",
classificationMethod: "esriClassifyManual",
classBreakInfos: [{
minValue: 0,
maxValue: 1.9999,
symbol: {
color: [0, 0, 0, 0],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "I (Not Felt)"
},
{
minValue: 2.0,
maxValue: 3.0,
symbol: {
color: [191, 204, 255, .3],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "II (Weak)"
},
{
minValue: 3.1,
maxValue: 3.9,
symbol: {
color: [153, 153, 255, .4],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "III (Weak)"
},
{
minValue: 4.0,
maxValue: 4.5,
symbol: {
color: [136, 255, 255, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "IV (Light)"
},
{
minValue: 4.5,
maxValue: 4.9999,
symbol: {
color: [125, 248, 148, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "V (Light)"
},
{
minValue: 6.0,
maxValue: 6.9999,
symbol: {
color: [255, 255, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VI (Strong)"
},
{
minValue: 7.0,
maxValue: 7.9999,
symbol: {
color: [255, 221, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VII (Very Strong)"
},
{
minValue: 8.0,
maxValue: 8.9999,
symbol: {
color: [255, 145, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VIII (Severe) "
},
{
minValue: 9.0,
maxValue: 9.9999,
symbol: {
color: [255, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "IX (Violent)"
},
{
minValue: 10.0,
maxValue: 10.9999,
symbol: {
color: [221, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "X"
},
{
minValue: 11.0,
maxValue: 11.9999,
symbol: {
color: [136, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "XI"
},
{
minValue: 12.0,
maxValue: 12.0,
symbol: {
color: [68, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "XII"
}
]
}
var popupTrails = {
outFields: ["*"],
"title": "Shake ID: {id}",
"content": function (feature){
let name_plc;
let dlv = document.createElement("div");
dlv.className = "popd";
dlv.innerHTML = `<b><span class='name_plc'></span></b><br>ID: <span class="ida">${feature.graphic.attributes.id}</span><br> URL: View <br> Updated: ${feature.graphic.attributes.updated} <br>Grid_value: ${feature.graphic.attributes.grid_value}<br> Event Time: ${feature.graphic.attributes.eventTime} <style>.esri-popup__navigation { display: none;}</style>`;
getName();
function getName() {
let cId = $('span.ida').text();
if (cId) {
//console.log(cId);
let q3 = new Query();
q3.where = "id = '"+ cId +"'";
q3.outFields = ["*"];
QTt.execute(q3).then(function (results) {
results.features.map(function (feat) {
let pID = feat.attributes["id"];
if (cId === pID) {
name_plc = feat.attributes["place"];
console.log(name_plc);
let tx = $('.name_plc').text();
if (tx == 0){
$(".name_plc").append(name_plc);
}
}
});
});
} else {
setTimeout(getName, 230);
}
}
return dlv;
},
};
fl = new FeatureLayer({
source: gras,
objectIdField: "ObjectID",
geometryType: "polygon",
fields: [{
name: "ObjectID",
alias: "ObjectID",
type: "oid"
}, {
name: "id",
alias: "id",
type: "string"
}, {
name: "updated",
alias: "Last Update",
type: "string"
}, {
name: "eventTime",
alias: "eventTime",
type: "string"
}, {
name: "url",
alias: "url",
type: "string"
}, {
name: "grid_value",
alias: "grid_value",
type: "double"
}],
renderer: renderer,
popupEnabled: true,
//outFields: ['*'],
popupTemplate: popupTrails,
visibleElements: [{
featureNavigation: false,
}],
});
map.add(fl);
Here is my full CodePen as well.. Any way to do this client side javascript? simply change index to smallest polygons on top?! 1/3 times some of my polygons render in the correct order.. but I need to ensure they all always do, so they are visible and I can click them.
Update:
Here is a better screenshot: For instance, I try to click the green shape in the middle, the largest blue circle highlights and the popup only displays the meta for that one. Cannot click the smaller inner ones.
i.e. before click.
i.e. after trying to click the green inner small polygon -- only outer is accessible.
perhaps the issue is my order by clause needs to be handled within my filter?
eqLayerView.filter = {
outFields: "*",
orderByFields: "Shape__Area DESC",
where: "id IN (" + sqlExp + ")"
};
Take a look at this example, is base on your code, I just remove lot of things and keep the important ones to see that sort by area works. Like I told you, the layer plus the renderer did not help you to realize this. Just click and you will see each feature been selected.
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>OrderByFields - Render order</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/geometry/geometryEngine",
"esri/geometry/Circle",
"esri/Graphic",
"esri/symbols/SimpleFillSymbol",
"esri/tasks/QueryTask",
"esri/tasks/support/Query"
], function (
Map,
MapView,
FeatureLayer,
geometryEngine,
Circle,
Graphic,
SimpleFillSymbol,
QueryTask,
Query) {
var map = new Map({
basemap: "gray"
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-122, 37],
zoom: 2
});
let fl;
let gras = [];
let dVals = [];
const QT = new QueryTask({
url: "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1"
});
const query = new Query();
query.where = "eventTime >= CURRENT_TIMESTAMP - 30 AND updated >= CURRENT_TIMESTAMP - 30 AND grid_value > 2 AND id = 'us6000ah9t'";
query.outFields = ["*"];
query.orderByFields = ["Shape__Area DESC"];
query.returnDistinctValues = false;
query.returnGeometry = true;
QT.execute(query).then(function (evt) {
evt.features.forEach(function (feature) {
const att = feature.attributes
console.log(att.Shape__Area);
const test = geometryEngine.convexHull(feature.geometry)
let genpoly = null
if (att.grid_value <= 4.0) {
const rad = att.Shape__Length / 75
genpoly = new Circle({
center: test.centroid,
radius: rad,
radiusUnit: "meters"
})
} else {
genpoly = test
}
att.newArea = geometryEngine.geodesicArea(genpoly);
const polygonGraphic = new Graphic({
geometry: genpoly,
attributes: att,
type: "polygon"
});
gras.push(polygonGraphic);
});
fl = new FeatureLayer({
source: gras.sort((a, b) => {
if (a.attributes.newArea < b.attributes.newArea) {
return 1;
}
if (a.attributes.newArea > b.attributes.newArea) {
return -1;
}
return 0;
}),
objectIdField: "ObjectID",
geometryType: "polygon",
fields: [
{
name: "ObjectID",
alias: "ObjectID",
type: "oid"
}, {
name: "id",
alias: "id",
type: "string"
}, {
name: "grid_value",
alias: "grid_value",
type: "double"
}, {
name: "Shape__Area",
alias: "Original Area",
type: "double"
}, {
name: "newArea",
alias: "Process Area",
type: "double"
}
],
popupTemplate: {
title: "{id}",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "grid_value",
label: "Grid Value"
},
{
fieldName: "Shape__Area",
label: "Old Area"
},
{
fieldName: "newArea",
label: "Process Area"
}
]
}
]
},
renderer: {
type: "simple",
symbol: {
type: "simple-fill",
color: [255, 0, 0, 1],
outline: {
width: 1,
color: "black"
}
}
}
});
map.add(fl);
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
UPDATE:
After reviewing your update, I think I understand better the issue and I notice something that I miss before, featureNavigation: false. I am pretty sure that on click all features are selected, the problem is that the one you want is not the fist one to appear. In other words, you have a problem with the order in witch popup is showing clicked features.
So, I will propose you a simple solution, manually open the popup with the desire feature (in you case the one with less area). For this, you need to:
disable popup auto open
handle view click event
use view hittest method to get features
open popup with the desire feature
Take a look at this example I made for you, I add an extra condition to retrieve some features to make it faster
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>esriFieldTimeDate</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.15/esri/themes/light/main.css">
<script src="https://js.arcgis.com/4.15/"></script>
<script>
require([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
"esri/geometry/geometryEngine",
"esri/geometry/Circle",
"esri/Graphic",
"esri/symbols/SimpleFillSymbol",
"esri/tasks/QueryTask",
"esri/tasks/support/Query"
], function (
Map,
MapView,
FeatureLayer,
geometryEngine,
Circle,
Graphic,
SimpleFillSymbol,
QueryTask,
Query) {
var map = new Map({
basemap: "gray"
});
var view = new MapView({
container: "viewDiv",
map: map,
center: [-122, 37],
zoom: 2
});
let fl;
let gras = [];
const QT = new QueryTask({
url: "https://services9.arcgis.com/RHVPKKiFTONKtxq3/arcgis/rest/services/USGS_Seismic_Data_v1/FeatureServer/1"
});
function newAreaCompareFunction(a, b) {
if (a.attributes.newArea < b.attributes.newArea) {
return 1;
}
if (a.attributes.newArea > b.attributes.newArea) {
return -1;
}
return 0;
}
const simpleRenderer = {
type: "simple",
symbol: {
type: "simple-fill",
color: [255, 0, 0, 1],
outline: {
width: 1,
color: "black"
}
}
};
const docRenderer = {
type: "class-breaks",
field: "grid_value",
classificationMethod: "esriClassifyManual",
classBreakInfos: [{
minValue: 0,
maxValue: 1.9999,
symbol: {
color: [0, 0, 0, 0],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "I (Not Felt)"
},
{
minValue: 2.0,
maxValue: 3.0,
symbol: {
color: [191, 204, 255, .3],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "II (Weak)"
},
{
minValue: 3.1,
maxValue: 3.9,
symbol: {
color: [153, 153, 255, .4],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "III (Weak)"
},
{
minValue: 4.0,
maxValue: 4.5,
symbol: {
color: [136, 255, 255, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "IV (Light)"
},
{
minValue: 4.5,
maxValue: 4.9999,
symbol: {
color: [125, 248, 148, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "V (Light)"
},
{
minValue: 6.0,
maxValue: 6.9999,
symbol: {
color: [255, 255, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VI (Strong)"
},
{
minValue: 7.0,
maxValue: 7.9999,
symbol: {
color: [255, 221, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VII (Very Strong)"
},
{
minValue: 8.0,
maxValue: 8.9999,
symbol: {
color: [255, 145, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "VIII (Severe) "
},
{
minValue: 9.0,
maxValue: 9.9999,
symbol: {
color: [255, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "IX (Violent)"
},
{
minValue: 10.0,
maxValue: 10.9999,
symbol: {
color: [221, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "X"
},
{
minValue: 11.0,
maxValue: 11.9999,
symbol: {
color: [136, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "XI"
},
{
minValue: 12.0,
maxValue: 12.0,
symbol: {
color: [68, 0, 0, 1],
outline: {
color: [0, 0, 0, 0],
width: 0.4,
type: "simple-line",
style: "solid"
},
type: "simple-fill",
style: "solid"
},
label: "XII"
}
]
};
const query = new Query();
query.where = "eventTime >= CURRENT_TIMESTAMP - 30 AND updated >= CURRENT_TIMESTAMP - 30 AND grid_value > 2 AND id = 'us6000ah9t'";
query.outFields = ["*"];
query.orderByFields = ["Shape__Area DESC"];
query.returnDistinctValues = false;
query.returnGeometry = true;
QT.execute(query).then(function (evt) {
evt.features.forEach(function (feature) {
const att = feature.attributes
console.log(att.Shape__Area);
const test = geometryEngine.convexHull(feature.geometry)
let genpoly = null
if (att.grid_value <= 4.0) {
const rad = att.Shape__Length / 75
genpoly = new Circle({
center: test.centroid,
radius: rad,
radiusUnit: "meters"
})
} else {
genpoly = test
}
att.newArea = geometryEngine.geodesicArea(genpoly);
const polygonGraphic = new Graphic({
geometry: genpoly,
attributes: att,
type: "polygon"
});
gras.push(polygonGraphic);
});
fl = new FeatureLayer({
source: gras.sort(newAreaCompareFunction),
objectIdField: "ObjectID",
geometryType: "polygon",
fields: [
{
name: "ObjectID",
alias: "ObjectID",
type: "oid"
}, {
name: "id",
alias: "id",
type: "string"
}, {
name: "grid_value",
alias: "grid_value",
type: "double"
}, {
name: "Shape__Area",
alias: "Original Area",
type: "double"
}, {
name: "newArea",
alias: "Process Area",
type: "double"
}
],
popupTemplate: {
title: "{id}",
content: [
{
type: "fields",
fieldInfos: [
{
fieldName: "ObjectID",
label: "Object ID"
},
{
fieldName: "grid_value",
label: "Grid Value"
},
{
fieldName: "Shape__Area",
label: "Old Area"
},
{
fieldName: "newArea",
label: "Process Area"
}
]
}
]
},
renderer: docRenderer
});
map.add(fl);
view.goTo(
gras
.map(f => f.geometry.extent)
.reduce(
(p, c) => p ? p.union(c) : c
)
);
view.popup.autoOpenEnabled = false; // <- disable view popup auto open
view.on("click", function (event) { // <- listen to view click event
view.hitTest(event, { include: fl }) // <- retrieve features
.then(function (response) {
if (response.results.length) {
var feature = response.results // <- get desire feature
.map(result => result.graphic)
.reduce(
(p, c) =>
p ? (c.attributes.newArea < p.attributes.newArea ? c : p) : c
)
;
view.popup.open({ // <- open popup
location: event.mapPoint, // <- use map point of the click event
features: [feature] // <- add the desire feature
});
}
});
});
});
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>

Echarts: Plot the variance of signals

I want to plot the variance of multiple signals in a chart (or basically fillup the space between an upper and a lower signal).
Is it possible to create such kind of charts?
I saw the confidence-band example (https://echarts.apache.org/examples/en/editor.html?c=confidence-band) , however this seems to work only for one signal in a chart.
Another solution would be to draw thousands of small rectangles using markArea around the signals but this slows down the performance of the chart (e.g. when scrolling the x-axisis) and doesnt look very smooth.
As I know the common practice in Echarts community draw usual chart type (bar, line, ...) with series (read docs) and write visual logic by custom series for unique. Also Echarts has some API methods (undocumented) like registerVisual, registerLayout that can be used for redefine layouts, computation and so on.
For described task you need to use custom series for calculate bands coordinates. It's not very simple because (it seems to me) mandatory requirements with confidence band is rare.
About performance. Echarts by default use Canvas for render visual parts. Usually Canvas has no many parts in HTML for display chart, it's just imageData rendered by browser and it almost doesn't matter how many data point need to display. In other words, we see PNG, and not a lot of div, svg, g and others layers with geometric primitives as in SVG but heavy computation complex business logic may affect the responsiveness of UI as in other charts.
Below example how would I implement this feature. I'm not sure that's the right way but it work and can be tuned.
var dates = ['2020-01-03','2020-01-31','2020-02-17','2020-02-18','2020-03-13','2020-04-10','2020-05-01','2020-05-19','2020-05-22','2020-05-25'];
var sensor1 = [0.6482086334797242, 0.9121368038482911, 0.3205730196548609, 0.8712238348969002, 0.4487714576177558, 0.9895025457815625, 0.0415490306934774, 0.1592908349676395, 0.5356690594518069, 0.9949108727912939];
var sensor2 = [0.8278430459565170, 0.5700757488718124, 0.9803575576802187, 0.0770264671179814,0.2843735619252158,0.8140209568127250,0.6055633547296827,0.9554255125528607,0.1703504100638565,0.5653245914197297];
// Calculate fake bands coordinates
function calcContourCoords(seriesData, ctx){
var addNoise = idx => Math.round(Math.random() * 8 * idx);
var pixelCoords = seriesData.map((dataPoint, idx) => {
return [
ctx.convertToPixel({ xAxisIndex: 0 }, idx) + addNoise(idx),
ctx.convertToPixel({ yAxisIndex: 0 }, dataPoint) + addNoise(idx)
]
});
var polyfilltype = ClipperLib.PolyFillType.pftEvenOdd;
var linePath = new ClipperLib.Path();
var delta = 15;
var scale = 1;
for (var i = 0; i < pixelCoords.length; i++){
var point = new ClipperLib.IntPoint(...pixelCoords[i]);
linePath.push(point);
}
var co = new ClipperLib.ClipperOffset(1.0, 0.25);
co.AddPath(linePath, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etOpenSquare);
co.Execute(linePath, delta * scale);
return co.m_destPoly.map(c => [c.X, c.Y])
}
// Render visual by calculated coords
function renderItem(params, api){
// Prevent multiple call
if (params.context.rendered) return;
params.context.rendered = true;
// Get stored in series data for band
var series = myChart.getModel().getSeriesByName(params.seriesName)[0];
var seriesData = series.get('data');
// Calculate band coordinates for series
var bandCoords = calcContourCoords(seriesData, myChart);
// Draw band
return {
type: 'polygon',
shape: {
points: echarts.graphic.clipPointsByRect(bandCoords, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
})
},
style: api.style({
fill: series.option.itemStyle.color
})
};
}
// =============
var option = {
tooltip: {},
legend: {
data:['Label']
},
xAxis: [
{ name: 'x0', data: dates, boundaryGap: true },
{ name: 'x1', data: dates, boundaryGap: true, show: false },
],
yAxis: [
{ name: 'y0' },
{ name: 'y1', show: false },
],
series: [
// First line
{
name: 'Sensor1',
type: 'line',
data: sensor1,
itemStyle: { color: 'rgba(69, 170, 242, 1)' },
yAxisIndex: 0,
xAxisIndex: 0,
},
{
name: 'BandSensor1',
type: 'custom',
data: sensor1,
itemStyle: { color: 'rgba(69, 170, 242, 0.2)' },
renderItem: renderItem,
yAxisIndex: 0,
xAxisIndex: 0,
},
// Second line
{
name: 'Sensor2',
type: 'line',
data: sensor2,
itemStyle: { color: 'rgba(253, 151, 68, 1)' },
yAxisIndex: 1,
xAxisIndex: 1,
},
{
name: 'BandSensor2',
type: 'custom',
data: sensor2,
itemStyle: { color: 'rgba(253, 151, 68, 0.2)' },
renderItem: renderItem,
yAxisIndex: 1,
xAxisIndex: 1,
},
]
};
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(option);
<script src="https://cdn.jsdelivr.net/npm/clipper-lib#6.4.2/clipper.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/4.7.0/echarts.min.js"></script>
<div id="main" style="width: 800px;height:600px;"></div>
Improved version of #Sergey Fedorov- this solution takes into account min,max values or. dynamic border thicness of the band
var dates = ['2020-01-03', '2020-01-31', '2020-02-17', '2020-02-18', '2020-03-13', '2020-04-10', '2020-05-01', '2020-05-19', '2020-05-22', '2020-05-25', '2020-05-27'];
const data_raw1 = [
{ min: -5, mean: 0, max: 0 },
{ min: 1, mean: 2, max: 5 },
{ min: 2, mean: 4, max: 6 },
{ min: 4, mean: 5, max: 8 },
{ min: 7, mean: 11, max: 14 },
{ min: 11, mean: 15, max: 17 },
{ min: 6, mean: 8, max: 8.5 },
{ min: -1, mean: 5, max: 6 },
{ min: 4, mean: 9, max: 12 },
{ min: 14, mean: 18, max: 22 },
{ min: 18, mean: 20, max: 21 },
];
const data_raw2 = [
{ min: 10, mean: 15, max: 20 },
{ min: 12, mean: 25, max: 30 },
{ min: 22, mean: 26, max: 32 },
{ min: 30, mean: 31, max: 45 },
{ min: 47, mean: 49, max: 50 },
{ min: 30, mean: 32, max: 41 },
{ min: 34, mean: 36, max: 38 },
{ min: 40, mean: 42, max: 45 },
{ min: 47, mean: 49, max: 56 },
{ min: 60, mean: 68, max: 70 },
{ min: 75, mean: 80, max: 85 },
];
const data_raw3 = data_raw2.map(d => ({ min: d.min * 1.2 + 10, mean: d.mean * 1.4 + 11, max: d.max * 1.5 + 12 }))
function calcContourCoords(seriesData, ctx) {
console.log("seriesData=", seriesData);
const pixelCoords = []
for (let i = 0; i < seriesData.length; i++) {
console.log(i, seriesData[i]);
pixelCoords.push([
ctx.convertToPixel({ xAxisIndex: 0 }, i),
ctx.convertToPixel({ yAxisIndex: 0 }, seriesData[i].max)
]);
}
console.log("\n")
for (let i = seriesData.length - 1; i >= 0; i--) {
console.log(i, seriesData[i]);
pixelCoords.push([
ctx.convertToPixel({ xAxisIndex: 0 }, i),
ctx.convertToPixel({ yAxisIndex: 0 }, seriesData[i].min)
]);
if (i == 0) {
pixelCoords.push([
ctx.convertToPixel({ xAxisIndex: 0 }, i),
ctx.convertToPixel({ yAxisIndex: 0 }, seriesData[i].max)
]);
}
}
var linePath = new ClipperLib.Path();
var delta = 10;
var scale = 1;
for (var i = 0; i < pixelCoords.length; i++) {
var point = new ClipperLib.IntPoint(...pixelCoords[i]);
linePath.push(point);
}
var co = new ClipperLib.ClipperOffset(1.0, 0.25);
co.AddPath(linePath, ClipperLib.JoinType.jtRound, ClipperLib.EndType.etClosedPolygon);
co.Execute(linePath, delta * scale);
return co.m_destPoly.map(c => [c.X, c.Y])
}
// Render visual by calculated coords
function renderItem(params, api) {
// Prevent multiple call
if (params.context.rendered) return;
params.context.rendered = true;
// Get stored in series data for band
var series = myChart.getModel().getSeriesByName(params.seriesName)[0];
var seriesData = series.get('data');
// Calculate band coordinates for series
var bandCoords = calcContourCoords(seriesData, myChart);
// Draw band
return {
type: 'polygon',
shape: {
points: echarts.graphic.clipPointsByRect(bandCoords, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
})
},
style: api.style({
fill: series.option.itemStyle.color
})
};
}
// =============
var option = {
tooltip: {},
legend: {
data: ['Label']
},
xAxis: [
{ name: 'x0', data: dates, boundaryGap: true },
{ name: 'x1', data: dates, boundaryGap: true, show: false },
],
yAxis: [
{ name: 'y0' },
{ name: 'y1', show: false },
],
series: [
// First line
{
name: 'Sensor1',
type: 'line',
data: data_raw1.map(d => d.mean),
itemStyle: { color: 'rgba(69, 170, 242, 1)' },
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'red' },
},
{
name: 'BandSensor1',
type: 'custom',
data: data_raw1,
itemStyle: { color: 'rgba(69, 170, 242, 0.2)' },
renderItem: renderItem,
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'red', opacity: 0.1 },
},
{
name: 'Sensor2',
type: 'line',
data: data_raw2.map(d => d.mean),
itemStyle: { color: 'rgba(69, 170, 242, 1)' },
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'blue' },
},
{
name: 'BandSensor2',
type: 'custom',
data: data_raw2,
itemStyle: { color: 'rgba(69, 170, 242, 0.2)' },
renderItem: renderItem,
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'blue', opacity: 0.1 },
},
{
name: 'Sensor3',
type: 'line',
data: data_raw3.map(d => d.mean),
itemStyle: { color: 'rgba(69, 170, 242, 1)' },
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'green' },
},
{
name: 'BandSensor3',
type: 'custom',
data: data_raw3,
itemStyle: { color: 'rgba(69, 170, 242, 0.2)' },
renderItem: renderItem,
yAxisIndex: 0,
xAxisIndex: 0,
itemStyle: { color: 'green', opacity: 0.1 },
},
]
};
var myChart = echarts.init(document.getElementById('chart'));
myChart.setOption(option);

Remove extra chart area on Highcharts Gantt chart

When adding a large number of series to the example Gantt configuration (http://jsfiddle.net/r6emu) additional height is added to the top and bottom of the chart area. Is there any way to prevent the additional area/lines?
Example provided here:
http://jsfiddle.net/r6emu/1677/
// Define tasks
var tasks = [{
name: 'Sleep',
intervals: [{ // From-To pairs
from: Date.UTC(0, 0, 0, 0),
to: Date.UTC(0, 0, 0, 6)
}, {
from: Date.UTC(0, 0, 0, 22),
to: Date.UTC(0, 0, 0, 24)
}]
}, {
name: 'Family time',
intervals: [{ // From-To pairs
from: Date.UTC(0, 0, 0, 6),
to: Date.UTC(0, 0, 0, 16)
}, {
from: Date.UTC(0, 0, 0, 16),
to: Date.UTC(0, 0, 0, 22)
}]
}, {
name: 'Eat',
intervals: [{ // From-To pairs
from: Date.UTC(0, 0, 0, 7),
to: Date.UTC(0, 0, 0, 8),
label: 'Breakfast'
}, {
from: Date.UTC(0, 0, 0, 12),
to: Date.UTC(0, 0, 0, 12, 30)
}, {
from: Date.UTC(0, 0, 0, 16),
to: Date.UTC(0, 0, 0, 17),
label: 'Dinner'
}, {
from: Date.UTC(0, 0, 0, 20, 30),
to: Date.UTC(0, 0, 0, 21)
}]
},
[... many series removed ...]
{
name: 'Eat',
intervals: [{ // From-To pairs
from: Date.UTC(0, 0, 0, 7),
to: Date.UTC(0, 0, 0, 8),
label: 'Breakfast'
}, {
from: Date.UTC(0, 0, 0, 12),
to: Date.UTC(0, 0, 0, 12, 30)
}, {
from: Date.UTC(0, 0, 0, 16),
to: Date.UTC(0, 0, 0, 17),
label: 'Dinner'
}, {
from: Date.UTC(0, 0, 0, 20, 30),
to: Date.UTC(0, 0, 0, 21)
}]
}, {
name: 'Work',
intervals: [{ // From-To pairs
from: Date.UTC(0, 0, 0, 8),
to: Date.UTC(0, 0, 0, 16)
}]
}];
// Define milestones
var milestones = [{
name: 'Get to bed',
time: Date.UTC(0, 0, 0, 22),
task: 1,
marker: {
symbol: 'triangle',
lineWidth: 1,
lineColor: 'black',
radius: 8
}
}];
// re-structure the tasks into line seriesvar series = [];
var series = [];
$.each(tasks.reverse(), function(i, task) {
var item = {
name: task.name,
data: []
};
$.each(task.intervals, function(j, interval) {
item.data.push({
x: interval.from,
y: i,
label: interval.label,
from: interval.from,
to: interval.to
}, {
x: interval.to,
y: i,
from: interval.from,
to: interval.to
});
// add a null value between intervals
if (task.intervals[j + 1]) {
item.data.push(
[(interval.to + task.intervals[j + 1].from) / 2, null]
);
}
});
series.push(item);
});
// restructure the milestones
$.each(milestones, function(i, milestone) {
var item = Highcharts.extend(milestone, {
data: [[
milestone.time,
milestone.task
]],
type: 'scatter'
});
series.push(item);
});
console.log(series);
// create the chart
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
title: {
text: 'Daily activities'
},
xAxis: {
type: 'datetime'
},
yAxis: {
tickInterval: 1,
labels: {
formatter: function() {
if (tasks[this.value]) {
return tasks[this.value].name;
}
}
},
startOnTick: false,
endOnTick: false,
title: {
text: 'Activity'
},
minPadding: 0.2,
maxPadding: 0.2
},
legend: {
enabled: false
},
tooltip: {
formatter: function() {
return '<b>'+ tasks[this.y].name + '</b><br/>' +
Highcharts.dateFormat('%H:%M', this.point.options.from) +
' - ' + Highcharts.dateFormat('%H:%M', this.point.options.to);
}
},
plotOptions: {
line: {
lineWidth: 9,
marker: {
enabled: false
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function() {
return this.point.options && this.point.options.label;
}
}
}
},
series: series
});
It looks like you are forcing this area by having y axis padding and the lines by having a tick interval of 1.
yAxis: {
tickInterval: 1,
..
// minPadding: 0.2,
// maxPadding: 0.2
Going back to the default padding gives pretty good results, but the default of .01 may still be too much if your chart grows taller.

Categories