提交 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
}
}
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.
先完成此消息的编辑!
想要评论请 注册