diff --git a/src/L.LineUtil.PolylineDecorator.js b/src/L.LineUtil.PolylineDecorator.js index 6f5cbe7..c66e2a5 100644 --- a/src/L.LineUtil.PolylineDecorator.js +++ b/src/L.LineUtil.PolylineDecorator.js @@ -19,6 +19,24 @@ L.LineUtil.PolylineDecorator = { return dist; }, + /** + * Calculates the length of the given path + * path: array of L.Point objects (pixel coordinates) + * Returns the length of the given path + */ + getLength: function(path) { + var numPoints = path.length; + if (numPoints < 2) { + return 0; + } + var i, len = 0, pt, prevPt = path[0]; + for (i = 1; i < numPoints; ++i) { + len += prevPt.distanceTo(pt = path[i]); + prevPt = pt; + } + return len; + }, + getPixelLength: function(pl, map) { var ll = (pl instanceof L.Polyline) ? pl.getLatLngs() : pl, nbPts = ll.length; @@ -36,15 +54,13 @@ L.LineUtil.PolylineDecorator = { /** * path: array of L.LatLng + * pathAsPoints: array of L.Point * offsetRatio: the ratio of the total pixel length where the pattern will start * repeatRatio: the ratio of the total pixel length between two points of the pattern * map: the map, to access the current projection state */ - projectPatternOnPath: function (path, offsetRatio, repeatRatio, map) { - var pathAsPoints = [], i; - for(i=0, l=path.length; i 0) { + pxLength = L.LineUtil.PolylineDecorator.getLength(pxPath); } - var offset, repeat, pathPixelLength = null, latLngs = this._paths[pathIndex]; - if(pattern.isOffsetInPixels) { - pathPixelLength = L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map); - offset = pattern.offset/pathPixelLength; + clippedPxPaths.forEach(function (clipped) { + var offset, repeat, + clippedLength = L.LineUtil.PolylineDecorator.getLength(clipped.coords); + + repeat = this._calcRepeat(pattern, pxLength, clippedLength); + offset = this._calcOffset(pattern, pxLength, clippedLength, clipped.offset, repeat * clippedLength); + + if (offset <= 1) { + var coordsAsLatLngs = clipped.coords.map(function (p) { + return map.unproject(p); + }); + dirPoints = dirPoints.concat(L.LineUtil.PolylineDecorator.projectPatternOnPath(coordsAsLatLngs, clipped.coords, offset, repeat, map)); + } + + }, this); + + return dirPoints; + }, + + _calcOffset: function (pattern, pxLength, clippedLength, clippedOffset, pxRepeat) { + var pxOffset, + offset; + // Calc pattern offset in pixels + if (pattern.isOffsetInPixels) { + pxOffset = pattern.offset; } else { - offset = pattern.offset; + pxOffset = pattern.offset * pxLength; } + // Calc pattern offset for the clipped path + if (clippedOffset <= pxOffset) { + offset = pxOffset - clippedOffset; + } else { + offset = Math.ceil((clippedOffset - pxOffset) / pxRepeat) * pxRepeat - (clippedOffset - pxOffset); + } + // Return pattern offset in percent + return offset / clippedLength; + }, + + _calcRepeat: function (pattern, pxLength, clippedLength) { if(pattern.isRepeatInPixels) { - pathPixelLength = (pathPixelLength !== null) ? pathPixelLength : L.LineUtil.PolylineDecorator.getPixelLength(latLngs, this._map); - repeat = pattern.repeat/pathPixelLength; + return pattern.repeat / clippedLength; } else { - repeat = pattern.repeat; + return pattern.repeat * pxLength / clippedLength; } - dirPoints = L.LineUtil.PolylineDecorator.projectPatternOnPath(latLngs, offset, repeat, this._map); - // save in cache to avoid recomputing this - pattern.cache[zoom][pathIndex] = dirPoints; - - return dirPoints; }, - /** - * Public redraw, invalidating the cache. - */ redraw: function() { - this._redraw(true); - }, - - /** - * "Soft" redraw, called internally for example on zoom changes, - * keeping the cache. - */ - _softRedraw: function() { - this._redraw(false); - }, - - _redraw: function(clearCache) { if(this._map === null) return; this.clearLayers(); - if(clearCache) { - for(var i=0; i