提交 fe8d7909 编写于 作者: Q qiang

feat(h5): add google maps

上级 03979081
......@@ -427,16 +427,10 @@ module.exports = function (pagesJson, manifestJson, loader) {
const networkTimeoutConfig = getNetworkTimeout(manifestJson)
let qqMapKey = 'XVXBZ-NDMC4-JOGUS-XGIEE-QVHDZ-AMFV2'
const sdkConfigs = h5.sdkConfigs || {}
if (
sdkConfigs.maps &&
sdkConfigs.maps.qqmap &&
sdkConfigs.maps.qqmap.key
) {
qqMapKey = sdkConfigs.maps.qqmap.key
}
const qqMapKey = sdkConfigs.maps && sdkConfigs.maps.qqmap && sdkConfigs.maps.qqmap.key
const googleMapKey = sdkConfigs.maps && sdkConfigs.maps.google && sdkConfigs.maps.google.key
let locale = manifestJson.locale
locale = locale && locale.toUpperCase() !== 'AUTO' ? locale : ''
......@@ -456,6 +450,7 @@ global.__uniConfig.debug = ${manifestJson.debug === true};
global.__uniConfig.networkTimeout = ${JSON.stringify(networkTimeoutConfig)};
global.__uniConfig.sdkConfigs = ${JSON.stringify(sdkConfigs)};
global.__uniConfig.qqMapKey = ${JSON.stringify(qqMapKey)};
global.__uniConfig.googleMapKey = ${JSON.stringify(googleMapKey)};
global.__uniConfig.locale = ${JSON.stringify(locale)};
global.__uniConfig.fallbackLocale = ${JSON.stringify(manifestJson.fallbackLocale)};
global.__uniConfig.locales = locales.keys().reduce((res,key)=>{const locale=key.replace(/\\.\\/(uni-app.)?(.*).json/,'$2');const messages = locales(key);Object.assign(res[locale]||(res[locale]={}),messages.common||messages);return res},{});
......
export const MapType = {
QQ: 'qq',
GOOGLE: 'google',
UNKNOWN: ''
}
export function getMapInfo () {
let type = MapType.UNKNOWN
let key = ''
if (__uniConfig.qqMapKey) {
type = MapType.QQ
key = __uniConfig.qqMapKey
} else if (__uniConfig.googleMapKey) {
type = MapType.GOOGLE
key = __uniConfig.googleMapKey
}
return {
type,
key
}
}
......@@ -3,11 +3,25 @@
:id="id"
v-on="$listeners"
>
<map-marker
v-for="item in markers"
:key="item.id"
v-bind="item"
/>
<div
ref="map"
style="width: 100%; height: 100%; position: relative; overflow: hidden;"
style="width: 100%; height: 100%; position: relative; overflow: hidden"
/>
<div style="position: absolute; top: 0; width: 100%; height: 100%; overflow: hidden; pointer-events: none;">
<div
style="
position: absolute;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
"
>
<slot />
</div>
</uni-map>
......@@ -19,124 +33,32 @@ import {
} from 'uni-mixins'
import {
hasOwn
} from 'uni-shared'
loadMaps
} from './maps'
import mapMarker from './map-marker'
let maps
let callbacks
function loadMap (callback) {
if (maps) {
callback()
} else if (window.qq && window.qq.maps) {
maps = window.qq.maps
callback()
} else if (callbacks) {
callbacks.push(callback)
function getLat (latLng) {
if ('getLat' in latLng) {
return latLng.getLat()
} else {
callbacks = [callback]
const key = __uniConfig.qqMapKey
const callbackName = '_callback' + Date.now()
window[callbackName] = function () {
delete window[callbackName]
maps = window.qq.maps
var Callout = maps.Callout = function (option = {}) {
this.option = option
var map = option.map
this.position = option.position
this.index = 1
this.visible = this.alwaysVisible = option.display === 'ALWAYS'
this.init()
Object.defineProperty(this, 'onclick', {
setter (callback) {
this.div.onclick = callback
},
getter () {
return this.div.onclick
}
})
if (map) {
this.setMap(map)
}
}
Callout.prototype = new maps.Overlay()
Callout.prototype.init = function () {
var option = this.option
var div = this.div = document.createElement('div')
var divStyle = div.style
divStyle.position = 'absolute'
divStyle.whiteSpace = 'nowrap'
divStyle.transform = 'translateX(-50%) translateY(-100%)'
divStyle.zIndex = 1
divStyle.boxShadow = option.boxShadow || 'none'
divStyle.display = this.visible ? 'block' : 'none'
var triangle = this.triangle = document.createElement('div')
triangle.setAttribute('style',
'position: absolute;white-space: nowrap;border-width: 4px;border-style: solid;border-color: #fff transparent transparent;border-image: initial;font-size: 12px;padding: 0px;background-color: transparent;width: 0px;height: 0px;transform: translate(-50%, 100%);left: 50%;bottom: 0;'
)
this.setStyle(option)
this.changed = function (key) {
divStyle.display = this.visible ? 'block' : 'none'
}
div.appendChild(triangle)
}
Callout.prototype.construct = function () {
var div = this.div
var panes = this.getPanes()
panes.floatPane.appendChild(div)
}
Callout.prototype.draw = function () {
var overlayProjection = this.getProjection()
if (!this.position || !this.div || !overlayProjection) {
return
}
var pixel = overlayProjection.fromLatLngToDivPixel(this.position)
var divStyle = this.div.style
divStyle.left = pixel.x + 'px'
divStyle.top = pixel.y + 'px'
}
Callout.prototype.destroy = function () {
this.div.parentNode.removeChild(this.div)
this.div = null
this.triangle = null
}
Callout.prototype.setOption = function (option) {
this.option = option
this.setPosition(option.position)
if (option.display === 'ALWAYS') {
this.alwaysVisible = this.visible = true
} else {
this.alwaysVisible = false
}
this.setStyle(option)
}
Callout.prototype.setStyle = function (option) {
var div = this.div
var divStyle = div.style
div.innerText = option.content
divStyle.lineHeight = (option.fontSize || 14) + 'px'
divStyle.fontSize = (option.fontSize || 14) + 'px'
divStyle.padding = (option.padding || 8) + 'px'
divStyle.color = option.color || '#000'
divStyle.borderRadius = (option.borderRadius || 0) + 'px'
divStyle.backgroundColor = option.bgColor || '#fff'
divStyle.marginTop = '-' + (option.top + 5) + 'px'
this.triangle.style.borderColor = `${option.bgColor || '#fff'} transparent transparent`
}
Callout.prototype.setPosition = function (position) {
this.position = position
this.draw()
}
callbacks.forEach(callback => callback())
callbacks = null
}
const script = document.createElement('script')
script.src = `https://map.qq.com/api/js?v=2.exp&key=${key}&callback=${callbackName}&libraries=geometry`
document.body.appendChild(script)
return latLng.lat()
}
}
function getLng (latLng) {
if ('getLng' in latLng) {
return latLng.getLng()
} else {
return latLng.lng()
}
}
export default {
name: 'Map',
components: {
mapMarker
},
mixins: [subscriber],
props: {
id: {
......@@ -194,6 +116,12 @@ export default {
showLocation: {
type: [Boolean, String],
default: false
},
libraries: {
type: Array,
default () {
return []
}
}
},
data () {
......@@ -204,7 +132,6 @@ export default {
},
isMapReady: false,
isBoundsReady: false,
markersSync: [],
polylineSync: [],
circlesSync: [],
controlsSync: []
......@@ -222,56 +149,6 @@ export default {
this._map.setZoom(Number(val) || 16)
})
},
markers (val, old) {
this.mapReady(() => {
var add = []
var has = []
var changed = []
var changedOption = []
var remove = []
val.forEach(option => {
if (!('id' in option)) {
add.push(option)
} else {
var isOld = false
for (var index = 0; index < old.length; index++) {
var element = old[index]
if (!('id' in element)) {
old.splice(index--, 1)
continue
}
if (element.id !== option.id) {
continue
}
isOld = true
has.push(element.id)
if (JSON.stringify(element) !== JSON.stringify(option)) {
changed.push(element.id)
changedOption.push(option)
}
old.splice(index--, 1)
}
if (!isOld) {
add.push(option)
}
}
})
var markers = this.markersSync
markers.forEach(marker => {
var id = marker.id
var index
if (has.indexOf(id) >= 0) {
if ((index = changed.indexOf(id)) >= 0) {
this.changeMarker(marker, changedOption[index])
}
} else {
remove.push(marker)
}
})
this.removeMarkers(remove)
this.createMarkers(add)
})
},
polyline (val) {
this.mapReady(() => {
this.createPolyline()
......@@ -299,6 +176,7 @@ export default {
}
},
created () {
this._markers = {}
var latitude = this.latitude
var longitude = this.longitude
if (latitude && longitude) {
......@@ -307,12 +185,12 @@ export default {
}
},
mounted () {
loadMap(() => {
loadMaps(this.libraries, result => {
this._maps = result
this.init()
})
},
beforeDestroy () {
this.removeMarkers(this.markersSync)
this.removePolyline()
this.removeCircles()
this.removeControls()
......@@ -323,6 +201,7 @@ export default {
type,
data = {}
}) {
const maps = this._maps
function callback (res, err) {
res = res || {}
res.errMsg = `${type}:${err ? 'fail' + err : 'ok'}`
......@@ -341,8 +220,8 @@ export default {
var latitude
var longitude
var center = this._map.getCenter()
latitude = center.getLat()
longitude = center.getLng()
latitude = getLat(center)
longitude = getLng(center)
callback({
latitude: latitude,
......@@ -368,7 +247,10 @@ export default {
var duration = data.duration
var autoRotate = !!data.autoRotate
var rotate = Number(data.rotate) ? data.rotate : 0
var rotation = marker.getRotation()
let rotation = 0
if ('getRotation' in marker) {
rotation = marker.getRotation()
}
var a = marker.getPosition()
var b = new maps.LatLng(destination.latitude, destination.longitude)
var distance = maps.geometry.spherical.computeDistanceBetween(a, b) / 1000
......@@ -410,8 +292,15 @@ export default {
}
rotate = maps.geometry.spherical.computeHeading(a, b) - lastRtate
}
marker.setRotation(rotation + rotate)
marker.moveTo(b, speed)
if ('setRotation' in marker) {
marker.setRotation(rotation + rotate)
}
if ('moveTo' in marker) {
marker.moveTo(b, speed)
} else {
marker.setPosition(b)
maps.event.trigger(marker, 'moveend', {})
}
} catch (error) {
callback(null, error)
}
......@@ -427,12 +316,12 @@ export default {
var northeast = latLngBounds.getNorthEast()
callback({
southwest: {
latitude: southwest.getLat(),
longitude: southwest.getLng()
latitude: getLat(southwest),
longitude: getLng(southwest)
},
northeast: {
latitude: northeast.getLat(),
longitude: northeast.getLng()
latitude: getLat(northeast),
longitude: getLng(northeast)
}
})
})
......@@ -447,6 +336,7 @@ export default {
}
},
init () {
const maps = this._maps
var center = new maps.LatLng(this.center.latitude, this.center.longitude)
var map = this._map = new maps.Map(this.$refs.map, {
center,
......@@ -457,6 +347,9 @@ export default {
zoomControl: false,
scaleControl: false,
panControl: false,
fullscreenControl: false,
streetViewControl: false,
keyboardShortcuts: false,
minZoom: 5,
maxZoom: 18,
draggable: true
......@@ -481,8 +374,8 @@ export default {
return {
scale: map.getZoom(),
centerLocation: {
latitude: center.getLat(),
longitude: center.getLng()
latitude: getLat(center),
longitude: getLng(center)
}
}
}
......@@ -503,14 +396,11 @@ export default {
var latitude
var longitude
var center = map.getCenter()
latitude = center.getLat()
longitude = center.getLng()
latitude = getLat(center)
longitude = getLng(center)
this.$emit('update:latitude', latitude)
this.$emit('update:longitude', longitude)
})
if (this.markers && Array.isArray(this.markers) && this.markers.length) {
this.createMarkers(this.markers)
}
if (this.polyline && Array.isArray(this.polyline) && this.polyline.length) {
this.createPolyline()
}
......@@ -532,6 +422,7 @@ export default {
this.$emit('mapready')
},
centerChange () {
const maps = this._maps
var latitude = Number(this.latitude)
var longitude = Number(this.longitude)
if (latitude !== this.center.latitude || longitude !== this.center.longitude) {
......@@ -544,156 +435,8 @@ export default {
}
}
},
createMarkers (markerOptions) {
var map = this._map
var markers = this.markersSync
markerOptions.forEach(option => {
var marker = new maps.Marker({
map,
flat: true,
autoRotation: false
})
marker.id = option.id
this.changeMarker(marker, option)
maps.event.addListener(marker, 'click', e => {
var callout = marker.callout
if (callout) {
var div = callout.div
var parent = div.parentNode
if (!callout.alwaysVisible) {
callout.set('visible', !callout.visible)
}
if (callout.visible) {
parent.removeChild(div)
parent.appendChild(div)
}
}
hasOwn(option, 'id') && this.$trigger('markertap', {}, {
markerId: option.id
})
})
markers.push(marker)
})
},
changeMarker (marker, option) {
var self = this
var map = this._map
var title = option.title || option.name
var position = new maps.LatLng(option.latitude, option.longitude)
var img = new Image()
img.onload = () => {
var anchor = option.anchor || {}
var icon
var w
var h
var top
var x = anchor.x
var y = anchor.y
if (option.iconPath && (option.width || option.height)) {
w = option.width || img.width / img.height * option.height
h = option.height || img.height / img.width * option.width
} else {
w = img.width / 2
h = img.height / 2
}
x = (typeof x === 'number' ? x : 0.5) * w
y = (typeof y === 'number' ? y : 1) * h
top = h - (h - y)
icon = new maps.MarkerImage(img.src, null, null, new maps.Point(x, y), new maps.Size(w, h))
marker.setPosition(position)
marker.setIcon(icon)
marker.setRotation(option.rotate || 0)
var labelOpt = option.label || {}
if (marker.label) {
marker.label.setMap(null)
delete (marker.label)
}
var label
if (labelOpt.content) {
label = new maps.Label({
position,
map,
clickable: false,
content: labelOpt.content,
style: {
border: 'none',
padding: '8px',
background: 'none',
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + 'px',
lineHeight: (labelOpt.fontSize || 14) + 'px',
marginLeft: labelOpt.x,
marginTop: labelOpt.y
}
})
marker.label = label
}
var calloutOpt = option.callout || {}
var callout = marker.callout
var calloutStyle
if (calloutOpt.content) {
calloutStyle = {
id: option.id,
position,
map,
top,
content: calloutOpt.content,
color: calloutOpt.color,
fontSize: calloutOpt.fontSize,
borderRadius: calloutOpt.borderRadius,
bgColor: calloutOpt.bgColor,
padding: calloutOpt.padding,
boxShadow: calloutOpt.boxShadow,
display: calloutOpt.display
}
} else if (title) {
calloutStyle = {
id: option.id,
position,
map,
top,
content: title,
boxShadow: '0px 0px 3px 1px rgba(0,0,0,0.5)'
}
}
if (calloutStyle) {
if (callout) {
callout.setOption(calloutStyle)
} else {
callout = marker.callout = new maps.Callout(calloutStyle)
callout.div.onclick = function ($event) {
hasOwn(option, 'id') && self.$trigger('callouttap', $event, {
markerId: option.id
})
$event.stopPropagation()
$event.preventDefault()
}
}
} else {
if (callout) {
callout.setMap(null)
delete (marker.callout)
}
}
}
img.src = option.iconPath ? this.$getRealPath(option.iconPath)
: 'data:image/png;base64,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'
},
removeMarkers (markers) {
for (var index = 0; index < markers.length; index++) {
var marker = markers[index]
if (marker.label) {
marker.label.setMap(null)
}
if (marker.callout) {
marker.callout.setMap(null)
}
marker.setMap(null)
markers.splice(index--, 1)
}
},
createPolyline () {
const maps = this._maps
var map = this._map
var polyline = this.polylineSync
this.removePolyline()
......@@ -733,6 +476,7 @@ export default {
polyline.splice(0, polyline.length)
},
createCircles () {
const maps = this._maps
var map = this._map
var circles = this.circlesSync
this.removeCircles()
......@@ -740,12 +484,15 @@ export default {
var center = new maps.LatLng(option.latitude, option.longitude)
function getColor (color) {
var c = color.match(/#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/)
if (c && c.length) {
return maps.Color.fromHex(c[0], Number('0x' + c[1] || 255) / 255)
} else {
return undefined
var c = color && color.match(/#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/)
if ('Color' in maps) {
if (c && c.length) {
return maps.Color.fromHex(c[0], Number('0x' + c[1] || 255) / 255)
} else {
return undefined
}
}
return color
}
var circle = new maps.Circle({
map,
......@@ -768,6 +515,7 @@ export default {
circles.splice(0, circles.length)
},
createControls () {
const maps = this._maps
var _self = this
var map = this._map
var controls = this.controlsSync
......@@ -814,6 +562,7 @@ export default {
controls.splice(0, controls.length)
},
createLocation () {
const maps = this._maps
var map = this._map
var location = this._location
if (location) {
......@@ -879,6 +628,7 @@ export default {
}
},
fitBounds (points, cb) {
const maps = this._maps
this.boundsReady(() => {
var map = this._map
var bounds = new maps.LatLngBounds()
......@@ -914,14 +664,11 @@ export default {
}
},
getMarker (id) {
var markers = this.markersSync
for (var index = 0; index < markers.length; index++) {
var element = markers[index]
if (element.id === id) {
return element
}
var marker = this._markers[id]
if (!marker) {
throw new Error('translateMarker: fail cannot find marker with id ' + id)
}
throw new Error('translateMarker: fail cannot find marker with id ' + id)
return marker
}
}
}
......
import getRealPath from 'uni-platform/helpers/get-real-path'
export default {
props: {
id: {
type: [Number, String],
default: ''
},
latitude: {
type: [Number, String],
require: true
},
longitude: {
type: [Number, String],
require: true
},
title: {
type: String,
default: ''
},
iconPath: {
type: String,
require: true
},
rotate: {
type: [Number, String],
default: 0
},
alpha: {
type: [Number, String],
default: 1
},
width: {
type: [Number, String],
default: ''
},
height: {
type: [Number, String],
default: ''
},
callout: {
type: Object,
default: null
},
label: {
type: Object,
default: null
},
anchor: {
type: Object,
default: null
},
clusterId: {
type: [Number, String],
default: ''
},
customCallout: {
type: Object,
default: null
},
ariaLabel: {
type: String,
default: ''
}
},
mounted () {
const $parent = this.$parent
$parent.mapReady(() => {
this._maps = $parent._maps
this._map = $parent._map
this.addMarker(this.$props)
Object.keys(this.$props).forEach(key => {
this.$watch(key, () => {
this.updateMarker(this.$props)
})
})
})
},
beforeDestroy () {
this.removeMarker()
},
methods: {
addMarker (props) {
const maps = this._maps
const map = this._map
const marker = this._marker = new maps.Marker({
map,
flat: true,
autoRotation: false
})
this.$parent._markers[this.id] = marker
this.updateMarker(props)
maps.event.addListener(marker, 'click', () => {
const callout = marker.callout
if (callout) {
const div = callout.div
const parent = div.parentNode
if (!callout.alwaysVisible) {
callout.set('visible', !callout.visible)
}
if (callout.visible) {
parent.removeChild(div)
parent.appendChild(div)
}
}
if (this.id) {
this.$parent.$trigger('markertap', {}, {
markerId: this.id
})
}
})
},
updateMarker (option) {
const map = this._map
const maps = this._maps
const marker = this._marker
const title = option.title
const position = new maps.LatLng(option.latitude, option.longitude)
const img = new Image()
img.onload = () => {
const anchor = option.anchor || {}
let icon
let w
let h
const x = typeof anchor.x === 'number' ? anchor.x : 0.5
const y = typeof anchor.y === 'number' ? anchor.y : 1
if (option.iconPath && (option.width || option.height)) {
w = option.width || (img.width / img.height) * option.height
h = option.height || (img.height / img.width) * option.width
} else {
w = img.width / 2
h = img.height / 2
}
const top = h - (h - y)
if ('MarkerImage' in maps) {
icon = new maps.MarkerImage(
img.src,
null,
null,
new maps.Point(x * w, y * h),
new maps.Size(w, h)
)
} else {
icon = {
url: img.src,
anchor: new maps.Point(x, y),
size: new maps.Size(w, h)
}
}
marker.setPosition(position)
marker.setIcon(icon)
if ('setRotation' in marker) {
marker.setRotation(option.rotate || 0)
}
const labelOpt = option.label || {}
if ('label' in marker) {
marker.label.setMap(null)
delete marker.label
}
let label
if (labelOpt.content) {
if ('Label' in maps) {
label = new maps.Label({
position: position,
map: map,
clickable: false,
content: labelOpt.content,
style: {
border: 'none',
padding: '8px',
background: 'none',
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + 'px',
lineHeight: (labelOpt.fontSize || 14) + 'px',
marginLeft: labelOpt.x,
marginTop: labelOpt.y
}
})
marker.label = label
} else if ('setLabel' in marker) {
marker.setLabel({
text: labelOpt.content,
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + 'px'
})
}
}
const calloutOpt = option.callout || {}
let callout = marker.callout
let calloutStyle
if (calloutOpt.content || title) {
calloutStyle = calloutOpt.content
? {
position,
map,
top,
content: calloutOpt.content,
color: calloutOpt.color,
fontSize: calloutOpt.fontSize,
borderRadius: calloutOpt.borderRadius,
bgColor: calloutOpt.bgColor,
padding: calloutOpt.padding,
boxShadow: calloutOpt.boxShadow,
display: calloutOpt.display
}
: {
position,
map,
top,
content: title,
boxShadow: '0px 0px 3px 1px rgba(0,0,0,0.5)'
}
if (callout) {
callout.setOption(calloutStyle)
} else {
callout = marker.callout = new maps.Callout(calloutStyle)
callout.div.onclick = function ($event) {
if (this.id !== '') {
this.$parent.$trigger('callouttap', $event, {
markerId: this.id
})
}
$event.stopPropagation()
$event.preventDefault()
}
}
} else {
if (callout) {
callout.setMap(null)
delete marker.callout
}
}
}
img.src = getRealPath(option.iconPath)
},
removeMarker () {
const marker = this._marker
if (marker) {
if (marker.label) {
marker.label.setMap(null)
}
if (marker.callout) {
marker.callout.setMap(null)
}
marker.setMap(null)
}
delete this.$parent._markers[this.id]
this._marker = null
}
},
render () {
return null
}
}
export function createCallout (maps) {
const overlay = new (maps.OverlayView || maps.Overlay)()
function onAdd () {
const div = this.div
const panes = this.getPanes()
panes.floatPane.appendChild(div)
}
function onRemove () {
const parentNode = this.div.parentNode
if (parentNode) {
parentNode.removeChild(this.div)
}
}
class Callout {
option
position
index
visible
alwaysVisible
div
triangle
set onclick (callback) {
this.div.onclick = callback
}
get onclick () {
return this.div.onclick
}
constructor (option = {}) {
this.option = option || {}
const map = option.map
this.position = option.position
this.index = 1
const visible = (this.visible = this.alwaysVisible = option.display === 'ALWAYS')
const div = (this.div = document.createElement('div'))
const divStyle = div.style
divStyle.position = 'absolute'
divStyle.whiteSpace = 'nowrap'
divStyle.transform = 'translateX(-50%) translateY(-100%)'
divStyle.zIndex = '1'
divStyle.boxShadow = option.boxShadow || 'none'
divStyle.display = visible ? 'block' : 'none'
const triangle = (this.triangle = document.createElement('div'))
triangle.setAttribute(
'style',
'position: absolute;white-space: nowrap;border-width: 4px;border-style: solid;border-color: #fff transparent transparent;border-image: initial;font-size: 12px;padding: 0px;background-color: transparent;width: 0px;height: 0px;transform: translate(-50%, 100%);left: 50%;bottom: 0;'
)
this.setStyle(option)
div.appendChild(triangle)
if (map) {
this.setMap(map)
}
}
onAdd = onAdd
construct = onAdd
setOption (option) {
this.option = option
this.setPosition(option.position)
if (option.display === 'ALWAYS') {
this.alwaysVisible = this.visible = true
} else {
this.alwaysVisible = false
}
this.setStyle(option)
}
setStyle (option) {
const div = this.div
const divStyle = div.style
div.innerText = option.content || ''
divStyle.lineHeight = (option.fontSize || 14) + 'px'
divStyle.fontSize = (option.fontSize || 14) + 'px'
divStyle.padding = (option.padding || 8) + 'px'
divStyle.color = option.color || '#000'
divStyle.borderRadius = (option.borderRadius || 0) + 'px'
divStyle.backgroundColor = option.bgColor || '#fff'
divStyle.marginTop = '-' + ((option.top || 0) + 5) + 'px'
this.triangle.style.borderColor = `${option.bgColor || '#fff'} transparent transparent`
}
setPosition (position) {
this.position = position
this.draw()
}
draw () {
const overlayProjection = this.getProjection()
if (!this.position || !this.div || !overlayProjection) {
return
}
const pixel = overlayProjection.fromLatLngToDivPixel(this.position)
const divStyle = this.div.style
divStyle.left = pixel.x + 'px'
divStyle.top = pixel.y + 'px'
}
changed () {
const divStyle = this.div.style
divStyle.display = this.visible ? 'block' : 'none'
}
onRemove = onRemove
destroy = onRemove
}
Callout.prototype = overlay
return Callout
}
import {
MapType,
getMapInfo
} from '../../../../helpers/location'
import { createCallout } from './callout'
let maps
const callbacksMap = {}
const GOOGLE_MAP_CALLBACKNAME = '__map_callback__'
export function loadMaps (libraries, callback) {
const mapInfo = getMapInfo()
if (!mapInfo.key) {
console.error('Map key not configured.')
return
}
const callbacks = (callbacksMap[mapInfo.type] = callbacksMap[mapInfo.type] || [])
if (maps) {
callback(maps)
} else if (
window[mapInfo.type] &&
window[mapInfo.type].maps
) {
maps = window[mapInfo.type].maps
maps.Callout = maps.Callout || createCallout(maps)
callback(maps)
} else if (callbacks.length) {
callbacks.push(callback)
} else {
callbacks.push(callback)
const globalExt = window
const callbackName = GOOGLE_MAP_CALLBACKNAME + mapInfo.type
globalExt[callbackName] = function () {
delete globalExt[callbackName]
maps = window[mapInfo.type].maps
maps.Callout = createCallout(maps)
callbacks.forEach((callback) => callback(maps))
callbacks.length = 0
}
const script = document.createElement('script')
let src =
mapInfo.type === MapType.GOOGLE ? 'https://maps.googleapis.com/maps/api/js?' : 'https://map.qq.com/api/js?v=2.exp&'
if (mapInfo.type === MapType.QQ) {
libraries.push('geometry')
}
if (libraries.length) {
src += `libraries=${libraries.join('%2C')}&`
}
script.src = `${src}key=${mapInfo.key}&callback=${callbackName}`
script.onerror = function () {
console.error('Map load failed.')
}
document.body.appendChild(script)
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册