Socket
Socket
Sign inDemoInstall

leaflet-polylinedecorator

Package Overview
Dependencies
1
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.3.0 to 1.3.2

example/big_polyline_geojson.js

2

bower.json
{
"name": "leaflet-polylinedecorator",
"main": "leaflet.polylineDecorator.js",
"version": "1.3.0",
"version": "1.3.2",
"authors": [

@@ -6,0 +6,0 @@ "Benjamin Becquet"

@@ -7,142 +7,117 @@ (function (global, factory) {

function computeAngle(a, b) {
var computeSegmentHeading = function computeSegmentHeading(a, b) {
return Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI + 90;
}
};
function getPointPathPixelLength(pts) {
var getPointPathPixelLength = function getPointPathPixelLength(pts) {
return pts.reduce(function (distance, pt, i) {
return i === 0 ? 0 : distance + pt.distanceTo(pts[i - 1]);
}, 0);
}
};
function getPixelLength(pl, map) {
var latLngs = pl instanceof L.Polyline ? pl.getLatLngs() : pl;
var points = latLngs.map(function (latLng) {
return map.project(latLng);
});
return getPointPathPixelLength(points);
var asRatioToPathLength = function asRatioToPathLength(_ref, totalPathLength) {
var value = _ref.value,
isInPixels = _ref.isInPixels;
return isInPixels ? value / totalPathLength : value;
};
function parseRelativeOrAbsoluteValue(value) {
if (typeof value === 'string' && value.indexOf('%') !== -1) {
return {
value: parseFloat(value) / 100,
isInPixels: false
};
}
var parsedValue = value ? parseFloat(value) : 0;
return {
value: parsedValue,
isInPixels: parsedValue > 0
};
}
/**
* path: array of L.LatLng
* ratios is an object with the following fields:
* offset: the ratio of the total pixel length where the pattern will start
* endOffset: the ratio of the total pixel length where the pattern will end
* repeat: the ratio of the total pixel length between two points of the pattern
* map: the map, to access the current projection state
*/
function projectPatternOnPath(path, ratios, map) {
var pathAsPoints = path.map(function (latLng) {
function projectPatternOnPath(latLngs, pattern, map) {
var pathAsPoints = latLngs.map(function (latLng) {
return map.project(latLng);
});
var pathPixelLength = getPointPathPixelLength(pathAsPoints);
// project the pattern as pixel points
var pattern = projectPatternOnPointPath(pathAsPoints, ratios);
// and convert it to latlngs;
pattern.forEach(function (point) {
point.latLng = map.unproject(point.pt);
var ratios = {
offset: asRatioToPathLength(pattern.offset, pathPixelLength),
endOffset: asRatioToPathLength(pattern.endOffset, pathPixelLength),
repeat: asRatioToPathLength(pattern.repeat, pathPixelLength)
};
return projectPatternOnPointPath(pathAsPoints, ratios).map(function (point) {
return {
latLng: map.unproject(point.pt),
heading: point.heading
};
});
}
return pattern;
function pointsToSegments(pts) {
var segments = [];
var a = void 0,
b = void 0,
distA = 0,
distAB = void 0;
for (var i = 1, l = pts.length; i < l; i++) {
a = pts[i - 1];
b = pts[i];
distAB = a.distanceTo(b);
segments.push({
a: a,
b: b,
distA: distA, // distances from the start of the polyline
distB: distA + distAB,
heading: computeSegmentHeading(a, b)
});
distA += distAB;
}
return segments;
}
function projectPatternOnPointPath(pts, _ref) {
var offset = _ref.offset,
endOffset = _ref.endOffset,
repeat = _ref.repeat;
function projectPatternOnPointPath(pts, _ref2) {
var offset = _ref2.offset,
endOffset = _ref2.endOffset,
repeat = _ref2.repeat;
var positions = [];
// 1. compute the absolute interval length in pixels
var repeatIntervalLength = getPointPathPixelLength(pts) * repeat;
// 2. find the starting point by using the offset and find the last pixel using endOffset
var previous = interpolateOnPointPath(pts, offset);
var endOffsetPixels = endOffset > 0 ? getPointPathPixelLength(pts) * endOffset : 0;
// 1. split the path as segment infos
var segments = pointsToSegments(pts);
var nbSegments = segments.length;
positions.push(previous);
if (repeat > 0) {
// 3. consider only the rest of the path, starting at the previous point
var remainingPath = pts;
remainingPath = remainingPath.slice(previous.predecessor);
if (nbSegments === 0) {
return [];
}
remainingPath[0] = previous.pt;
var remainingLength = getPointPathPixelLength(remainingPath);
var totalPathLength = segments[nbSegments - 1].distB;
var repeatIntervalPixels = totalPathLength * repeat;
var startOffsetPixels = offset > 0 ? totalPathLength * offset : 0;
var endOffsetPixels = endOffset > 0 ? totalPathLength * endOffset : 0;
// 4. project as a ratio of the remaining length,
// and repeat while there is room for another point of the pattern
// 2. generate the positions of the pattern as offsets from the polygon start
var positionOffsets = [];
var positionOffset = startOffsetPixels;
do {
positionOffsets.push(positionOffset);
positionOffset += repeatIntervalPixels;
} while (repeatIntervalPixels > 0 && positionOffset < totalPathLength - endOffsetPixels);
while (repeatIntervalLength <= remainingLength - endOffsetPixels) {
previous = interpolateOnPointPath(remainingPath, repeatIntervalLength / remainingLength);
positions.push(previous);
remainingPath = remainingPath.slice(previous.predecessor);
remainingPath[0] = previous.pt;
remainingLength = getPointPathPixelLength(remainingPath);
// 3. projects offsets to segments
var segmentIndex = 0;
var segment = segments[0];
return positionOffsets.map(function (positionOffset) {
// find the segment matching the offset,
// starting from the previous one as offsets are ordered
while (positionOffset > segment.distB && segmentIndex < nbSegments - 1) {
segmentIndex++;
segment = segments[segmentIndex];
}
}
return positions;
}
/**
* pts: array of L.Point
* ratio: the ratio of the total length where the point should be computed
* Returns null if ll has less than 2 LatLng, or an object with the following properties:
* latLng: the LatLng of the interpolated point
* predecessor: the index of the previous vertex on the path
* heading: the heading of the path at this point, in degrees
*/
function interpolateOnPointPath(pts, ratio) {
var nbVertices = pts.length;
if (nbVertices < 2) {
return null;
}
// easy limit cases: ratio negative/zero => first vertex
if (ratio <= 0) {
var segmentRatio = (positionOffset - segment.distA) / (segment.distB - segment.distA);
return {
pt: pts[0],
predecessor: 0,
heading: computeAngle(pts[0], pts[1])
pt: interpolateBetweenPoints(segment.a, segment.b, segmentRatio),
heading: segment.heading
};
}
// ratio >=1 => last vertex
if (ratio >= 1) {
return {
pt: pts[nbVertices - 1],
predecessor: nbVertices - 1,
heading: computeAngle(pts[nbVertices - 2], pts[nbVertices - 1])
};
}
// 1-segment-only path => direct linear interpolation
if (nbVertices == 2) {
return {
pt: interpolateBetweenPoints(pts[0], pts[1], ratio),
predecessor: 0,
heading: computeAngle(pts[0], pts[1])
};
}
var pathLength = getPointPathPixelLength(pts);
var a = pts[0],
b = a,
ratioA = 0,
ratioB = 0,
distB = 0;
// follow the path segments until we find the one
// on which the point must lie => [ab]
var i = 1;
for (; i < nbVertices && ratioB < ratio; i++) {
a = b;
ratioA = ratioB;
b = pts[i];
distB += a.distanceTo(b);
ratioB = distB / pathLength;
}
// compute the ratio relative to the segment [ab]
var segmentRatio = (ratio - ratioA) / (ratioB - ratioA);
return {
pt: interpolateBetweenPoints(a, b, segmentRatio),
predecessor: i - 2,
heading: computeAngle(a, b)
};
});
}

@@ -155,4 +130,4 @@

function interpolateBetweenPoints(ptA, ptB, ratio) {
if (ptB.x != ptA.x) {
return L.point(ptA.x * (1 - ratio) + ratio * ptB.x, ptA.y * (1 - ratio) + ratio * ptB.y);
if (ptB.x !== ptA.x) {
return L.point(ptA.x + ratio * (ptB.x - ptA.x), ptA.y + ratio * (ptB.y - ptA.y));
}

@@ -222,7 +197,2 @@ // special case where points lie on the same vertical axis

// enable rotationAngle and rotationOrigin support on L.Marker
/**
* Defines several classes of symbol factories,
* to be used with L.PolylineDecorator
*/
L.Symbol = L.Symbol || {};

@@ -235,4 +205,2 @@

L.Symbol.Dash = L.Class.extend({
isZoomDependant: true,
options: {

@@ -271,4 +239,2 @@ pixelSize: 10,

L.Symbol.ArrowHead = L.Class.extend({
isZoomDependant: true,
options: {

@@ -313,4 +279,2 @@ polygon: true,

L.Symbol.Marker = L.Class.extend({
isZoomDependant: false,
options: {

@@ -325,3 +289,2 @@ markerOptions: {},

this.options.markerOptions.draggable = false;
this.isZoomDependant = L.Browser.ie && this.options.rotate;
},

@@ -426,16 +389,2 @@

_parseRelativeOrAbsoluteValue: function _parseRelativeOrAbsoluteValue(value) {
if (typeof value === 'string' && value.indexOf('%') !== -1) {
return {
value: parseFloat(value) / 100,
isInPixels: false
};
}
var parsedValue = value ? parseFloat(value) : 0;
return {
value: parsedValue,
isInPixels: parsedValue > 0
};
},
/**

@@ -449,5 +398,5 @@ * Parse the pattern definition

// absolute (in pixels) or relative (in percentage of the polyline length)
offset: this._parseRelativeOrAbsoluteValue(patternDef.offset),
endOffset: this._parseRelativeOrAbsoluteValue(patternDef.endOffset),
repeat: this._parseRelativeOrAbsoluteValue(patternDef.repeat)
offset: parseRelativeOrAbsoluteValue(patternDef.offset),
endOffset: parseRelativeOrAbsoluteValue(patternDef.endOffset),
repeat: parseRelativeOrAbsoluteValue(patternDef.repeat)
};

@@ -479,9 +428,2 @@ },

_asRatioToPathLength: function _asRatioToPathLength(_ref, totalPathLength) {
var value = _ref.value,
isInPixels = _ref.isInPixels;
return isInPixels ? value / totalPathLength : value;
},
/**

@@ -498,10 +440,3 @@ * Select pairs of LatLng and heading angle,

var pathPixelLength = getPixelLength(latLngs, this._map);
var ratios = {
offset: this._asRatioToPathLength(pattern.offset, pathPixelLength),
endOffset: this._asRatioToPathLength(pattern.endOffset, pathPixelLength),
repeat: this._asRatioToPathLength(pattern.repeat, pathPixelLength)
};
return projectPatternOnPath(latLngs, ratios, this._map);
return projectPatternOnPath(latLngs, pattern, this._map);
},

@@ -546,4 +481,5 @@

this._patterns.forEach(function (pattern) {
var layers = _this5._getPatternLayers(pattern);
this._patterns.map(function (pattern) {
return _this5._getPatternLayers(pattern);
}).forEach(function (layers) {
_this5.addLayer(L.layerGroup(layers));

@@ -550,0 +486,0 @@ });

@@ -13,15 +13,10 @@

// --- Arrow, with animation to demonstrate the use of setPatterns ---
// --- Simple arrow ---
var arrow = L.polyline([[57, -19], [60, -12]], {}).addTo(map);
var arrowHead = L.polylineDecorator(arrow).addTo(map);
var arrowHead = L.polylineDecorator(arrow, {
patterns: [
{offset: '100%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, pathOptions: {stroke: true}})}
]
}).addTo(map);
var arrowOffset = 0;
var anim = window.setInterval(function() {
arrowHead.setPatterns([
{offset: arrowOffset+'%', repeat: 0, symbol: L.Symbol.arrowHead({pixelSize: 15, polygon: false, pathOptions: {stroke: true}})}
])
if(++arrowOffset > 100)
arrowOffset = 0;
}, 100);
// --- Polygon, with an inner ring ---

@@ -28,0 +23,0 @@ var polygon = L.polygon([[[54, -6], [55, -7], [56, -2], [55, 1], [53, 0]], [[54, -3], [54, -2], [55, -1], [55, -5]]], {color: "#ff7800", weight: 1}).addTo(map);

{
"name": "leaflet-polylinedecorator",
"version": "1.3.0",
"version": "1.3.2",
"repository": "bbecquet/Leaflet.PolylineDecorator",

@@ -5,0 +5,0 @@ "main": "./dist/leaflet.polylineDecorator.js",

@@ -10,5 +10,5 @@ # Leaflet PolylineDecorator

The development version of the plugin (on the `master` branch) is targeted at the 1.x version of Leaflet.
**The current version of the plugin (on the `master` branch) works only with versions 1.\* of Leaflet**.
For a version of the plugin compatible with the 0.7.x Leaflet release, use the `leaflet-0.7.2` branch.
For a version of the plugin compatible with the older 0.7.* Leaflet releases, use the `leaflet-0.7.2` branch. But this branch is not maintained anymore and Leaflet 1.* has been around for a while, so you should definitely update.

@@ -79,6 +79,8 @@ ## npm / bower

## Performance note
## Performance note/alternatives
Please note that this library is in an early stage, and many operations could still be optimized.
Moreover, as it requires a lot of (re-)computations, and each pattern symbol is an actual `L.ILayer` object, it can have an impact on the responsiveness of your map, especially if used on many objects.
In cases where it's applicable (dash patterns), you should probably use instead the `dashArray` property of `L.Path`, as it's natively drawn by the browser.
This plugin creates actual `L.Layer` objects (markers, polyline, etc.) to draw the pattern symbols. This is extra customizable as you can define your own symbols, but it may have an impact on the responsiveness of your map if you have to draw a lot of symbols on many large polylines.
Here are two light-weight alternatives for simpler cases:
- the [`dashArray` property of `L.Path`](http://leafletjs.com/reference-1.1.0.html#path-dasharray), f you only need to draw simple patterns (dashes, dots, etc.).
- the [`Leaflet.TextPath`](https://github.com/makinacorpus/Leaflet.TextPath) plugin, which is based on SVG.
import {
getPixelLength,
projectPatternOnPath,
} from './utils.js';
parseRelativeOrAbsoluteValue,
} from './patternUtils.js';
import './L.Symbol.js';

@@ -91,16 +91,2 @@

_parseRelativeOrAbsoluteValue: function(value) {
if (typeof value === 'string' && value.indexOf('%') !== -1) {
return {
value: parseFloat(value) / 100,
isInPixels: false,
};
}
const parsedValue = value ? parseFloat(value) : 0;
return {
value: parsedValue,
isInPixels: parsedValue > 0,
};
},
/**

@@ -114,5 +100,5 @@ * Parse the pattern definition

// absolute (in pixels) or relative (in percentage of the polyline length)
offset: this._parseRelativeOrAbsoluteValue(patternDef.offset),
endOffset: this._parseRelativeOrAbsoluteValue(patternDef.endOffset),
repeat: this._parseRelativeOrAbsoluteValue(patternDef.repeat),
offset: parseRelativeOrAbsoluteValue(patternDef.offset),
endOffset: parseRelativeOrAbsoluteValue(patternDef.endOffset),
repeat: parseRelativeOrAbsoluteValue(patternDef.repeat),
};

@@ -142,6 +128,2 @@ },

_asRatioToPathLength: function({ value, isInPixels }, totalPathLength) {
return isInPixels ? value / totalPathLength : value;
},
/**

@@ -158,10 +140,3 @@ * Select pairs of LatLng and heading angle,

const pathPixelLength = getPixelLength(latLngs, this._map);
const ratios = {
offset: this._asRatioToPathLength(pattern.offset, pathPixelLength),
endOffset: this._asRatioToPathLength(pattern.endOffset, pathPixelLength),
repeat: this._asRatioToPathLength(pattern.repeat, pathPixelLength),
};
return projectPatternOnPath(latLngs, ratios, this._map);
return projectPatternOnPath(latLngs, pattern, this._map);
},

@@ -199,6 +174,5 @@

_draw: function () {
this._patterns.forEach(pattern => {
const layers = this._getPatternLayers(pattern);
this.addLayer(L.layerGroup(layers));
});
this._patterns
.map(pattern => this._getPatternLayers(pattern))
.forEach(layers => { this.addLayer(L.layerGroup(layers)); });
}

@@ -205,0 +179,0 @@ });

@@ -16,4 +16,2 @@ // enable rotationAngle and rotationOrigin support on L.Marker

L.Symbol.Dash = L.Class.extend({
isZoomDependant: true,
options: {

@@ -55,4 +53,2 @@ pixelSize: 10,

L.Symbol.ArrowHead = L.Class.extend({
isZoomDependant: true,
options: {

@@ -107,4 +103,2 @@ polygon: true,

L.Symbol.Marker = L.Class.extend({
isZoomDependant: false,
options: {

@@ -119,3 +113,2 @@ markerOptions: { },

this.options.markerOptions.draggable = false;
this.isZoomDependant = (L.Browser.ie && this.options.rotate);
},

@@ -122,0 +115,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc