bbecquet / leaflet.polylinedecorator Goto Github PK
View Code? Open in Web Editor NEWA plug-in for the JS map library Leaflet, allowing to define patterns (like dashes, arrows, icons, etc.) on Polylines.
License: MIT License
A plug-in for the JS map library Leaflet, allowing to define patterns (like dashes, arrows, icons, etc.) on Polylines.
License: MIT License
Hello,
My use case:
L.polylineDecorator(polyline, {
patterns: [
{
repeat: 200,
offset: 100,
endOffset: 20,
symbol: L.Symbol.arrowHead({
polygon: true,
pixelSize: 12,
pathOptions: {
fill: true,
fillColor: '#FFFFFF',
fillOpacity: 1,
stroke: true,
color: '#C51586',
opacity: 1,
weight: 3,
lineCap: 'square',
lineJoin: 'miter'
}
})
}
]
})
Hi
Is there a simple way within decorator to rotate the symbol 180 degrees so that they point in the correct direction for any relation 'roles' that are set to 'backward'? The only other way I can think of is to reverse the coordinates for those ways.
Thanks
At lower zoom levels, extremities of a small line segments can be projected to the same integer pixel points, with loss of precision. This can lead to inconsistent computations of symbol headings and positions.
Replace projection code to work with floating points pixels (using map.project()
instead of map.latLngToLayerPoint()
);
Should have done it a long time ago… Will be useful for non-regression and the myriad of edge cases.
Some things to test, not exhaustive:
Hi, using leaflet 1.1.0 with your example below gives:
Unable to get property 'getPixelLength' of undefined or null reference
// --- Example with an array of Polylines ---
var multiCoords1 = [
[[47.5468, -0.7910], [48.8068, -0.1318], [49.1242, 1.6699], [49.4966, 3.2958], [51.4266, 2.8564], [51.7542, 2.1093]],
[[48.0193, -2.8125], [46.3165, -2.8564], [44.9336, -1.0107], [44.5278, 1.5820], [44.8714, 3.7353], [45.8287, 5.1855], [48.1953, 5.1416]],
[[45.9205, 0.4394], [46.7699, 0.9228], [47.6061, 2.5488], [47.7540, 3.3837]]
];
var plArray = [];
for(var i=0; i<multiCoords1.length; i++) {
plArray.push(L.polyline(multiCoords1[i]).addTo(map));
}
L.polylineDecorator(multiCoords1, {
patterns: [
{offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}
]
}).addTo(map);
CSS Transform rules accessed through JavaScript are a real mess:
msTransform
, with a lower-case first letter as opposed to the other vendors.WebkitTransform
in addition to its OTransform
property, so the rotate rule is applied twice, resulting in a wrong angle.transform
property should be used as a priority, but in that case Firefox applies the rule twice, and Opera 3 times.I have used the PolylineDecorator with please for a while now, but has a need to try adding a text symbol (an icon) along the line. I have looked at the TextPath library that does not work with the new leaflet anymore. Has anyone gotten this to work, or has the ninja-skills to add it to the L.Symbol class?
Thanks for any assistance or hints!
Due to the way DXImageTransform works, the rotation shifts the center of the element.
See http://extremelysatisfactorytotalitarianism.com/blog/?p=1002 for detailed explanation and possible workaround.
Since updating from to 1.3.2, I have noticed that some of my paths cause an error like the following;
Error: Invalid LatLng object: (NaN, 148.20798060000007)
at LatLng (leaflet-src.js:1329)
at Object.unproject (leaflet-src.js:1624)
at Object.pointToLatLng (leaflet-src.js:1466)
at NewClass.unproject (leaflet-src.js:3842)
at leaflet.polylineDecorator.js:51
at Array.map (<anonymous>)
at projectPatternOnPath (leaflet.polylineDecorator.js:49)
at NewClass._getDirectionPoints (leaflet.polylineDecorator.js:430)
at leaflet.polylineDecorator.js:454
at Array.map (<anonymous>)
I am definitely not passing in any points that are NaN, so I believe it's something to do with the algorithm. Some paths are completely OK, whereas others are not.
One of the paths with the error is 8 points long, and all of the lat/lngs are the same position. Another path is 320 points long, and many different points. What is common between them, is that both of them have (at least) their first 2 points in the path exactly the same, which I think is the cause.
The error occurs for the very first point in the path, and I think the problem stems from inside the function projectPatternOnPointPath()
, in particular this line where segmentRatio
is calculated
https://github.com/bbecquet/Leaflet.PolylineDecorator/blob/master/src/patternUtils.js#L94
At that line, positionOffset
= some int, segment.distA
and segment.distB
are both equal to zero, so the line ends up dividing by zero, to get NaN, and then this NaN value is passed into interpolateBetweenPoints()
The algorithm is a little advanced for me so I don't think I can do a PR to fix it, but hopefully this is a good start
Here is one of my simpler paths that causes the error (they are all the same latlng point, so this might not be a good example to work with, let me know if you would like my 320 point path)
[
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806},
{lat: -21.9527438, lng: 148.2079806}
]
If I draw polylines on a map and use D3 .on("mouseover"... the tooltip does not appear. However, if I remove the polylines altogether, the tooltip works fine. This is only a problem in mobile devices. Desktop browsers work fine, and everything is displayed. Any help would be greatly appreciated.
When you include both measurecontrol.js with polylineDecorator(arrowhead) either one of the two stops working, depending on the order of their includes.
Apparently, even if the markers don't need to be redrawn on zoom changes, the rotation is applied once again, making the resulting transform wrong.
The problem occurs for transform-based rotations (IE9) and for filter-based rotations (IE<9), although the resulting aspect isn't the same.
This doesn't occur if the PolylineDecorator redraws the pattern on each zoom changes (the decorator's _isZoomDependant
property is true), for example when the pattern repeat is defined in pixels.
Hi,
Here's jsfiddle for reproducing issue:
http://jsfiddle.net/3rmk0nou/26/
Please skip 626 lines because it's copy-pasted Leaflet.PolylineDecorator
code (is there CDN link for this plugin anywhere?).
In current example, when zoom level is 17 and polyline is created using decorator (Click button to create), it takes ~20 seconds to create, and ~20 seconds to fitBounds on i5-3210M @ 2.50GHz
laptop. Polyline has only 10 vertexes.
If zoom level is 20, create time exceeds one minute. The more map is zoomed while creating decorated polyline, the slower it gets. On mobile device it can take multiple minutes. In user point of view, "it hangs" (though it does provide result after quite some time).
Starts in Leaflet 0.6, because it removes/doesn't need the duplicate first/last point on the path to close a Polygon. So, internally, the path lacks the last segment.
We should probably add it again explicitely in PolylineDecorator when working on instances of L.Polygon.
Hi, thank you for that great plugIn!
I´m triying to put in an Image for a LineString. The Example shows that with airplanes on a Line. I would like to put a picture on that lineString, so the picture replaces the geometry. I#m doing that on top of GeoJSON data. The goal is to have more styling you can´t have with Leaflets pathOptions.
In my example the svg wont take place on the LineString and the more you zoom out, the more they move away.
I'd love to see this available as a package on NPM.
Hello,
I want to change decoration on a polyline with the zoom.
if (map.getZoom() == 15) {
poly.setStyle({weight: 3});
L.polylineDecorator(poly,{setPatterns: [{offset: 25, repeat: 100, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {color:"red'",fillOpacity: 1, weight: 0}})}]}).addTo(map);
}
if (map.getZoom() == 14) {
poly.setStyle({weight: 3});
L.polylineDecorator(poly,{setPatterns: [{offset: 25, repeat: 100, symbol: L.Symbol.arrowHead({pixelSize: 5, pathOptions: {color:"blue'",fillOpacity: 1, weight: 0}})}]}).addTo(map);
}
But it doesn't change the decoration, it add a decoration above.
could you help me ?
thank you
Hi,
I know that Leaflet.PolylineDecorator accept only two types of layer:
I wonder if you already consider to support Geodesic type? I am currently trying to create a geodesic using this library Leaflet Geodesic and add a simple symbol in the middle of the line (custom icon or filled circle).
Thank you.
Hi
New to Leaflet, & indeed JS so please bear with me.
Using Overpass Turbo I've downloaded some data & converted it to geojson :
{
"type": "Feature",
"id": "way/2532",
"properties": {
"@id": "way/2532",
"cycleway": "opposite_lane",
"highway": "unclassified",
"name": "Westgate Street",
},
"geometry": {
"type": "LineString",
"coordinates": [
[
-2.3604021,
51.3815277
],
[
-2.3609347,
51.3814807
],
]
}
},
Putting Decorator inside an onEachFeature function I thought I'd be able to pass 'layer' to it.
This doesn't work:
onEachFeature: function onEachFeature(feature, layer) {
L.polylineDecorator(layer, {
patterns: [
{offset: 25, repeat: 30, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}
]
});
}
Any ideas how to perform this feature? Is it because geojson is Lng/Lat & decorator can only accept Lat/Lng? If so is there an easy way to swap them?
Any help would be appreciated.
Cheers
Dave F.
PS How do I add tags to this message such as 'bug' 'question' etc?
Hi!
Is there any possibility to add event handlers to the decorations of a feature? In my case a popup will open if you click on the feature. If you click on a decoration (in my case markers) nothing happens. For me it would be sufficient if the event just gets promoted to the decorated feature. I wouldn't mind if I needed to add additional event handlers to the decorations.
Thanks for a very useful little lib.
I regularly need to update my polylines with new coordinates. I do this by calling line.setLatLngs().
How would I update the associated decorators (in my case arrow heads) without creating new ones and throwing away the old ones?
I am using map box and leaflet for drawing polyline , But when draw the polyline some points to be draw incorrectly as per below latitude longitude :
[-33.3333333333333 -165.75,
-31.6166666666667 -169.6,
-29.9333333333333 -173.683333333333,
-28.4 -177.466666666667,
-26.3 178.466666666667,
-23.85 174.216666666667,
-21.4833333333333 170.366666666667,
-18.9833333333333 166.916666666667]
Please suggest some solution. Some issue related to grenwitch. How to draw correct polyline.
The offset at the moment is only for the start of the polyline. I had a need to provide an offset at the end as well.
My proposal is to add a new option "endoffset" with the same behaviour as offset, but for the end of the polyline.
Alternatively, "offset" could be renamed to "startoffset" and "offset" could instead be shorthand for setting startoffset and endoffset at the same time.
I already have worked around this in a local version of the code and happy to contribute back whichever style is preferred.
Hi I am using your PolylineDecorator and would like to get a clarification.
Usually libraries will provide a single, consolidated .js (or sometimes two - one minified and one with whitespace and comments for debugging) for distribution, and separate files for developing the library further. So I tried just using the leaflet.polylineDecorator.js but came to conclusion, that I need to download all sources files.
Looking at https://github.com/bbecquet/Leaflet.PolylineDecorator, it is not clear to me what https://github.com/bbecquet/Leaflet.PolylineDecorator/blob/master/leaflet.polylineDecorator.js is supposed to do. The example project that you provide uses the src files instead.
Thank you,
Olga
Like markers, polylines and polygons. At least by default.
For most usage they don't need to be active, and hopefully it will help making the library less of a performance hog.
Hi, I was wondering if there is currently a feature that would allow the size of (in my case arrowheads) to be fixed on the map? I'm drawing over an other polyline and would like to fit them inside. independent of zoom level.
From what I was able to create so far with this plugin, great job!
Work very very slow :(
Could you make it possible to change the pixelSize value in CSS?
It´s possible to change the pathOptions in CSS by assigning a className, but this won´t works for the "options" with pixelSize.
var arrowHead = L.polylineDecorator(arrow, {
patterns: [
{offset: '10%', repeat: '25%', symbol: L.Symbol.arrowHead({headAngle: 45, polygon: true, pixelSize: 7, pathOptions: {className: 'pfeil'}})}, ...
Is there an example on how we may create our own user defined symbols (to be used with L.Symbol)? Also, where can I find the list of predefined symbols in PolylineDecorator? Currently, I wished to have a double line. We have tried using small image of two lines repeated and that works great. But we have would like to be able to change the color. Creating multiple images(different colors) would not efficient or a configurable option. Using a user defined svg pattern would also help. We would be able to set the colors on the page.
I've tried specifying a color in the pathoptions and elsewhere but no luck. im looking to make a polyline the same width as the symbol so the arrow head fits nicely inside the line but with a different color.
thanks
I'd like to draw rotated SVG markers as line decorators. With default iconAnchor in the middle of the marker everything is fine, however using custom iconAnchor to make markers not to overlap line end doesn't behave as intended.
See demo: https://jsfiddle.net/zakjan/rtkg3snf/
Is it possible?
Will make the definition of dot patterns more explicit than declaring 0-length dashes.
Inherit L.Symbol.Dash if possible.
Just wondering what the rationale is for dropping MultiPolyline support here fcabc1e.
Is it deprecated in leaflet? I couldn't find any reference to that.
Would it be possible to backport bower.json from master to a 0.7.x release? My build script fails to include the correct file from this project without it :(
The effect can be achieved quite easily with CSS3 transform rotate() on the DOM node of a marker, taking the heading as angle.
The challenge is to access the DOM node created by L.Marker, as it is a private property of the class.
Hi, we are testing this great plugin, but we are having problems managing multipolygons, it just dont work,
will multipolygon support exist? any idea? thanks!! love the plugin!
I tried to use the leaflet polyline decorator with leaflet 1.0 beta, but I ran into a problem. When I set rotate: true, the markers are not on the polylines, but when I use the leaflet 0.7.3, the markers are on the polylines. (See the two pictures (first: 0.7.3, second: 1.0 beta))
I use the same code, the difference is the version of leaflet.
var map = L.map('map').setView([52, -11.0], 5);
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
var markerLine = L.polyline([[58.44773, -28.65234], [52.9354, -23.33496], [53.01478, -14.32617], [58.1707, -10.37109], [59.68993, -0.65918]], {}).addTo(map);
var pathPattern = L.polylineDecorator(markerLine,{
patterns: [
{ offset: '10px', repeat: '100px', symbol: L.Symbol.marker({rotate: true, markerOptions: {
icon: L.icon({
iconUrl: 'images/marker-icon.png',
iconSize: [11, 17]
})
}})}
]
}).addTo(map);
Error is "this._map is undefined".
Check before trying to (re-)draw if the decorator is attached to a map.
When you have a short line between two points e.g source: 51.51462, -0.12377 , target: 51.5133, -0.12207 and use an repeat of 50% the plugin gives an error "TypeError b is null"
When I try to remove a layer which contains a decorator from the map, I get the following in my console:
Uncaught TypeError: Object [object Object] has no method 'off' leaflet.js?body=1:8
o.FeatureGroup.o.LayerGroup.extend.removeLayer leaflet.js?body=1:8
removeTrack track.js?body=1:85
(anonymous function) track.js?body=1:75
jQuery.event.dispatch jquery.js?body=1:5096
elemData.handle
Hi,
I have been using your great plugin but i can't seem to find a way to put popups on the symbols. Do you know of a way to do this?
In the leaflet-0.7.2 branch, the main leaflet.polylineDecorator.js file has an extra (UTF?) character that isn't visible when browsing the source in github, but if you save out the raw source and try to execute the javascript, it fails with an error about the extra character:
L.rotatedMarker = function (pos, options) {
return new L.RotatedMarker(pos, options);
};/**
^^^ extra characters after the semi-colon and before the comment
* Defines several classes of symbol factories,
* to be used with L.PolylineDecorator
i.e. they can be too long and don't follow the polyline angles.
Sorry but I'm new. There is a way to put a static arrow into a polyline that I have?
I tried in this mode but doesn't work.
var pathPattern = L.polylineDecorator([ [Lat], [ Long ]],
{patterns: [{ offset: 12, repeat: 25, symbol: L.Symbol.arrow({pixelSize: 10, pathOptions: {color: '#f0000', weight: 2}}) },{ offset: 0, repeat: 25, symbol: L.Symbol.arrow({pixelSize: 0}) }]}
).addTo(map);
Thanks Giuseppe
Hi, thx for your hard work. I'm really happy to have found this plugin.
Is it possible to build a polyline decorator based on a polyline (built with certain offset through Leaflet.PolylineOffset) that has not been added to the map at that point
I'm going to put part of my code to illustrate what I'm trying to do.
The result for the following code if that arrows are applied to the original polyline instead of the polyline with the offset. Is there a reason for that behaviour?
var L = require('leaflet');
require('leaflet-polyline_offset');
require('leaflet-polyline_decorator');
//
// versions
// leaflet 0.7.7
// leaflet-polylinedecorator 1.1.0
// leaflet-polylineoffset 1.0.0
//
function buildLayer (latLngs, styles) {
var groupLayer = L.featureGroup();
var polyline = L.polyline(latLngs, styles);
// this polyline works like an invisible path so arrows be drawn over it, instead of the original path
// so, opacity = 1 is only for testing purposes
var offsetPolyline = L.polyline(latLngs, {opacity: 1, color: '#000000', weight: 1, offset:10});
var decorator = L.polylineDecorator(offsetPolyline, {
patterns: [
{offset: 0, repeat: 200, symbol: L.Symbol.arrowHead({polygon: false,
pixelSize: 10,
pathOptions: {opacity: 1, weight: 2, stroke: true, color:'#000000'}
})}
]
});
groupLayer.addLayer(polyline);
groupLayer.addLayer(offsetPolyline);
groupLayer.addLayer(decorator);
return groupLayer;
}
....
// later on .. the buildLayer's result is added to the map
map.addLayer(buildLayer);
Obviously, it's pretty silly to give the polyline decorator < 2 points, but rather than just gracefully not doing anything when given this, it errors and leaflet crashes
Pretty small issue because I can just put a check in my js to ensure this never happens, but I believe when a standard polyline is given < 2 points it doesn't crash, so perhaps the same should occur with this addon?
The error I get is something like
TypeError: Cannot read property 'predecessor' of null at Object.projectPatternOnPointPath (vendor-4da3fd3….js:5579)
at Object.projectPatternOnPath (vendor-4da3fd3….js:5575)
at n._getDirectionPoints (vendor-4da3fd3….js:5565)
at n._drawPattern (vendor-4da3fd3….js:5566)
at n._draw (vendor-4da3fd3….js:5567)
at n.onAdd (vendor-4da3fd3….js:5560)
at n._layerAdd (vendor-4da3fd3….js:5207)
at n.whenReady (vendor-4da3fd3….js:5118)
at n.addLayer (vendor-4da3fd3….js:5209)
at n.addLayer (vendor-4da3fd3….js:5219)
Specifically, the error occurs here;
previous
gets set to interpolateOnPointPath
which returns null when given < 2 points. And then later previous.predecessor
is attempted to be accessed, causing the error
Thoughts?
Hello,
is it possible to change color of the symbol ?
I need to display polyline with direction arrows and I want to set the same color for arrows symbols like lines.
Here is my code:
var decoration = new L.polylineDecorator(polyline, {
patterns: [{offset: 25, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 10, pathOptions: {fillOpacity: 1, weight: 0}})}]
});
m_TrailLayer.addLayer(decoration);
Dusan
Please, add support for this plugin - Leaflet.MultiOptionsPolyline (https://github.com/hgoebl/Leaflet.MultiOptionsPolyline)
problem:
No arrows on track and no errors if use both plugins
Leaflet 1.0 is breaking your plugin, are there any plans to upgrade?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.