How to link zoom in different charts in echarts - echarts

We have multiple charts with zoom. Is there a way to link all this charts so they always have the same zoom factor when the user zoom in one of the charts?

When having multiple grids in the same chart is not a possibility, I use this trick to do the job:
myChart.on('datazoom', function (evt) {
var zoom = myChart.getOption().dataZoom[0];
myOtherChart.dispatchAction({
type: 'dataZoom',
dataZoomIndex: 0,
startValue: zoom.startValue,
endValue: zoom.endValue
});
});
Both charts have dataZoom, in my case I hide the one in myOtherChart.

If you've got more events to track, creating the action can be simplified by letting echarts create it:
["datazoom", "legendselectchanged", /* more events*/].forEach((eventType: string) => {
this.chartInstance1.on(eventType, (event) => {
// Automatically create an action from the event
let newEvent = this.chartInstance1.makeActionFromEvent(event);
// Dispatch it directly
this.chartInstance2.dispatchAction(newEvent);
});
})
For everyone who wants to go further, also synchronizing mouse, legend and magic events, its easier to use the connect function.
Template:
// chart 1
<div echarts (chartInit)="onChartInit($event)"></div>
// chart 2
<div echarts (chartInit)="onChartInit($event)"></div>
Typescript:
import { connect, ECharts } from "echarts";
// ...
onChartInit(chart: ECharts) {
this.charts.push(chart);
if (this.charts.length === 2)
// This will do the magic out of the box
connect([charts[0], charts[1]]);
}

Related

Trigger event on multiple features when hovering over any of those in leaflet

I have a layer with two polylines and polylineDecorators. I would like to highlight both polylines and polylineDecorators when I hover on any of these. Right now I'm able to highlight only one at the time when hovering on it.
Here is my code:
var layer_migration = L.layerGroup({
layerName: 'layer_migration',
pane: 'linesPane',
});
function onEachFeature_migration (feature, layer) {
var polyline = L.polyline(layer.getLatLngs(),{
color: "#8B0000",weight: 5,opacity: 0.4,dashArray: '8,8',
dashOffset: 0
}).addTo(layer_migration);
var PLdecorator1 = L.polylineDecorator(polyline, {
patterns: [{
offset: '104%',
repeat: 100,
symbol: L.Symbol.arrowHead({pixelSize: 16,
pathOptions: {color: "#8B0000",fillOpacity: 0.6,weight: 0
}
})
}]
}).addTo(layer_migration)
var myfeatures = L.featureGroup([polyline,PLdecorator1]).addTo(layer_migration);
myfeatures.on('mouseover', function(e) {
var layer = e.target;
layer.setStyle({color: '#8B0000',opacity: 1,fillOpacity:1
});
});
}
Any help super appreciated.
Thanks,
P
In your mouseover callback, I think that e.target will just refer to the individual layer (polyline or decorator) that triggered the event, not the collection of layers that make up the feature group. I've not tested it, but according to the docs, you ought to be able to get the effect you want by calling .setLayer() on the feature group itself:
myfeatures.on('mouseover', function(e) {
myfeatures.setStyle({color: '#8B0000',opacity: 1,fillOpacity:1});
});
Also, if the two polylines are created by two separate calls to onEachFeature_migration(), then they will end up as two separate feature groups. To get around this, you might need to assign an empty featureGroup to myfeatures outside the function, then add the new polylines to it inside the function using myfeatures.addLayer().

Highchart Gantt chart Navigator color

I am rendering a Gantt chart with different series color. The colors are somehow not reflected on the navigator at the bottom. How can I display the same colors in both series and navigator?
Fiddle link : Fiddle
Note: These colors are going to be dynamic which will be based on different cases. So I want them to reflect in the navigator too, dynamically.
I am changing color of the series like so :
chart: {
events: {
load: function() {
Highcharts.each(this.series[0].points, function(p) {
p.color = 'grey'
});
}
}
},
As you can see series color is grey but in the navigator below, I see different colors.
As per highcharts-gantt documentation:
Update the series with a new set of options. For a clean and precise handling of new options, all methods and elements from the series are removed, and it is initialized from scratch.
On event, you should then go through given serie points and change its options (in your case 'color').
The changes will be applied in the timeline below - example code changes the color after 1,5sec.
//Updating the color
setTimeout(function() {
for (var i = 0; i < chart.series[0].points.length; i++) {
chart.series[0].points[i].update({
color: "grey"
});
}
}, 1500);
Working example
In your code it would be:
events: {
load: function() {
Highcharts.each(this.series[0].points, function(p) {
p.update({color: "grey"});
});
}
}
To avoid shrink of timeline - launch setExtremes() after chart update.
Fires when the minimum and maximum is set for the axis, either by calling the .setExtremes() method or by selecting an area in the chart.
//Fully selected timeline
this.xAxis[0].setExtremes();
Working example - timeline selection
You can also set options for series of navigator, like below:
navigator: {
series: {
...,
colorByPoint: false,
color: 'grey'
},
...
}
Live demo: https://jsfiddle.net/BlackLabel/c4j9dvqx/
API Reference: https://api.highcharts.com/gantt/navigator.series.color

Change leafletLayers after a dragend event

