L.LabelTextCollision = L.Canvas .extend({ options : { /** * Collision detection */ collisionFlg : true }, initialize : function(options) { options = L.Util.setOptions(this, options); }, _handleMouseHover : function(e, point) { var id, layer; for (id in this._drawnLayers) { layer = this._drawnLayers[id]; if (layer.options.interactive && layer._containsPoint(point)) { L.DomUtil.addClass(this._containerText, 'leaflet-interactive'); // change cursor this._fireEvent([ layer ], e, 'mouseover'); this._hoveredLayer = layer; } } if (this._hoveredLayer) { this._fireEvent([ this._hoveredLayer ], e); } }, _handleMouseOut : function(e, point) { var layer = this._hoveredLayer; if (layer && (e.type === 'mouseout' || !layer ._containsPoint(point))) { // if we're leaving the layer, fire mouseout L.DomUtil.removeClass(this._containerText, 'leaflet-interactive'); this._fireEvent([ layer ], e, 'mouseout'); this._hoveredLayer = null; } }, _updateTransform : function(center, zoom) { L.Canvas.prototype._updateTransform.call(this, center, zoom); var scale = this._map.getZoomScale(zoom, this._zoom), position = L.DomUtil .getPosition(this._container), viewHalf = this._map .getSize().multiplyBy(0.5 + this.options.padding), currentCenterPoint = this._map .project(this._center, zoom), destCenterPoint = this._map .project(center, zoom), centerOffset = destCenterPoint .subtract(currentCenterPoint), topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add( viewHalf).subtract(centerOffset); if (L.Browser.any3d) { L.DomUtil.setTransform(this._containerText, topLeftOffset, scale); } else { L.DomUtil.setPosition(this._containerText, topLeftOffset); } }, _initContainer : function(options) { L.Canvas.prototype._initContainer.call(this); this._containerText = document.createElement('canvas'); L.DomEvent.on(this._containerText, 'mousemove', L.Util.throttle(this._onMouseMove, 32, this), this).on( this._containerText, 'click dblclick mousedown mouseup contextmenu', this._onClick, this).on(this._containerText, 'mouseout', this._handleMouseOut, this); this._ctxLabel = this._containerText.getContext('2d'); L.DomUtil .addClass(this._containerText, 'leaflet-zoom-animated'); this.getPane().appendChild(this._containerText); }, _update : function() { // textList this._textList = []; L.Renderer.prototype._update.call(this); var b = this._bounds, container = this._containerText, size = b .getSize(), m = L.Browser.retina ? 2 : 1; L.DomUtil.setPosition(container, b.min); // set canvas size (also clearing it); use double size on retina container.width = m * size.x; container.height = m * size.y; container.style.width = size.x + 'px'; container.style.height = size.y + 'px'; // display text on the whole surface container.style.zIndex = '4'; this._container.style.zIndex = '3'; if (L.Browser.retina) { this._ctxLabel.scale(2, 2); } // translate so we use the same path coordinates after canvas // element moves this._ctxLabel.translate(-b.min.x, -b.min.y); L.Canvas.prototype._update.call(this); }, _updatePoly : function(layer, closed) { L.Canvas.prototype._updatePoly.call(this, layer, closed); this._text(this._ctxLabel, layer); }, _updateCircle : function(layer) { L.Canvas.prototype._updateCircle.call(this, layer); this._text(this._ctxLabel, layer); }, _text : function(ctx, layer) { if (layer.options.text != undefined) { ctx.globalAlpha = 1; var p = layer._point; var textPoint; if (p == undefined) { // polygon or polyline if (layer._parts.length == 0 || layer._parts[0].length == 0) { return; } p = this._getCenter(layer._parts[0]); } // label bounds offset var offsetX = 0; var offsetY = 0; /** * TODO setting for custom font */ ctx.lineWidth = 4.0; ctx.font = "16px 'Meiryo'"; // Collision detection var textWidth = (ctx.measureText(layer.options.text).width) + p.x;// + offsetX; var textHeight = p.y + offsetY + 20; var bounds = L.bounds( L.point(p.x + offsetX, p.y + offsetY), L.point( textWidth, textHeight)); if (this.options.collisionFlg) { for ( var index in this._textList) { var pointBounds = this._textList[index]; if (pointBounds.intersects(bounds)) { return; } } } this._textList.push(bounds); ctx.strokeStyle = "white"; ctx.strokeText(layer.options.text, p.x + offsetX, p.y + offsetY); if (layer.options.textColor == undefined) { ctx.fillStyle = "blue"; } else { ctx.fillStyle = layer.options.textColor; } ctx.fillText(layer.options.text, p.x + offsetX, p.y + offsetY); } }, _getCenter : function(points) { var i, halfDist, segDist, dist, p1, p2, ratio, len = points.length; if (!len) { return null; } // polyline centroid algorithm; only uses the first ring if // there are multiple for (i = 0, halfDist = 0; i < len - 1; i++) { halfDist += points[i].distanceTo(points[i + 1]) / 2; } // The line is so small in the current view that all points are // on the same pixel. if (halfDist === 0) { return points[0]; } for (i = 0, dist = 0; i < len - 1; i++) { p1 = points[i]; p2 = points[i + 1]; segDist = p1.distanceTo(p2); dist += segDist; if (dist > halfDist) { ratio = (dist - halfDist) / segDist; var resutl = [ p2.x - ratio * (p2.x - p1.x), p2.y - ratio * (p2.y - p1.y) ]; return L.point(resutl[0], resutl[1]); } } }, });