diff --git a/packages/webpack-uni-pages-loader/lib/platforms/h5.js b/packages/webpack-uni-pages-loader/lib/platforms/h5.js
index af5131e8f6462a5fdd82d57f4f1528d146fce453..6c62e30fbb7daf1fc1249544dad71b27bd884cc2 100644
--- a/packages/webpack-uni-pages-loader/lib/platforms/h5.js
+++ b/packages/webpack-uni-pages-loader/lib/platforms/h5.js
@@ -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},{});
diff --git a/src/platforms/h5/helpers/location.js b/src/platforms/h5/helpers/location.js
new file mode 100644
index 0000000000000000000000000000000000000000..827e89c4a5b99bf45097dade1106a74ab624cf73
--- /dev/null
+++ b/src/platforms/h5/helpers/location.js
@@ -0,0 +1,21 @@
+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
+ }
+}
diff --git a/src/platforms/h5/view/components/map/index.vue b/src/platforms/h5/view/components/map/index.vue
index c6248fd2e70f71518e03c245d7539a84353ecaf3..9088eda478c0b84b85b017cdfa366ea6f2775aa0 100644
--- a/src/platforms/h5/view/components/map/index.vue
+++ b/src/platforms/h5/view/components/map/index.vue
@@ -3,11 +3,25 @@
:id="id"
v-on="$listeners"
>
+
+
@@ -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
}
}
}
diff --git a/src/platforms/h5/view/components/map/map-marker.js b/src/platforms/h5/view/components/map/map-marker.js
new file mode 100644
index 0000000000000000000000000000000000000000..3d47d00f48a521ab6edd618c1d883c38f2e10acc
--- /dev/null
+++ b/src/platforms/h5/view/components/map/map-marker.js
@@ -0,0 +1,254 @@
+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
+ }
+}
diff --git a/src/platforms/h5/view/components/map/maps/callout.js b/src/platforms/h5/view/components/map/maps/callout.js
new file mode 100644
index 0000000000000000000000000000000000000000..3e9f81327b62cc89aa63a1d4a071356635d6d581
--- /dev/null
+++ b/src/platforms/h5/view/components/map/maps/callout.js
@@ -0,0 +1,112 @@
+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
+}
diff --git a/src/platforms/h5/view/components/map/maps/index.js b/src/platforms/h5/view/components/map/maps/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..b284ee4c4c5805d54e020b0ebc330c1dd7c7c144
--- /dev/null
+++ b/src/platforms/h5/view/components/map/maps/index.js
@@ -0,0 +1,55 @@
+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)
+ }
+}