I need to delete all the leafletLayers and add others after a 'dragend' event. So, i proceeded as below :
mapParent.component
template: '<app-map [leafLetmarkers]="markers" (refreshMap)="refresh($event)"></app-map>'
...
markers: L.Layer[] = [];
refresh(position) {
//delete all markers
var markers = [];
//set the new markers
this.markers= newMarkers;
}
map.component
template: '<div leaflet style="height: 100%;"
[leafletOptions]="options"
[leafletLayers]="markers"
(leafletMapReady)="onMapReady($event)">
</div>'
...
#Input('leafLetmarkers') markers: L.Layer[];
#Output() refreshData = new EventEmitter<L.LatLng>();
onMapReady(map: L.Map) {
map.on('dragend', e => this.refreshMap.emit(map.getCenter()));
}
Is this the right way to do this ?
Regards.
Your general approach is correct.
The issue you might run into is that you are changing a bound property this.markers inside of a callback from Leaflet. Leaflet callbacks are outside of the Angular zone (Angular doesn't try to track changes outside of its zone). This is a design choice on the part of ngx-leaflet to prevent excessive change detection that might impact application performance.
The solution is to manually trigger change detection:
fitBounds: any = null;
circle = circle([ 46.95, -122 ], { radius: 5000 });
// Inject the Change Detector into your component
constructor(private changeDetector: ChangeDetectorRef) {}
ngOnInit() {
// The 'add' event callback happens outside of the Angular zone
this.circle.on('add', () => {
// Because we're outside of Angular's zone, this change won't be detected
this.fitBounds = this.circle.getBounds();
// But, it will if we tell Angular to detect changes
this.changeDetector.detectChanges();
});
}
For more details, you can see this section of the ngx-leaflet README:
https://github.com/Asymmetrik/ngx-leaflet#a-note-about-change-detection

Leaflet: Removing markers from map

I load some lat / lon info, then use it to build a polyline.
I then want to add a marker at each of the polyline vertices that will show when the polyline is clicked.
The vertices should disappear if a different (or the same) polyline is clicked.
The code below creates the polyline and the vertex markers.
But the vertex markers do not ever disappear.
I've tried to do this several ways with the same result. I've tried storing the vertex markers in an array and adding them directly to the map, then map.removeLayer'ing them. That doesn't work either. Nor does it work if I use an L.featureGroup instead of a layerGroup.
Clearly I've missed the point somewhere as to how markers can be removed. Could someone point me at the error in my methodology?
// trackMarkersVisible is a global L.layerGroup
// success is a callback from an ajax that fetches trackData, an array f lat/lon pairs
success: function (trackData) {
// build an array of latLng's
points = buildTrackPointSet(trackData, marker.deviceID);
var newTrack = L.polyline(
points, {
color: colors[colorIndex],
weight: 6,
clickable: true
}
);
$(newTrack).on("click", function () {
trackMarkersVisible.clearLayers();
$.each(points, function(idx, val) {
var tm = new L.Marker(val);
trackMarkersVisible.addLayer(tm);
});
map.addLayer(trackMarkersVisible);
});
}
Without a JSFiddle or Plunker it's hard to say because i'm not sure what behaviour your getting but using the clearLayers() method of L.LayerGroup should remove all layers from that group. I would check in the onclick handler if the group already has layers: group.getLayers().length === 0 If the group is empty, add the markers, if the group has layers use clearLayers. Example in code:
polyline.on('click', function (e) {
if (group.getLayers().length === 0) {
e.target._latlngs.forEach(function (latlng) {
group.addLayer(L.marker(latlng));
});
} else {
group.clearLayers();
}
});
This works for me, see the example on Plunker: http://plnkr.co/edit/7IPHrO?p=preview
FYI: an instance of L.Polyline is always clickable by default so you can leave out the clickable: true

Bind event to right-click

How do I bind to or recognize a right-click event?
I have a scatter plot where left-click adds a point at the clicked location; I would like right-click to remove the point (if present).
This is my current code:
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
events: {
click: function(event) {
var cs = [Math.floor(event.xAxis[0].value),
Math.floor(event.yAxis[0].value)];
this.series[0].addPoint(cs);
}
},
type: 'scatter',
},
... etc. ...
});
This should help:Making Highcharts support right click context menu
This is not a full solution: I did not figure out how to capture right-click events.
But here's a workaround for clicking on the chart background:
have the user do a shift-click
supply a callback as before
in the callback, inspect the event. If shift was pressed, do something different
Here's what the callback might look like:
function clickChart(event) {
var isShiftPressed = event.shiftKey;
if(isShiftPressed) {
// do something
} else {
// do something different
}
The event object has boolean attributes shiftKey (and altKey).
Here's a workaround for removing points: (actually, it's not a workaround -- I just didn't realize there was an easier way!)
points have their own events
just set up a callback that removes points when they're clicked
Example:
function clickPoint(event) {
this.remove();
}
var chart = new Highcharts.Chart({
chart: {
type: 'scatter',
renderTo: 'chart',
},
series: [{
point: {
events: {
click: clickPoint
}
}
}]
});
Note: the documentation is misleading, at the least, but the jsfiddle examples seem to be correct. It seems to show that the point options are not in series.
Currently, there are only a few events supported by Highcharts.
for ref : https://www.highcharts.com/blog/tutorials/introduction-to-highcharts-events/
To add custom events, such as
double click (including mobile devices)
right click (context menu)
mouse over
mouse out
mouse down
mouse move
we can add a plugin
highcharts-custom-events
https://www.npmjs.com/package/highcharts-custom-events
hope you find this helpful and solves your problem.