Original author is rcknr. I manually transpiled to use JS classes
See here
Otherwise, put this gist into a file called map-label.js and include with import MapLabel from './map-label'. From there, follow the instructions outlined above.
| /** | |
| * @license | |
| * | |
| * Copyright 2011 Google Inc. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| /** | |
| * @fileoverview Map Label. | |
| * | |
| * @author Luke Mahe (lukem@google.com), | |
| * Chris Broadfoot (cbro@google.com) | |
| */ | |
| /** | |
| * Creates a new Map Label | |
| * @constructor | |
| * @extends google.maps.OverlayView | |
| * @param {Object.<string, *>=} opt_options Optional properties to set. | |
| */ | |
| class MapLabel { | |
| constructor(opt_options) { | |
| if (!MapLabel.prototype.setValues) { | |
| for (const property in google.maps.OverlayView.prototype) { | |
| if(!MapLabel.prototype.hasOwnProperty(property)) { | |
| MapLabel.prototype[property] = google.maps.OverlayView.prototype[property]; | |
| } | |
| } | |
| } | |
| this.set('align', 'center'); | |
| this.set('fontColor', '#000000'); | |
| this.set('fontFamily', 'Roboto,Arial,sans-serif'); | |
| this.set('fontSize', 12); | |
| this.set('strokeColor', '#ffffff'); | |
| this.set('strokeWeight', 4); | |
| this.set('zIndex', 1e3); | |
| this.setValues(opt_options); | |
| } | |
| /** @inheritDoc */ | |
| changed(prop) { | |
| switch (prop) { | |
| case 'fontFamily': | |
| case 'fontSize': | |
| case 'fontColor': | |
| case 'strokeWeight': | |
| case 'strokeColor': | |
| case 'text': | |
| this.drawCanvas_(); | |
| break; | |
| case 'align': | |
| case 'maxZoom': | |
| case 'minZoom': | |
| case 'position': | |
| return this.draw(); | |
| } | |
| } | |
| /** | |
| * Draws the label to the canvas 2d context. | |
| * @private | |
| */ | |
| drawCanvas_() { | |
| const canvas = this.canvas_; | |
| if (!canvas) return; | |
| const style = canvas.style; | |
| style.position = 'absolute'; | |
| style.zIndex = /** @type number */(this.get('zIndex')); | |
| const ctx = canvas.getContext('2d'); | |
| ctx.font = `${this.get('fontSize')}px ${this.get('fontFamily')}`; | |
| const strokeWeight = Number(this.get('strokeWeight')); | |
| const text = this.get('text'); | |
| const textMeasure = ctx.measureText(text); | |
| canvas.width = Math.ceil(textMeasure.width + strokeWeight * 2); | |
| canvas.height = Math.ceil(parseInt(this.get('fontSize'), 10) + strokeWeight * 2); | |
| if (window.devicePixelRatio > 1) { | |
| style.width = `${canvas.width}px`; | |
| style.height = `${canvas.height}px`; | |
| canvas.width = canvas.width * window.devicePixelRatio; | |
| canvas.height = canvas.height * window.devicePixelRatio; | |
| ctx.scale(window.devicePixelRatio, window.devicePixelRatio); | |
| } | |
| ctx.lineJoin = 'round'; | |
| ctx.textBaseline = 'top'; | |
| ctx.textAlign = 'left'; | |
| ctx.strokeStyle = this.get('strokeColor'); | |
| ctx.fillStyle = this.get('fontColor'); | |
| ctx.font = `${this.get('fontSize')}px ${this.get('fontFamily')}`; | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| if (text) { | |
| if (strokeWeight) { | |
| ctx.lineWidth = strokeWeight; | |
| ctx.strokeText(text, strokeWeight, strokeWeight); | |
| } | |
| ctx.fillText(text, strokeWeight, strokeWeight); | |
| } | |
| } | |
| /** | |
| * @inheritDoc | |
| */ | |
| onAdd() { | |
| const canvas = this.canvas_ = document.createElement('canvas'); | |
| this.drawCanvas_(); | |
| const panes = this.getPanes(); | |
| if (panes) { | |
| panes.overlayLayer.appendChild(canvas); | |
| } | |
| } | |
| /** | |
| * @inheritDoc | |
| */ | |
| draw() { | |
| const projection = this.getProjection(); | |
| if (!projection) { | |
| // The map projection is not ready yet so do nothing | |
| return; | |
| } | |
| if (!this.canvas_) { | |
| // onAdd has not been called yet. | |
| return; | |
| } | |
| const latLng = /** @type {google.maps.LatLng} */ (this.get('position')); | |
| if (!latLng) { | |
| return; | |
| } | |
| const pos = projection.fromLatLngToDivPixel(latLng); | |
| const style = this.canvas_.style; | |
| style.top = `${pos.y}px`; | |
| switch(this.get('align')) { | |
| case 'left': | |
| style.left = `${pos.x - (this.canvas_.width / (window.devicePixelRatio ? window.devicePixelRatio : 1))}px`; | |
| style['margin-left'] = '-1em'; | |
| style['margin-top'] = '-0.4em'; | |
| break; | |
| case 'right': | |
| style.left = `${pos.x}px`; | |
| style['margin-left'] = '1em'; | |
| style['margin-top'] = '-0.4em'; | |
| break; | |
| default: | |
| style.left = `${pos.x - (this.canvas_.width / (window.devicePixelRatio ? window.devicePixelRatio : 1)) / 2}px`; | |
| style['margin-left'] = 0; | |
| style['margin-top'] = '1em'; | |
| } | |
| style.visibility = this.getVisible_(); | |
| } | |
| /** | |
| * Get the visibility of the label. | |
| * @private | |
| * @return {string} blank string if visible, 'hidden' if invisible. | |
| */ | |
| getVisible_() { | |
| const minZoom = /** @type number */(this.get('minZoom')); | |
| const maxZoom = /** @type number */(this.get('maxZoom')); | |
| if (minZoom === undefined && maxZoom === undefined) { | |
| return ''; | |
| } | |
| const map = this.getMap(); | |
| if (!map) { | |
| return ''; | |
| } | |
| const mapZoom = map.getZoom(); | |
| if (mapZoom < minZoom || mapZoom > maxZoom) { | |
| return 'hidden'; | |
| } | |
| return ''; | |
| } | |
| /** | |
| * @inheritDoc | |
| */ | |
| onRemove() { | |
| const canvas = this.canvas_; | |
| if (canvas && canvas.parentNode) { | |
| canvas.parentNode.removeChild(canvas); | |
| } | |
| } | |
| } | |
| window.MapLabel = MapLabel; | |
| export default MapLabel; |