Here is a full jsfiddle example
I use a custom series and draw a polygon:
data = [
[80.9251933067, 207.9047427038],
[52.8853803102, 337.7443022089],
[25.9926385814, 120.3586150136]
];
I use echarts.graphi.clipPointsByRect() (like in this echarts-example) to make sure, the polygon is not drawn outside of the grid.
echarts.graphic.clipPointsByRect(points, {
x: params.coordSys.x,
y: params.coordSys.y,
width: params.coordSys.width,
height: params.coordSys.height
})
Initially the polygon is drawn correctly, like this:
But when I zoom in, the polygon is distorted: e.g. you can click the zoom part buttom below the chart to zoom from 40 to 60 - in this case I'd expect to see the part of the shape (like highlighted in yellow in the image above) - but instead I see this distorted image:
Maybe this function is not meant for this use-case, or is this a bug?
Is there another function for this use-case or does anyone know a workaround?
Update
Version 4.4.x contains a new clip feature. This makes it easy to avoid the distortion:
in the render function we don't need to clip our shapes: i.e. no need to call clipPointsByRect()
instead we just activate clip on the custom series:
New series definition with clip: 'true':
series: [{
type: 'custom',
clip: 'true',
renderItem: renderItem,
data: data
}]
Here is an updated jsfiddle expample
Original Version
it seems that the function is really not working as expected - see echarts-source code comment:
export function clipPointsByRect(points, rect) {
// FIXME: this way migth be incorrect when grpahic clipped by a corner.
// and when element have border.
I've created an issue #10222 for the e-charts project
A workaround for now is to use a custom clipping function
e.g. lineclip supports the Sutherland-Hodgman algorithm for polygon clipping
Here is the updated jsfiddle-example that shows the correct result when you zoom in:
Related
what is the best performing way to render a time cursor in an echarts graph?
The idea is to synchronize the vertical cursor shown on one graph with another graph on the same page. While the mouse moves over one graph a vertical line is drawn. Now I'd like to have a similar line being shown at the same time location on the other graph.
I'm currently do this by sending a message with a timestamp to the other graph and add a series to the config with a markline:
{
type: 'line',
animation: false,
markLine: {
symbol: 'none',
label: {
show: false
},
lineStyle: {
type: 'solid',
color: '#000',
opacity: 1
},
data: [
{ xAxis: 0 }
]
}
}
On receiving the timestamp, the graph updates data[0].xAxis and the chart is re-rendered. With many charts being connected, it still feels sluggish and I believe that the rendering of the graph with just changing the markline series is still too expensive.
There are a few merge options wrt. the config, but I can't find one, that updates just the markline series or better just moves a line.
I was also trying 'connect', but that was connecting too much (e.g. selection, tooltip, etc.) and even slower than my current method.
There might be another option to render the line with ZRender, but I have not gone that far yet.
Any suggestions?
Cheers,
klaus
We're building a new application using Leaflet as map displaying framework.
In our current application it's possible to supply the drawing order of specific 'parts' of a layer in relation to the parts of other layers.
Ex.
When the 'fill' of Layer2 is drawn over the 'fill' of Layer1, the 'outlines' of Layer1 can be drawn over the 'fill' of Layer2:
Desired
Normal
Can this be controlled in Leaflet, of do I have to add an extra layer to drawn the outlines of Layer1 over the the fill of Layer2.
EDIT
This is an example of what can be created using the demo code in the answer by 'Falke Design' - so this looks very promising:
EDIT 2
Basically the supplied answer uses two layers (not exactly what I wanted), but this code will be a good alternative.
You can also create a new layer with only borders on a new pane, that is always on top of the normal one:
// create a own pane, that is always on top of the normal drawn shapes
var bordersPane = map.createPane("borders");
bordersPane.style.zIndex = '405';
And then create, after drawing a layer, a new layer with only borders to the new pane:
// copy the latlngs of the drawn layer and create a new layer on the pane "borders" with only a storke
var layer = L.rectangle(e.layer.getLatLngs(),{pane: 'borders', fill: false, color: '#000', interactive: false}).addTo(map);
In the example I used Leaflet-Geoman for drawing:
// create a own pane, that is always on top of the normal drawn shapes
var bordersPane = map.createPane("borders");
bordersPane.style.zIndex = '405';
// add a stroke and a fill color to the drawing option
map.pm.enableDraw('Rectangle',{pathOptions: {fillOpacity: 1, stroke: true, color: '#000', fillColor: 'green'}})
// layer drawn / created event
map.on('pm:create',(e)=>{
// change the color of the drawn layer
e.layer.setStyle({fillColor: 'red'});
// copy the latlngs of the drawn layer and create a new layer on the pane "borders" with only a storke and is not editable or something (pmIgnore)
var layer = L.rectangle(e.layer.getLatLngs(),{pane: 'borders', fill: false, color: '#000', interactive: false, pmIgnore: true}).addTo(map);
// connect the two layers
layer.refLayer = e.layer;
e.layer.refLayer = layer;
// when the drawn layer is changed, change also the border layer
e.layer.on('pm:edit pm:update pm:drag pm:markerdrag',(e)=>{
e.layer.refLayer.setLatLngs(e.layer.getLatLngs())
})
})
https://jsfiddle.net/falkedesign/8owphr26/
The easiest way would be to reduce the opacity of the fill, then you see through it and see the borders:
L.rectangle(latlng,{fillOpacity: 0.5});
//or
layer.setStyle({fillOpacity: 0.5});
In the echarts docs at https://echarts.apache.org/en/option.html#dataZoom-slider.handleIcon the handle icon for data zoom slider has shape options like "circle", "rectangle" etc.
However these shapes doesn't seem to work.
If we specify dataZoom: [{ handleIcon: "circle" }] the handle icon just disappears.
Is the implementation for this API still pending or else?
You misinterpreted the documentation. The method handleIcon expects a string of path but not some shape identifier. Please take a look at the tests where you can found how to use this method.
However, you can define the icons outside of the chart configuration and use inside with identifier:
var icons = {
circle: 'M17.498,11.697c...',
square: 'M17.498,11.697c...'
}
var option = {
//...
dataZoom: [{ handleIcon: icons['circle'] }]
}
I want to show a single world map and wrap it around so that each area is shown only once on the screen. Please refer the fiddle http://jsfiddle.net/8m13d6vs/
var osmUrl = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
osm = L.tileLayer(osmUrl, {
noWrap: false,
attribution: "<a href='http://openstreetmap.org'>OpenStreetMap</a>"
});
var map = L.map('map').setView([0, 0], 1).addLayer(osm);
In the above fiddle, wrap is on, but the world map is duplicated. I want a single world map, and on left/right mouse drag, it should wrap around. It should be responsive to the area as well. Is there any way to achieve this? Hope my problem statement is understandable.
There's the Leaflet worldCopyJump option:
var map = L.map('map', {worldCopyJump: true}).setView([0, 0], 1).addLayer(osm);
It defaults to false, but setting this to true will copy the contents of the map over as the user pans beyond the map boundaries.
This sounds like a misunderstanding of the definition of "wrap":
In the context of Leaflet's Tile Layer / Grid Layer option noWrap, it says:
Whether the layer is wrapped around the antimeridian. If true, the GridLayer will only be displayed once at low zoom levels.
So it sounds like simply noWrap: true should achieve your objective.
Updated JSFiddle: http://jsfiddle.net/8m13d6vs/3/
BTW you should consider upgrading Leaflet version to 1+
I have two geoJson layers being loaded - both layers are the same data for testing purposes, but being drawn from two different json files. When I turn the layers on and off in the layer controller, the draw order of the layers change.
Any ideas why this is happening?
I have put my code into a JSFiddle: http://jsfiddle.net/lprashad/ph5y9/10/ and the JS is below:
//styling for watersheds_copy
var Orange = {
"color": "#ff7800",
"weight": 5,
"opacity": 0.65
};
var Water_Orange = L.geoJson(watersheds_copy, {
style: Orange
});
Water_Orange.addData(watersheds_copy);
//these are blue
var Water_blue = L.geoJson(watersheds, {});
Water_blue.addData(watersheds);
//This sets the inital order - last in layer list being on top. Except minimal - tile layer is always on bottom
var map = L.map('map', {
center: [41.609, -74.028],
zoom: 8,
layers: [minimal, Water_Orange, Water_blue]
});
var baseLayers = {
"Minimal": minimal,
"Night View": midnight
};
//This controls the order in the layer switcher. This does not change draw order
var overlays = {
"Water_Orange": Water_Orange,
"Water_blue": Water_blue
};
L.control.layers(baseLayers, overlays).addTo(map);
LP
While searching I happened upon this site that shows some of the Leaflet code:
http://ruby-doc.org/gems/docs/l/leaflet-js-0.7.0.3/lib/leaflet/src/control/Control_Layers_js.html
In it I found this condition for the application of autoZIndex:
if (this.options.autoZIndex && layer.setZIndex) {
this._lastZIndex++;
layer.setZIndex(this._lastZIndex);
}
TileLayer is the only layer type that has a setZIndex function, so apparently autoZIndex only works there.
I'm not sure which annoys me more. This incredible limitation or the fact that Leafet documentation doesn't point it out.
At least on 0.7.2, I had to use bringToFront in the callback of map.on('overlayadd'). autoZIndex: false did not work in my case neither. A comment on this issue may explain the reason.
It's not specific to L.GeoJson layers. As far as I can tell, it's true of all Leaflet layers with layer control. The last layer turned on is simply on top. I don't think this is a bug either. It's predictable behavior which I use and depend on when I'm designing maps with layer control...