OLD | NEW |
(Empty) | |
| 1 <!-- Copyright (c) 2015 Google Inc. All rights reserved. --> |
| 2 |
| 3 <link rel="import" href="../polymer/polymer.html"> |
| 4 <link rel="import" href="../google-apis/google-maps-api.html"> |
| 5 <link rel="import" href="google-map-point.html"> |
| 6 |
| 7 <!-- |
| 8 The `google-map-poly` element represents a series of connected line segments (ak
a a polyline) which |
| 9 may also be closed to form a polygon (provided there are at least three points).
It is used as a |
| 10 child of `google-map` and will contain at least two `google-map-point` child ele
ments. |
| 11 |
| 12 <b>Example</b>—a simple line: |
| 13 |
| 14 <google-map latitude="37.77493" longitude="-122.41942"> |
| 15 <google-map-poly> |
| 16 <google-map-point latitude="37.77493" longitude="-122.41942"></google-ma
p-point> |
| 17 <google-map-point latitude="38.77493" longitude="-123.41942"></google-ma
p-point> |
| 18 </google-map-poly> |
| 19 </google-map> |
| 20 |
| 21 <b>Example</b>—a semi-translucent blue triangle: |
| 22 |
| 23 <google-map latitude="37.77493" longitude="-122.41942"> |
| 24 <google-map-poly closed fill-color="blue" fill-opacity=".5"> |
| 25 <google-map-point latitude="36.77493" longitude="-121.41942"></google-ma
p-point> |
| 26 <google-map-point latitude="38.77493" longitude="-122.41942"></google-ma
p-point> |
| 27 <google-map-point latitude="36.77493" longitude="-123.41942"></google-ma
p-point> |
| 28 </google-map-poly> |
| 29 </google-map> |
| 30 --> |
| 31 |
| 32 <dom-module id="google-map-poly"> |
| 33 <style> |
| 34 :host { |
| 35 display: none; |
| 36 } |
| 37 </style> |
| 38 <template> |
| 39 <content id="points" select="google-map-point"></content> |
| 40 </template> |
| 41 </polymer-element> |
| 42 |
| 43 <script> |
| 44 Polymer({ |
| 45 is: 'google-map-poly', |
| 46 |
| 47 /** |
| 48 * Fired when the `path` property is built based on child `google-map-point`
elements, either |
| 49 * initially or when they are changed. |
| 50 * @event google-map-poly-path-built |
| 51 * @param {MVCArray.<LatLng>} path The poly path. |
| 52 */ |
| 53 /** |
| 54 * Fired when the user finishes adding vertices to the poly. The host compon
ent can use the |
| 55 * provided path to rebuild its list of points. |
| 56 * @event google-map-poly-path-updated |
| 57 * @param {MVCArray.<LatLng>} path The poly path. |
| 58 */ |
| 59 /** |
| 60 * Fired when the DOM `click` event is fired on the poly. Requires the click
Events attribute to |
| 61 * be true. |
| 62 * @event google-map-poly-click |
| 63 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 64 */ |
| 65 /** |
| 66 * Fired when the DOM `dblclick` event is fired on the poly. Requires the cl
ickEvents attribute |
| 67 * to be true. |
| 68 * @event google-map-poly-dblclick |
| 69 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 70 */ |
| 71 /** |
| 72 * Fired repeatedly while the user drags the poly. Requires the dragEvents a
ttribute to be true. |
| 73 * @event google-map-poly-drag |
| 74 * @param {google.maps.MouseEvent} event The mouse event. |
| 75 */ |
| 76 /** |
| 77 * Fired when the user stops dragging the poly. Requires the dragEvents attr
ibute to be true. |
| 78 * @event google-map-poly-dragend |
| 79 * @param {google.maps.MouseEvent} event The mouse event. |
| 80 */ |
| 81 /** |
| 82 * Fired when the user starts dragging the poly. Requires the dragEvents att
ribute to be true. |
| 83 * @event google-map-poly-dragstart |
| 84 * @param {google.maps.MouseEvent} event The mouse event. |
| 85 */ |
| 86 /** |
| 87 * Fired when the DOM `mousedown` event is fired on the poly. Requires the m
ouseEvents attribute |
| 88 * to be true. |
| 89 * @event google-map-poly-mousedown |
| 90 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 91 */ |
| 92 /** |
| 93 * Fired when the DOM `mousemove` event is fired on the poly. Requires the m
ouseEvents attribute |
| 94 * to be true. |
| 95 * @event google-map-poly-mousemove |
| 96 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 97 */ |
| 98 /** |
| 99 * Fired on poly mouseout. Requires the mouseEvents attribute to be true. |
| 100 * @event google-map-poly-mouseout |
| 101 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 102 */ |
| 103 /** |
| 104 * Fired on poly mouseover. Requires the mouseEvents attribute to be true. |
| 105 * @event google-map-poly-mouseover |
| 106 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 107 */ |
| 108 /** |
| 109 * Fired when the DOM `mouseup` event is fired on the poly. Requires the mou
seEvents attribute |
| 110 * to be true. |
| 111 * @event google-map-poly-mouseup |
| 112 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 113 */ |
| 114 /** |
| 115 * Fired when the poly is right-clicked on. Requires the clickEvents attribu
te to be true. |
| 116 * @event google-map-poly-rightclick |
| 117 * @param {google.maps.PolyMouseEvent} event The poly event. |
| 118 */ |
| 119 properties: { |
| 120 /** |
| 121 * A Google Maps polyline or polygon object (depending on value of "closed
" attribute). |
| 122 * @type google.maps.Polyline|google.maps.Polygon |
| 123 */ |
| 124 poly: { |
| 125 type: Object, |
| 126 readOnly: true |
| 127 }, |
| 128 |
| 129 /** |
| 130 * An array of the Google Maps LatLng objects that define the poly shape. |
| 131 * @type MVCArray.<LatLng> |
| 132 */ |
| 133 path: { |
| 134 type: Object, |
| 135 readOnly: true |
| 136 }, |
| 137 |
| 138 /** |
| 139 * The Google map object. |
| 140 * @type google.maps.Map |
| 141 */ |
| 142 map: { |
| 143 type: Object, |
| 144 observer: '_mapChanged' |
| 145 }, |
| 146 |
| 147 /** |
| 148 * When true, the poly will generate mouse events. |
| 149 */ |
| 150 clickable: { |
| 151 type: Boolean, |
| 152 value: false, |
| 153 observer: '_clickableChanged' |
| 154 }, |
| 155 |
| 156 /** |
| 157 * When true, the google-map-poly-*click events will be automatically regi
stered. |
| 158 */ |
| 159 clickEvents: { |
| 160 type: Boolean, |
| 161 value: false, |
| 162 observer: '_clickEventsChanged' |
| 163 }, |
| 164 |
| 165 /** |
| 166 * When true, the path will be closed by connecting the last point to the
first one and |
| 167 * treating the poly as a polygon. |
| 168 */ |
| 169 closed: { |
| 170 type: Boolean, |
| 171 value: false, |
| 172 observer: '_closedChanged' |
| 173 }, |
| 174 |
| 175 /** |
| 176 * When true, the poly may be dragged to a new position. |
| 177 */ |
| 178 draggable: { |
| 179 type: Boolean, |
| 180 value: false, |
| 181 }, |
| 182 |
| 183 /** |
| 184 * When true, the google-map-poly-drag* events will be automatically regis
tered. |
| 185 */ |
| 186 dragEvents: { |
| 187 type: Boolean, |
| 188 value: false, |
| 189 observer: '_dragEventsChanged' |
| 190 }, |
| 191 |
| 192 /** |
| 193 * When true, the poly's vertices may be individually moved or new ones ad
ded. |
| 194 */ |
| 195 editable: { |
| 196 type: Boolean, |
| 197 value: false, |
| 198 observer: '_editableChanged' |
| 199 }, |
| 200 |
| 201 /** |
| 202 * When true, indicates that the user has begun editing the poly path (add
ing vertices). |
| 203 */ |
| 204 editing: { |
| 205 type: Boolean, |
| 206 value: false, |
| 207 notify: true, |
| 208 readOnly: true |
| 209 }, |
| 210 |
| 211 /** |
| 212 * If the path is closed, the polygon fill color. All CSS3 colors are supp
orted except for |
| 213 * extended named colors. |
| 214 */ |
| 215 fillColor: { |
| 216 type: String, |
| 217 value: '', |
| 218 observer: '_fillColorChanged' |
| 219 }, |
| 220 |
| 221 /** |
| 222 * If the path is closed, the polygon fill opacity (between 0.0 and 1.0). |
| 223 */ |
| 224 fillOpacity: { |
| 225 type: Number, |
| 226 value: 0, |
| 227 observer: '_fillOpacityChanged' |
| 228 }, |
| 229 |
| 230 /** |
| 231 * When true, the poly's edges are interpreted as geodesic and will follow
the curvature of |
| 232 * the Earth. When not set, the poly's edges are rendered as straight line
s in screen space. |
| 233 * Note that the poly of a geodesic poly may appear to change when dragged
, as the dimensions |
| 234 * are maintained relative to the surface of the earth. |
| 235 */ |
| 236 geodesic: { |
| 237 type: Boolean, |
| 238 value: false, |
| 239 observer: '_geodesicChanged' |
| 240 }, |
| 241 |
| 242 /** |
| 243 * If the path is not closed, the icons to be rendered along the polyline. |
| 244 */ |
| 245 icons: { |
| 246 type: Array, |
| 247 value: null, |
| 248 observer: '_iconsChanged' |
| 249 }, |
| 250 |
| 251 /** |
| 252 * When true, the google-map-poly-mouse* events will be automatically regi
stered. |
| 253 */ |
| 254 mouseEvents: { |
| 255 type: Boolean, |
| 256 value: false, |
| 257 observer: '_mouseEventsChanged' |
| 258 }, |
| 259 |
| 260 /** |
| 261 * The color to draw the poly's stroke with. All CSS3 colors are supported
except for extended |
| 262 * named colors. |
| 263 */ |
| 264 strokeColor: { |
| 265 type: String, |
| 266 value: 'black', |
| 267 observer: '_strokeColorChanged' |
| 268 }, |
| 269 |
| 270 /** |
| 271 * The stroke opacity (between 0.0 and 1.0). |
| 272 */ |
| 273 strokeOpacity: { |
| 274 type: Number, |
| 275 value: 1, |
| 276 observer: '_strokeOpacityChanged' |
| 277 }, |
| 278 |
| 279 /** |
| 280 * The stroke position (center, inside, or outside). |
| 281 */ |
| 282 strokePosition: { |
| 283 type: String, |
| 284 value: 'center', |
| 285 observer: '_strokePositionChanged' |
| 286 }, |
| 287 |
| 288 /** |
| 289 * The stroke width in pixels. |
| 290 */ |
| 291 strokeWeight: { |
| 292 type: Number, |
| 293 value: 3, |
| 294 observer: '_strokeWeightChanged' |
| 295 }, |
| 296 |
| 297 /** |
| 298 * The Z-index relative to other objects on the map. |
| 299 */ |
| 300 zIndex: { |
| 301 type: Number, |
| 302 value: 0, |
| 303 observer: '_zIndexChanged' |
| 304 } |
| 305 }, |
| 306 |
| 307 // Lifecycle event handlers. |
| 308 |
| 309 detached: function() { |
| 310 this.poly.setMap(null); |
| 311 if (this._pointsObserver) { |
| 312 this._pointsObserver.disconnect(); |
| 313 this._pointsObserver = null; |
| 314 } |
| 315 for (var name in this._listeners) { |
| 316 this._clearListener(name); |
| 317 } |
| 318 }, |
| 319 |
| 320 attached: function() { |
| 321 // If element is added back to DOM, put it back on the map. |
| 322 this.poly && this.poly.setMap(this.map); |
| 323 }, |
| 324 |
| 325 // Attribute/property change watchers. |
| 326 |
| 327 attributeChanged: function(attrName, oldVal, newVal) { |
| 328 if (!this.poly) { |
| 329 return; |
| 330 } |
| 331 |
| 332 // Cannot use *Changed watchers for native properties. |
| 333 switch (attrName) { |
| 334 case 'hidden': |
| 335 this.poly.setVisible(!this.hidden); |
| 336 break; |
| 337 case 'draggable': |
| 338 this.poly.setDraggable(this.draggable); |
| 339 break; |
| 340 } |
| 341 }, |
| 342 |
| 343 _clickableChanged: function() { |
| 344 this.poly && this.poly.set('clickable', this.clickable); |
| 345 }, |
| 346 |
| 347 _clickEventsChanged: function() { |
| 348 if (this.poly) { |
| 349 if (this.clickEvents) { |
| 350 this._forwardEvent('click'); |
| 351 this._forwardEvent('dblclick'); |
| 352 this._forwardEvent('rightclick'); |
| 353 } else { |
| 354 this._clearListener('click'); |
| 355 this._clearListener('dblclick'); |
| 356 this._clearListener('rightclick'); |
| 357 } |
| 358 } |
| 359 }, |
| 360 |
| 361 _closedChanged: function() { |
| 362 this._mapChanged(); |
| 363 }, |
| 364 |
| 365 _dragEventsChanged: function() { |
| 366 if (this.poly) { |
| 367 if (this.clickEvents) { |
| 368 this._forwardEvent('drag'); |
| 369 this._forwardEvent('dragend'); |
| 370 this._forwardEvent('dragstart'); |
| 371 } else { |
| 372 this._clearListener('drag'); |
| 373 this._clearListener('dragend'); |
| 374 this._clearListener('dragstart'); |
| 375 } |
| 376 } |
| 377 }, |
| 378 |
| 379 _editableChanged: function() { |
| 380 this.poly && this.poly.setEditable(this.editable); |
| 381 }, |
| 382 |
| 383 _fillColorChanged: function() { |
| 384 this.poly && this.poly.set('fillColor', this.fillColor); |
| 385 }, |
| 386 |
| 387 _fillOpacityChanged: function() { |
| 388 this.poly && this.poly.set('fillOpacity', this.fillOpacity); |
| 389 }, |
| 390 |
| 391 _geodesicChanged: function() { |
| 392 this.poly && this.poly.set('geodesic', this.geodesic); |
| 393 }, |
| 394 |
| 395 _iconsChanged: function() { |
| 396 this.poly && this.poly.set('icons', this.icons); |
| 397 }, |
| 398 |
| 399 _mapChanged: function() { |
| 400 // Poly will be rebuilt, so disconnect existing one from old map and liste
ners. |
| 401 if (this.poly) { |
| 402 this.poly.setMap(null); |
| 403 google.maps.event.clearInstanceListeners(this.poly); |
| 404 } |
| 405 |
| 406 if (this.map && this.map instanceof google.maps.Map) { |
| 407 this._createPoly(); |
| 408 } |
| 409 }, |
| 410 |
| 411 _mouseEventsChanged: function() { |
| 412 if (this.poly) { |
| 413 if (this.mouseEvents) { |
| 414 this._forwardEvent('mousedown'); |
| 415 this._forwardEvent('mousemove'); |
| 416 this._forwardEvent('mouseout'); |
| 417 this._forwardEvent('mouseover'); |
| 418 this._forwardEvent('mouseup'); |
| 419 } else { |
| 420 this._clearListener('mousedown'); |
| 421 this._clearListener('mousemove'); |
| 422 this._clearListener('mouseout'); |
| 423 this._clearListener('mouseover'); |
| 424 this._clearListener('mouseup'); |
| 425 } |
| 426 } |
| 427 }, |
| 428 |
| 429 _strokeColorChanged: function() { |
| 430 this.poly && this.poly.set('strokeColor', this.strokeColor); |
| 431 }, |
| 432 |
| 433 _strokeOpacityChanged: function() { |
| 434 this.poly && this.poly.set('strokeOpacity', this.strokeOpacity); |
| 435 }, |
| 436 |
| 437 _strokePositionChanged: function() { |
| 438 this.poly && this.poly.set('strokePosition', this._convertStrokePosition()
); |
| 439 }, |
| 440 |
| 441 _strokeWeightChanged: function() { |
| 442 this.poly && this.poly.set('strokeWeight', this.strokeWeight); |
| 443 }, |
| 444 |
| 445 _zIndexChanged: function() { |
| 446 this.poly && this.poly.set('zIndex', this.zIndex); |
| 447 }, |
| 448 |
| 449 // Helper logic. |
| 450 |
| 451 _buildPathFromPoints: function() { |
| 452 this._points = Array.prototype.slice.call(Polymer.dom(this.$.points).getDi
stributedNodes()); |
| 453 |
| 454 // Build path from current points (ignoring vertex insertions while doing
so). |
| 455 this._building = true; |
| 456 this.path.clear(); |
| 457 for (var i = 0, point; point = this._points[i]; ++i) { |
| 458 this.path.push(point.getPosition()); |
| 459 } |
| 460 this._building = false; |
| 461 |
| 462 this.fire('google-map-poly-path-built', this.path); |
| 463 |
| 464 // Watch for future updates. |
| 465 if (this._pointsObserver) { |
| 466 return; |
| 467 } |
| 468 this._pointsObserver = new MutationObserver(this._buildPathFromPoints.bind
(this)); |
| 469 this._pointsObserver.observe(this, { |
| 470 childList: true |
| 471 }); |
| 472 }, |
| 473 |
| 474 _clearListener: function(name) { |
| 475 if (this._listeners[name]) { |
| 476 google.maps.event.removeListener(this._listeners[name]); |
| 477 this._listeners[name] = null; |
| 478 } |
| 479 }, |
| 480 |
| 481 _convertStrokePosition: function() { |
| 482 return google.maps.StrokePosition && this.strokePosition ? |
| 483 google.maps.StrokePosition[this.strokePosition.toUpperCase()] : 0; |
| 484 }, |
| 485 |
| 486 _createPoly: function() { |
| 487 // Build poly's path and register mutation listeners on first creation. |
| 488 if (!this.path) { |
| 489 this._setPath(new google.maps.MVCArray()); |
| 490 google.maps.event.addListener(this.path, 'insert_at', this._startEditing
.bind(this)); |
| 491 google.maps.event.addListener(this.path, 'set_at', this._updatePoint.bin
d(this)); |
| 492 this._buildPathFromPoints(); |
| 493 } |
| 494 |
| 495 var options = { |
| 496 clickable: this.clickable || this.draggable, // draggable must be click
able to work. |
| 497 draggable: this.draggable, |
| 498 editable: this.editable, |
| 499 geodesic: this.geodesic, |
| 500 map: this.map, |
| 501 path: this.path, |
| 502 strokeColor: this.strokeColor, |
| 503 strokeOpacity: this.strokeOpacity, |
| 504 strokePosition: this._convertStrokePosition(), |
| 505 strokeWeight: this.strokeWeight, |
| 506 visible: !this.hidden, |
| 507 zIndex: this.zIndex |
| 508 }; |
| 509 |
| 510 if (this.closed) { |
| 511 options.fillColor = this.fillColor; |
| 512 options.fillOpacity = this.fillOpacity; |
| 513 this._setPoly(new google.maps.Polygon(options)); |
| 514 } else { |
| 515 options.icons = this.icons; |
| 516 this._setPoly(new google.maps.Polyline(options)); |
| 517 } |
| 518 |
| 519 this._listeners = {}; |
| 520 }, |
| 521 |
| 522 _forwardEvent: function(name) { |
| 523 this._listeners[name] = google.maps.event.addListener(this.poly, name, fun
ction(event) { |
| 524 this.fire('google-map-poly-' + name, event); |
| 525 }.bind(this)); |
| 526 }, |
| 527 |
| 528 _startEditing: function(index) { |
| 529 if (this._building) { |
| 530 // Ignore changes while building path. |
| 531 return; |
| 532 } |
| 533 |
| 534 // Signal start of editing when first vertex inserted, end when map clicke
d. |
| 535 if (!this.editing) { |
| 536 this._setEditing(true); |
| 537 // The poly path and google-map-point elements lose sync once the user s
tarts adding points, |
| 538 // so invalidate the _points array. |
| 539 this._points = null; |
| 540 google.maps.event.addListenerOnce(this.map, 'click', function() { |
| 541 this._setEditing(false); |
| 542 this.fire('google-map-poly-path-updated', this.path); |
| 543 }.bind(this)); |
| 544 } |
| 545 }, |
| 546 |
| 547 _updatePoint: function(index, vertex) { |
| 548 // Ignore changes if path is out of sync with google-map-point elements. |
| 549 if (!this._points) { |
| 550 return; |
| 551 } |
| 552 |
| 553 // Update existing point so bound properties are updated. too. |
| 554 this._points[index].latitude = vertex.lat(); |
| 555 this._points[index].longitude = vertex.lng(); |
| 556 } |
| 557 }); |
| 558 </script> |
OLD | NEW |