Installed leaflet in extlib
[mediagoblin.git] / extlib / leaflet / src / layer / vector / Path.js
CommitLineData
c5ba5b04
JW
1/*\r
2 * L.Path is a base class for rendering vector paths on a map. It's inherited by Polyline, Circle, etc.\r
3 */\r
4\r
5L.Path = L.Class.extend({\r
6 includes: [L.Mixin.Events],\r
7 \r
8 statics: (function() {\r
9 var svgns = 'http://www.w3.org/2000/svg',\r
10 ce = 'createElementNS';\r
11 \r
12 return {\r
13 SVG_NS: svgns,\r
14 SVG: !!(document[ce] && document[ce](svgns, 'svg').createSVGRect),\r
15 \r
16 // how much to extend the clip area around the map view \r
17 // (relative to its size, e.g. 0.5 is half the screen in each direction)\r
18 CLIP_PADDING: 0.5\r
19 };\r
20 })(),\r
21 \r
22 options: {\r
23 stroke: true,\r
24 color: '#0033ff',\r
25 weight: 5,\r
26 opacity: 0.5,\r
27 \r
28 fill: false,\r
29 fillColor: null, //same as color by default\r
30 fillOpacity: 0.2,\r
31 \r
32 clickable: true,\r
33 \r
34 updateOnMoveEnd: false\r
35 },\r
36 \r
37 initialize: function(options) {\r
38 L.Util.setOptions(this, options);\r
39 },\r
40 \r
41 onAdd: function(map) {\r
42 this._map = map;\r
43 \r
44 this._initElements();\r
45 this._initEvents();\r
46 this.projectLatlngs();\r
47 this._updatePath();\r
48\r
49 map.on('viewreset', this.projectLatlngs, this);\r
50 \r
51 this._updateTrigger = this.options.updateOnMoveEnd ? 'moveend' : 'viewreset';\r
52 map.on(this._updateTrigger, this._updatePath, this);\r
53 },\r
54 \r
55 onRemove: function(map) {\r
56 map._pathRoot.removeChild(this._container);\r
57 map.off('viewreset', this._projectLatlngs, this);\r
58 map.off(this._updateTrigger, this._updatePath, this);\r
59 },\r
60 \r
61 projectLatlngs: function() {\r
62 // do all projection stuff here\r
63 },\r
64 \r
65 getPathString: function() {\r
66 // form path string here\r
67 },\r
68 \r
69 setStyle: function(style) {\r
70 L.Util.setOptions(this, style);\r
71 if (this._path) {\r
72 this._updateStyle();\r
73 }\r
74 },\r
75 \r
76 _initElements: function() {\r
77 this._initRoot();\r
78 this._initPath();\r
79 this._initStyle();\r
80 },\r
81 \r
82 _initRoot: function() {\r
83 if (!this._map._pathRoot) {\r
84 this._map._pathRoot = this._createElement('svg');\r
85 this._map._panes.overlayPane.appendChild(this._map._pathRoot);\r
86\r
87 this._map.on('moveend', this._updateSvgViewport, this);\r
88 this._updateSvgViewport();\r
89 }\r
90 },\r
91 \r
92 _updateSvgViewport: function() {\r
93 this._updateViewport();\r
94 \r
95 var vp = this._map._pathViewport,\r
96 min = vp.min,\r
97 max = vp.max,\r
98 width = max.x - min.x,\r
99 height = max.y - min.y,\r
100 root = this._map._pathRoot,\r
101 pane = this._map._panes.overlayPane;\r
102 \r
103 // Hack to make flicker on drag end on mobile webkit less irritating\r
104 // Unfortunately I haven't found a good workaround for this yet\r
105 if (L.Browser.mobileWebkit) { pane.removeChild(root); }\r
106 \r
107 L.DomUtil.setPosition(root, min);\r
108 root.setAttribute('width', width);\r
109 root.setAttribute('height', height);\r
110 root.setAttribute('viewBox', [min.x, min.y, width, height].join(' '));\r
111 \r
112 if (L.Browser.mobileWebkit) { pane.appendChild(root); }\r
113 },\r
114 \r
115 _updateViewport: function() {\r
116 var p = L.Path.CLIP_PADDING,\r
117 size = this._map.getSize(),\r
118 //TODO this._map._getMapPanePos()\r
119 panePos = L.DomUtil.getPosition(this._map._mapPane), \r
120 min = panePos.multiplyBy(-1).subtract(size.multiplyBy(p)),\r
121 max = min.add(size.multiplyBy(1 + p * 2));\r
122 \r
123 this._map._pathViewport = new L.Bounds(min, max);\r
124 },\r
125 \r
126 _initPath: function() {\r
127 this._container = this._createElement('g');\r
128 \r
129 this._path = this._createElement('path');\r
130 this._container.appendChild(this._path);\r
131 \r
132 this._map._pathRoot.appendChild(this._container);\r
133 },\r
134 \r
135 _initStyle: function() {\r
136 if (this.options.stroke) {\r
137 this._path.setAttribute('stroke-linejoin', 'round');\r
138 this._path.setAttribute('stroke-linecap', 'round');\r
139 }\r
140 if (this.options.fill) {\r
141 this._path.setAttribute('fill-rule', 'evenodd');\r
142 } else {\r
143 this._path.setAttribute('fill', 'none');\r
144 }\r
145 this._updateStyle();\r
146 },\r
147 \r
148 _updateStyle: function() {\r
149 if (this.options.stroke) {\r
150 this._path.setAttribute('stroke', this.options.color);\r
151 this._path.setAttribute('stroke-opacity', this.options.opacity);\r
152 this._path.setAttribute('stroke-width', this.options.weight);\r
153 }\r
154 if (this.options.fill) {\r
155 this._path.setAttribute('fill', this.options.fillColor || this.options.color);\r
156 this._path.setAttribute('fill-opacity', this.options.fillOpacity);\r
157 }\r
158 },\r
159 \r
160 _updatePath: function() {\r
161 var str = this.getPathString();\r
162 if (!str) {\r
163 // fix webkit empty string parsing bug\r
164 str = 'M0 0';\r
165 }\r
166 this._path.setAttribute('d', str);\r
167 },\r
168 \r
169 _createElement: function(name) {\r
170 return document.createElementNS(L.Path.SVG_NS, name);\r
171 },\r
172 \r
173 // TODO remove duplication with L.Map\r
174 _initEvents: function() {\r
175 if (this.options.clickable) {\r
176 if (!L.Path.VML) {\r
177 this._path.setAttribute('class', 'leaflet-clickable');\r
178 }\r
179 \r
180 L.DomEvent.addListener(this._container, 'click', this._onMouseClick, this);\r
181\r
182 var events = ['dblclick', 'mousedown', 'mouseover', 'mouseout'];\r
183 for (var i = 0; i < events.length; i++) {\r
184 L.DomEvent.addListener(this._container, events[i], this._fireMouseEvent, this);\r
185 }\r
186 }\r
187 },\r
188 \r
189 _onMouseClick: function(e) {\r
190 if (this._map.dragging && this._map.dragging.moved()) { return; }\r
191 this._fireMouseEvent(e);\r
192 },\r
193 \r
194 _fireMouseEvent: function(e) {\r
195 if (!this.hasEventListeners(e.type)) { return; }\r
196 this.fire(e.type, {\r
197 latlng: this._map.mouseEventToLatLng(e),\r
198 layerPoint: this._map.mouseEventToLayerPoint(e)\r
199 });\r
200 L.DomEvent.stopPropagation(e);\r
201 },\r
202 \r
203 _redraw: function() {\r
204 this.projectLatlngs();\r
205 this._updatePath();\r
206 }\r
207});