提交 37390661 编写于 作者: Q qiang

feat(h5): google map

上级 85ec55ff
......@@ -59,6 +59,7 @@ declare namespace UniApp {
tabBar?: TabBarOptions
subPackages?: { root: string }[]
qqMapKey?: string
googleMapKey?: string
// app-plus
entryPagePath?: string
entryPageQuery?: string
......
......@@ -20,8 +20,6 @@ const defaultAsync = {
suspensible: true,
}
const defaultQQMapKey = 'XVXBZ-NDMC4-JOGUS-XGIEE-QVHDZ-AMFV2'
export function uniManifestJsonPlugin(): Plugin {
return defineUniManifestJsonPlugin((opts) => {
return {
......@@ -45,10 +43,12 @@ export function uniManifestJsonPlugin(): Plugin {
const sdkConfigs = (h5 && h5.sdkConfigs) || {}
const qqMapKey =
(sdkConfigs.maps &&
sdkConfigs.maps.qqmap &&
sdkConfigs.maps.qqmap.key) ||
defaultQQMapKey
sdkConfigs.maps && sdkConfigs.maps.qqmap && sdkConfigs.maps.qqmap.key
const googleMapKey =
sdkConfigs.maps &&
sdkConfigs.maps.google &&
sdkConfigs.maps.google.key
let locale: string | null | undefined = manifest.locale
locale = locale && locale.toUpperCase() !== 'AUTO' ? locale : ''
......@@ -77,7 +77,8 @@ export function uniManifestJsonPlugin(): Plugin {
// h5
export const router = ${JSON.stringify(router)}
export const async = ${JSON.stringify(async)}
export const qqMapKey = '${qqMapKey}'
export const qqMapKey = ${JSON.stringify(qqMapKey)}
export const googleMapKey = ${JSON.stringify(googleMapKey)}
export const sdkConfigs = ${JSON.stringify(sdkConfigs)}
export const locale = '${locale}'
export const fallbackLocale = '${fallbackLocale}'
......
......@@ -55,7 +55,7 @@ function generatePagesJsonCode(
return `
import { defineAsyncComponent, resolveComponent, createVNode, withCtx, openBlock, createBlock } from 'vue'
import { PageComponent, AsyncLoadingComponent, AsyncErrorComponent, useI18n, setupWindow } from '@dcloudio/uni-h5'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, nvue, locale, fallbackLocale } from '${manifestJsonPath}'
import { appid, debug, networkTimeout, router, async, sdkConfigs, qqMapKey, googleMapKey, nvue, locale, fallbackLocale } from '${manifestJsonPath}'
const locales = import.meta.globEager('./locale/*.json')
${importLayoutComponentsCode}
const extend = Object.assign
......@@ -259,6 +259,7 @@ delete ${globalName}['____'+appid+'____']
networkTimeout,
sdkConfigs,
qqMapKey,
googleMapKey,
nvue,
locale,
fallbackLocale,
......
......@@ -7652,6 +7652,11 @@ var index$d = /* @__PURE__ */ defineBuiltInComponent({
};
}
});
var MapType;
(function(MapType2) {
MapType2["QQ"] = "qq";
MapType2["GOOGLE"] = "google";
})(MapType || (MapType = {}));
const props$6 = {
id: {
type: [Number, String],
......@@ -7732,8 +7737,8 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
let w;
let h;
let top;
let x = anchor.x;
let y = anchor.y;
let x = typeof anchor.x === "number" ? anchor.x : 0.5;
let 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;
......@@ -7741,37 +7746,53 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
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));
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);
marker.setRotation(option.rotate || 0);
if ("setRotation" in marker) {
marker.setRotation(option.rotate || 0);
}
const labelOpt = option.label || {};
if (marker.label) {
if ("label" in marker) {
marker.label.setMap(null);
delete marker.label;
}
let label;
if (labelOpt.content) {
label = new maps.Label({
position,
map,
clickable: false,
content: labelOpt.content,
style: {
border: "none",
padding: "8px",
background: "none",
if ("Label" in maps) {
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;
} else if ("setLabel" in marker) {
marker.setLabel({
text: labelOpt.content,
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + "px",
lineHeight: (labelOpt.fontSize || 14) + "px",
marginLeft: labelOpt.x,
marginTop: labelOpt.y
}
});
marker.label = label;
fontSize: (labelOpt.fontSize || 14) + "px"
});
}
}
const calloutOpt = option.callout || {};
let callout = marker.callout;
......@@ -7860,7 +7881,10 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
const duration = data.duration;
const autoRotate = !!data.autoRotate;
let rotate = Number(data.rotate) || 0;
const rotation = marker.getRotation();
let rotation = 0;
if ("getRotation" in marker) {
rotation = marker.getRotation();
}
const a = marker.getPosition();
const b = new maps.LatLng(destination.latitude, destination.longitude);
const distance = maps.geometry.spherical.computeDistanceBetween(a, b) / 1e3;
......@@ -7902,8 +7926,15 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
}
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", {});
}
});
}
};
......@@ -8062,11 +8093,14 @@ var MapCircle = /* @__PURE__ */ defineSystemComponent({
const center = new maps.LatLng(option.latitude, option.longitude);
function getColor(color) {
const 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 void 0;
if ("Color" in maps) {
if (c && c.length) {
return maps.Color.fromHex(c[0], Number("0x" + c[1] || 255) / 255).toRGBA();
} else {
return void 0;
}
}
return color;
}
circle = new maps.Circle({
map,
......@@ -8250,6 +8284,20 @@ function getPoints(points) {
}
return newPoints;
}
function getLat(latLng) {
if ("getLat" in latLng) {
return latLng.getLat();
} else {
return latLng.lat();
}
}
function getLng(latLng) {
if ("getLng" in latLng) {
return latLng.getLng();
} else {
return latLng.lng();
}
}
function useMap(props2, rootRef, emit2) {
const mapRef = vue.ref(null);
let maps;
......@@ -8303,8 +8351,8 @@ function useMap(props2, rootRef, emit2) {
onMapReady(() => {
const center = map.getCenter();
uniShared.callOptions(data, {
latitude: center.getLat(),
longitude: center.getLng(),
latitude: getLat(center),
longitude: getLng(center),
errMsg: `${type}:ok`
});
});
......@@ -8363,12 +8411,12 @@ function useMap(props2, rootRef, emit2) {
const northeast = latLngBounds.getNorthEast();
uniShared.callOptions(data, {
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)
},
errMsg: `${type}:ok`
});
......
......@@ -588,14 +588,14 @@ function attrChange(attr2) {
style[attr3] = elementComputedStyle[attr3];
});
changeAttrs.length = 0;
callbacks$1.forEach(function(callback) {
callbacks.forEach(function(callback) {
callback(style);
});
}, 0);
}
changeAttrs.push(attr2);
}
var callbacks$1 = [];
var callbacks = [];
function onChange(callback) {
if (!getSupport()) {
return;
......@@ -604,13 +604,13 @@ function onChange(callback) {
init();
}
if (typeof callback === "function") {
callbacks$1.push(callback);
callbacks.push(callback);
}
}
function offChange(callback) {
var index2 = callbacks$1.indexOf(callback);
var index2 = callbacks.indexOf(callback);
if (index2 >= 0) {
callbacks$1.splice(index2, 1);
callbacks.splice(index2, 1);
}
}
var safeAreaInsets = {
......@@ -14741,7 +14741,18 @@ function useWebViewSize(rootRef, iframeRef) {
return _resize;
}
function createCallout(maps2) {
const overlay = new maps2.Overlay();
const overlay = new (maps2.OverlayView || maps2.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 {
constructor(option = {}) {
this.setMap = overlay.setMap;
......@@ -14751,13 +14762,18 @@ function createCallout(maps2) {
this.map_changed = overlay.map_changed;
this.set = overlay.set;
this.get = overlay.get;
this.setOptions = overlay.setOptions;
this.setOptions = overlay.setValues;
this.bindTo = overlay.bindTo;
this.bindsTo = overlay.bindsTo;
this.notify = overlay.notify;
this.setValues = overlay.setValues;
this.unbind = overlay.unbind;
this.unbindAll = overlay.unbindAll;
this.addListener = overlay.addListener;
this.onAdd = onAdd;
this.construct = onAdd;
this.onRemove = onRemove;
this.destroy = onRemove;
this.option = option || {};
const map = option.map;
this.position = option.position;
......@@ -14785,11 +14801,6 @@ function createCallout(maps2) {
get onclick() {
return this.div.onclick;
}
construct() {
const div = this.div;
const panes = this.getPanes();
panes.floatPane.appendChild(div);
}
setOption(option) {
this.option = option;
this.setPosition(option.position);
......@@ -14831,39 +14842,56 @@ function createCallout(maps2) {
const divStyle = this.div.style;
divStyle.display = this.visible ? "block" : "none";
}
destroy() {
const parentNode = this.div.parentNode;
if (parentNode) {
parentNode.removeChild(this.div);
}
}
}
return Callout;
}
var MapType;
(function(MapType2) {
MapType2["QQ"] = "qq";
MapType2["GOOGLE"] = "google";
})(MapType || (MapType = {}));
let maps;
const callbacks = [];
const QQ_MAP_CALLBACKNAME = "__qq_map_callback__";
const callbacksMap = {};
const GOOGLE_MAP_CALLBACKNAME = "__map_callback__";
function loadMaps(callback) {
let type;
let key;
if (__uniConfig.qqMapKey) {
type = MapType.QQ;
key = __uniConfig.qqMapKey;
} else if (__uniConfig.googleMapKey) {
type = MapType.GOOGLE;
key = __uniConfig.googleMapKey;
} else {
console.error("Map key not configured.");
return;
}
const callbacks2 = callbacksMap[type] = callbacksMap[type] || [];
if (maps) {
callback(maps);
} else if (window.qq && window.qq.maps) {
maps = window.qq.maps;
} else if (window[type] && window[type].maps) {
maps = window[type].maps;
maps.Callout = maps.Callout || createCallout(maps);
callback(maps);
} else if (callbacks.length) {
callbacks.push(callback);
} else if (callbacks2.length) {
callbacks2.push(callback);
} else {
callbacks.push(callback);
const key = __uniConfig.qqMapKey;
callbacks2.push(callback);
const globalExt = window;
globalExt[QQ_MAP_CALLBACKNAME] = function() {
delete globalExt[QQ_MAP_CALLBACKNAME];
maps = window.qq.maps;
const callbackName = GOOGLE_MAP_CALLBACKNAME + type;
globalExt[callbackName] = function() {
delete globalExt[callbackName];
maps = window[type].maps;
maps.Callout = createCallout(maps);
callbacks.forEach((callback2) => callback2(maps));
callbacks.length = 0;
callbacks2.forEach((callback2) => callback2(maps));
callbacks2.length = 0;
};
const script = document.createElement("script");
script.src = `https://map.qq.com/api/js?v=2.exp&key=${key}&callback=${QQ_MAP_CALLBACKNAME}&libraries=geometry`;
const src = type === MapType.GOOGLE ? "https://maps.googleapis.com/maps/api/js?" : "https://map.qq.com/api/js?v=2.exp&libraries=geometry&";
script.src = `${src}key=${key}&callback=${callbackName}`;
script.onerror = function() {
console.error("Map load failed.");
};
document.body.appendChild(script);
}
}
......@@ -14958,8 +14986,8 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
let w;
let h;
let top;
let x = anchor.x;
let y = anchor.y;
let x = typeof anchor.x === "number" ? anchor.x : 0.5;
let 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;
......@@ -14967,37 +14995,53 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
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 maps2.MarkerImage(img.src, null, null, new maps2.Point(x, y), new maps2.Size(w, h));
if ("MarkerImage" in maps2) {
icon = new maps2.MarkerImage(img.src, null, null, new maps2.Point(x * w, y * h), new maps2.Size(w, h));
} else {
icon = {
url: img.src,
anchor: new maps2.Point(x, y),
size: new maps2.Size(w, h)
};
}
marker.setPosition(position);
marker.setIcon(icon);
marker.setRotation(option.rotate || 0);
if ("setRotation" in marker) {
marker.setRotation(option.rotate || 0);
}
const labelOpt = option.label || {};
if (marker.label) {
if ("label" in marker) {
marker.label.setMap(null);
delete marker.label;
}
let label;
if (labelOpt.content) {
label = new maps2.Label({
position,
map,
clickable: false,
content: labelOpt.content,
style: {
border: "none",
padding: "8px",
background: "none",
if ("Label" in maps2) {
label = new maps2.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;
} else if ("setLabel" in marker) {
marker.setLabel({
text: labelOpt.content,
color: labelOpt.color,
fontSize: (labelOpt.fontSize || 14) + "px",
lineHeight: (labelOpt.fontSize || 14) + "px",
marginLeft: labelOpt.x,
marginTop: labelOpt.y
}
});
marker.label = label;
fontSize: (labelOpt.fontSize || 14) + "px"
});
}
}
const calloutOpt = option.callout || {};
let callout = marker.callout;
......@@ -15086,7 +15130,10 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
const duration = data.duration;
const autoRotate = !!data.autoRotate;
let rotate = Number(data.rotate) || 0;
const rotation = marker.getRotation();
let rotation = 0;
if ("getRotation" in marker) {
rotation = marker.getRotation();
}
const a2 = marker.getPosition();
const b = new maps2.LatLng(destination.latitude, destination.longitude);
const distance2 = maps2.geometry.spherical.computeDistanceBetween(a2, b) / 1e3;
......@@ -15128,8 +15175,15 @@ var MapMarker = /* @__PURE__ */ defineSystemComponent({
}
rotate = maps2.geometry.spherical.computeHeading(a2, 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);
maps2.event.trigger(marker, "moveend", {});
}
});
}
};
......@@ -15291,11 +15345,14 @@ var MapCircle = /* @__PURE__ */ defineSystemComponent({
const center = new maps2.LatLng(option.latitude, option.longitude);
function getColor(color) {
const c = color.match(/#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?/);
if (c && c.length) {
return maps2.Color.fromHex(c[0], Number("0x" + c[1] || 255) / 255);
} else {
return void 0;
if ("Color" in maps2) {
if (c && c.length) {
return maps2.Color.fromHex(c[0], Number("0x" + c[1] || 255) / 255).toRGBA();
} else {
return void 0;
}
}
return color;
}
circle = new maps2.Circle({
map,
......@@ -19356,6 +19413,20 @@ function getPoints(points) {
}
return newPoints;
}
function getLat(latLng) {
if ("getLat" in latLng) {
return latLng.getLat();
} else {
return latLng.lat();
}
}
function getLng(latLng) {
if ("getLng" in latLng) {
return latLng.getLng();
} else {
return latLng.lng();
}
}
function useMap(props2, rootRef, emit2) {
const trigger = useCustomEvent(rootRef, emit2);
const mapRef = ref(null);
......@@ -19425,8 +19496,8 @@ function useMap(props2, rootRef, emit2) {
return {
scale: map.getZoom(),
centerLocation: {
latitude: center.getLat(),
longitude: center.getLng()
latitude: getLat(center),
longitude: getLng(center)
}
};
}
......@@ -19455,6 +19526,9 @@ function useMap(props2, rootRef, emit2) {
zoomControl: false,
scaleControl: false,
panControl: false,
fullscreenControl: false,
streetViewControl: false,
keyboardShortcuts: false,
minZoom: 5,
maxZoom: 18,
draggable: true
......@@ -19496,8 +19570,8 @@ function useMap(props2, rootRef, emit2) {
});
maps2.event.addListener(map2, "center_changed", () => {
const center2 = map2.getCenter();
const latitude = center2.getLat();
const longitude = center2.getLng();
const latitude = getLat(center2);
const longitude = getLng(center2);
emit2("update:latitude", latitude);
emit2("update:longitude", longitude);
});
......@@ -19511,8 +19585,8 @@ function useMap(props2, rootRef, emit2) {
onMapReady(() => {
const center = map.getCenter();
callOptions(data, {
latitude: center.getLat(),
longitude: center.getLng(),
latitude: getLat(center),
longitude: getLng(center),
errMsg: `${type}:ok`
});
});
......@@ -19573,12 +19647,12 @@ function useMap(props2, rootRef, emit2) {
const northeast = latLngBounds.getNorthEast();
callOptions(data, {
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)
},
errMsg: `${type}:ok`
});
......
......@@ -27,5 +27,8 @@
"safe-area-insets": "^1.4.1",
"xmlhttprequest": "^1.8.0"
},
"gitHead": "453a3e6ead807864087692f4339ea3d667045fe7"
"gitHead": "453a3e6ead807864087692f4339ea3d667045fe7",
"devDependencies": {
"@types/google.maps": "^3.45.6"
}
}
import { inject, onUnmounted, watch } from 'vue'
import { defineSystemComponent, useCustomEvent } from '@dcloudio/uni-components'
import { Map, Circle } from './qqMap/types'
import { QQMapsExt } from './qqMap'
import { Maps, Map, Circle } from './maps'
const props = {
latitude: { type: [Number, String], require: true },
......@@ -17,7 +16,7 @@ export type Props = Partial<Record<keyof typeof props, any>>
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
type OnMapReady = (callback: OnMapReadyCallback) => void
......@@ -42,15 +41,21 @@ export default /*#__PURE__*/ defineSystemComponent({
const center = new maps.LatLng(option.latitude, option.longitude)
function getColor(color: string) {
const 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
if ('Color' in maps) {
if (c && c.length) {
return maps.Color.fromHex(
c[0],
Number('0x' + c[1] || 255) / 255
).toRGBA()
} else {
return undefined
}
}
return color
}
circle = new maps.Circle({
map,
center,
map: map as any,
center: center as any,
clickable: false,
radius: option.radius,
strokeWeight: Number(option.strokeWidth) || 1,
......
import { inject, onUnmounted, watch, PropType } from 'vue'
import { getRealPath } from '@dcloudio/uni-platform'
import { defineSystemComponent, useCustomEvent } from '@dcloudio/uni-components'
import { Map } from './qqMap/types'
import { QQMapsExt } from './qqMap'
import { Maps, Map } from './maps'
interface Position {
left: number | string
......@@ -22,7 +21,7 @@ export type Props = Partial<Record<keyof typeof props, any>>
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
type OnMapReady = (callback: OnMapReadyCallback) => void
......
......@@ -7,14 +7,13 @@ import {
getLocation,
} from '../../../service/api'
//#endif
import { Map } from './qqMap/types'
import { QQMapsExt } from './qqMap'
import { Maps, Map } from './maps'
import MapMarker from './MapMarker'
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
type OnMapReady = (callback: OnMapReadyCallback) => void
......
import { onUnmounted, inject, watch } from 'vue'
import { getRealPath } from '@dcloudio/uni-platform'
import { defineSystemComponent, useCustomEvent } from '@dcloudio/uni-components'
import { Map, Marker, Label, LatLng } from './qqMap/types'
import { Callout, CalloutOptions, QQMapsExt } from './qqMap'
import { Maps, Map, LatLng, Callout, CalloutOptions } from './maps'
import {
Map as GMap,
LatLng as GLatLng,
Marker as GMarker,
Label as GLabel,
Icon,
} from './maps/google/types'
import {
Map as QMap,
LatLng as QLatLng,
Marker as QMarker,
Label as QLabel,
MarkerImage,
} from './maps/qq/types'
const props = {
id: {
......@@ -74,7 +87,7 @@ export type Props = Partial<Record<keyof typeof props, any>>
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
type OnMapReady = (callback: OnMapReadyCallback) => void
......@@ -92,11 +105,15 @@ export interface Context {
type AddMapChidlContext = (context: Context) => void
type RemoveMapChidlContext = (context: Context) => void
interface MarkerExt extends Marker {
type Label = GLabel | QLabel
interface MarkerExt {
callout?: InstanceType<Callout>
label?: Label
lastPosition?: LatLng
}
interface GMarkerExt extends GMarker, MarkerExt {}
interface QMarkerExt extends QMarker, MarkerExt {}
type Marker = GMarkerExt | QMarkerExt
export default /*#__PURE__*/ defineSystemComponent({
name: 'MapMarker',
......@@ -104,11 +121,11 @@ export default /*#__PURE__*/ defineSystemComponent({
setup(props) {
const id = String(Number(props.id) !== NaN ? props.id : '')
const onMapReady: OnMapReady = inject('onMapReady') as OnMapReady
let marker: MarkerExt
let marker: Marker
function removeMarker() {
if (marker) {
if (marker.label) {
marker.label.setMap(null)
;(marker.label as QLabel).setMap(null)
}
if (marker.callout) {
marker.callout.setMap(null)
......@@ -123,12 +140,12 @@ export default /*#__PURE__*/ defineSystemComponent({
const img = new Image()
img.onload = () => {
const anchor = option.anchor || {}
let icon
let icon: MarkerImage | Icon
let w
let h
let top
let x = anchor.x
let y = anchor.y
let x = typeof anchor.x === 'number' ? anchor.x : 0.5
let 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
......@@ -136,43 +153,59 @@ export default /*#__PURE__*/ defineSystemComponent({
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)
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 as any)
marker.setIcon(icon as any)
if ('setRotation' in marker) {
marker.setRotation(option.rotate || 0)
}
const labelOpt = option.label || {}
if (marker.label) {
marker.label.setMap(null)
if ('label' in marker) {
;(marker.label as QLabel).setMap(null)
delete marker.label
}
let label
if (labelOpt.content) {
label = new maps.Label({
position,
map,
clickable: false,
content: labelOpt.content,
style: {
border: 'none',
padding: '8px',
background: 'none',
if ('Label' in maps) {
label = new maps.Label({
position: position as QLatLng,
map: map as QMap,
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',
lineHeight: (labelOpt.fontSize || 14) + 'px',
marginLeft: labelOpt.x,
marginTop: labelOpt.y,
},
})
marker.label = label
})
}
}
const calloutOpt = option.callout || {}
let callout = marker.callout
......@@ -224,7 +257,7 @@ export default /*#__PURE__*/ defineSystemComponent({
}
function addMarker(props: Props) {
marker = new maps.Marker({
map,
map: map as GMap & QMap,
flat: true,
autoRotation: false,
})
......@@ -267,14 +300,20 @@ export default /*#__PURE__*/ defineSystemComponent({
const duration = data.duration
const autoRotate = !!data.autoRotate
let rotate: number = Number(data.rotate) || 0
const rotation = marker.getRotation()
let rotation = 0
if ('getRotation' in marker) {
rotation = marker.getRotation()
}
const a = marker.getPosition()
const b = new maps.LatLng(
destination.latitude,
destination.longitude
)
const distance =
maps.geometry.spherical.computeDistanceBetween(a, b) / 1000
maps.geometry.spherical.computeDistanceBetween(
a as any,
b as any
) / 1000
const time =
(typeof duration === 'number' ? duration : 1000) /
(1000 * 60 * 60)
......@@ -286,7 +325,7 @@ export default /*#__PURE__*/ defineSystemComponent({
const latLng = e.latLng
const label = marker.label
if (label) {
label.setPosition(latLng)
;(label as QLabel).setPosition(latLng)
}
const callout = marker.callout
if (callout) {
......@@ -297,11 +336,11 @@ export default /*#__PURE__*/ defineSystemComponent({
const event = maps.event.addListener(marker, 'moveend', () => {
event.remove()
movingEvent.remove()
marker.lastPosition = a
marker.setPosition(b)
marker.lastPosition = a!
marker.setPosition(b as any)
const label = marker.label
if (label) {
label.setPosition(b)
;(label as QLabel).setPosition(b as QLatLng)
}
const callout = marker.callout
if (callout) {
......@@ -316,14 +355,23 @@ export default /*#__PURE__*/ defineSystemComponent({
if (autoRotate) {
if (marker.lastPosition) {
lastRtate = maps.geometry.spherical.computeHeading(
marker.lastPosition,
a
marker.lastPosition as any,
a as any
)
}
rotate = maps.geometry.spherical.computeHeading(a, b) - lastRtate
rotate =
maps.geometry.spherical.computeHeading(a as any, b as any) -
lastRtate
}
if ('setRotation' in marker) {
marker.setRotation(rotation + rotate)
}
if ('moveTo' in marker) {
marker.moveTo(b as QLatLng, speed)
} else {
marker.setPosition(b as GLatLng)
maps.event.trigger(marker, 'moveend', {})
}
marker.setRotation(rotation + rotate)
marker.moveTo(b, speed)
})
},
}
......
import { inject, PropType, onUnmounted, watch } from 'vue'
import { defineSystemComponent, useCustomEvent } from '@dcloudio/uni-components'
import { Map, LatLng, Polyline } from './qqMap/types'
import { QQMapsExt } from './qqMap'
import { Maps, Map, LatLng, Polyline } from './maps'
interface Point {
latitude: number
......@@ -30,7 +29,7 @@ export type Props = Partial<Record<keyof typeof props, any>>
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
type OnMapReady = (callback: OnMapReadyCallback) => void
......@@ -62,9 +61,9 @@ export default /*#__PURE__*/ defineSystemComponent({
})
const strokeWeight = Number(option.width) || 1
polyline = new maps.Polyline({
map,
map: map as any,
clickable: false,
path,
path: path as any,
strokeWeight,
strokeColor: option.color || undefined,
strokeDashStyle: option.dottedLine ? 'dash' : 'solid',
......@@ -72,9 +71,9 @@ export default /*#__PURE__*/ defineSystemComponent({
const borderWidth = Number(option.borderWidth) || 0
if (borderWidth) {
polylineBorder = new maps.Polyline({
map,
map: map as any,
clickable: false,
path,
path: path as any,
strokeWeight: strokeWeight + borderWidth * 2,
strokeColor: option.borderColor || undefined,
strokeDashStyle: option.dottedLine ? 'dash' : 'solid',
......
......@@ -16,8 +16,7 @@ import {
useCustomEvent,
} from '@dcloudio/uni-components'
import { callOptions } from '@dcloudio/uni-shared'
import { QQMapsExt, loadMaps } from './qqMap'
import { Map } from './qqMap/types'
import { Maps, Map, loadMaps, LatLng } from './maps'
import MapMarker, {
Props as MapMarkerProps,
Context as MapMarkerContext,
......@@ -110,6 +109,22 @@ function getPoints(points: Point[]): Point[] {
return newPoints
}
function getLat(latLng: LatLng) {
if ('getLat' in latLng) {
return latLng.getLat()
} else {
return latLng.lat()
}
}
function getLng(latLng: LatLng) {
if ('getLng' in latLng) {
return latLng.getLng()
} else {
return latLng.lng()
}
}
function useMap(
props: Props,
rootRef: Ref<HTMLElement | null>,
......@@ -117,7 +132,7 @@ function useMap(
) {
const trigger = useCustomEvent(rootRef, emit)
const mapRef: Ref<HTMLDivElement | null> = ref(null)
let maps: QQMapsExt
let maps: Maps
let map: Map
const state: MapState = reactive({
latitude: Number(props.latitude),
......@@ -127,7 +142,7 @@ function useMap(
type CustomEventTrigger = ReturnType<typeof useCustomEvent>
type OnMapReadyCallback = (
map: Map,
maps: QQMapsExt,
maps: Maps,
trigger: CustomEventTrigger
) => void
const onMapReadyCallbacks: OnMapReadyCallback[] = []
......@@ -172,7 +187,7 @@ function useMap(
state.latitude = latitude
state.longitude = longitude
if (map) {
map.setCenter(new maps.LatLng(latitude, longitude))
map.setCenter(new maps.LatLng(latitude, longitude) as any)
}
}
}
......@@ -195,31 +210,31 @@ function useMap(
onBoundsReadyCallbacks.length = 0
}
function getMapInfo() {
const center = map.getCenter()
const center = map.getCenter()!
return {
scale: map.getZoom(),
centerLocation: {
latitude: center.getLat(),
longitude: center.getLng(),
latitude: getLat(center),
longitude: getLng(center),
},
}
}
function updateCenter() {
map.setCenter(new maps.LatLng(state.latitude, state.longitude))
map.setCenter(new maps.LatLng(state.latitude, state.longitude) as any)
}
function updateBounds() {
const bounds = new maps.LatLngBounds()
state.includePoints.forEach(({ latitude, longitude }) => {
const latLng = new maps.LatLng(latitude, longitude)
bounds.extend(latLng)
bounds.extend(latLng as any)
})
map.fitBounds(bounds)
map.fitBounds(bounds as any)
}
function initMap() {
const mapEl = mapRef.value as HTMLDivElement
const center = new maps.LatLng(state.latitude, state.longitude)
const map = new maps.Map(mapEl, {
center,
center: center as any,
zoom: Number(props.scale),
// scrollwheel: false,
disableDoubleClickZoom: true,
......@@ -227,6 +242,9 @@ function useMap(
zoomControl: false,
scaleControl: false,
panControl: false,
fullscreenControl: false,
streetViewControl: false,
keyboardShortcuts: false,
minZoom: 5,
maxZoom: 18,
draggable: true,
......@@ -291,9 +309,9 @@ function useMap(
)
})
maps.event.addListener(map, 'center_changed', () => {
const center = map.getCenter()
const latitude = center.getLat()
const longitude = center.getLng()
const center = map.getCenter()!
const latitude = getLat(center)
const longitude = getLng(center)
emit('update:latitude', latitude)
emit('update:longitude', longitude)
})
......@@ -307,10 +325,10 @@ function useMap(
switch (type) {
case 'getCenterLocation':
onMapReady(() => {
const center = map.getCenter()
const center = map.getCenter()!
callOptions(data, {
latitude: center.getLat(),
longitude: center.getLng(),
latitude: getLat(center),
longitude: getLng(center),
errMsg: `${type}:ok`,
})
})
......@@ -332,7 +350,7 @@ function useMap(
state.latitude = latitude
state.longitude = longitude
if (map) {
map.setCenter(new maps.LatLng(latitude, longitude))
map.setCenter(new maps.LatLng(latitude, longitude) as any)
}
onMapReady(() => {
callOptions(data, `${type}:ok`)
......@@ -370,17 +388,17 @@ function useMap(
break
case 'getRegion':
onBoundsReady(() => {
const latLngBounds = map.getBounds()
const latLngBounds = map.getBounds()!
const southwest = latLngBounds.getSouthWest()
const northeast = latLngBounds.getNorthEast()
callOptions(data, {
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),
},
errMsg: `${type}:ok`,
})
......@@ -402,7 +420,7 @@ function useMap(
} catch (error) {}
onMounted(() => {
loadMaps((result) => {
maps = result as QQMapsExt
maps = result
map = initMap()
emitMapReady()
trigger('updated', {} as Event, {})
......
import { LatLng, Overlay, QQMaps } from './types'
import { QQMaps, Overlay, LatLng as QLatLng } from './qq/types'
import { GoogleMaps, OverlayView, LatLng as GLatLng } from './google/types'
export interface CalloutOptions {
map?: any
position?: LatLng
position?: GLatLng | QLatLng
display?: 'ALWAYS'
boxShadow?: string
content?: string
......@@ -14,30 +15,50 @@ export interface CalloutOptions {
top?: number
}
export function createCallout(maps: QQMaps) {
const overlay = new maps.Overlay()
class Callout implements Overlay {
export function createCallout(maps: QQMaps | GoogleMaps) {
const overlay: OverlayView | Overlay = new ((maps as GoogleMaps)
.OverlayView || (maps as QQMaps).Overlay)()
function onAdd(this: Callout) {
const div = this.div
const panes = this.getPanes()!
panes.floatPane.appendChild(div)
}
function onRemove(this: Callout) {
const parentNode = this.div.parentNode
if (parentNode) {
parentNode.removeChild(this.div)
}
}
class Callout implements OverlayView, Overlay {
option: CalloutOptions
position?: LatLng
position?: GLatLng | QLatLng
index?: number
visible?: boolean
alwaysVisible?: boolean
div: HTMLDivElement
triangle: HTMLDivElement
// @ts-ignore
setMap = overlay.setMap
// @ts-ignore
getMap = overlay.getMap
// @ts-ignore
getPanes = overlay.getPanes
// @ts-ignore
getProjection = overlay.getProjection
map_changed = overlay.map_changed
map_changed = (overlay as any).map_changed
set = overlay.set
get = overlay.get
setOptions = overlay.setOptions
setOptions = overlay.setValues
bindTo = overlay.bindTo
bindsTo = overlay.bindsTo
bindsTo = (overlay as any).bindsTo
notify = overlay.notify
setValues = overlay.setValues
// @ts-ignore
unbind = overlay.unbind
// @ts-ignore
unbindAll = overlay.unbindAll
addListener = (overlay as any).addListener
set onclick(callback: any) {
this.div.onclick = callback
}
......@@ -72,11 +93,8 @@ export function createCallout(maps: QQMaps) {
this.setMap(map)
}
}
construct() {
const div = this.div
const panes = this.getPanes()
panes.floatPane.appendChild(div)
}
onAdd = onAdd
construct = onAdd
setOption(option: CalloutOptions) {
this.option = option
this.setPosition(option.position)
......@@ -102,7 +120,7 @@ export function createCallout(maps: QQMaps) {
option.bgColor || '#fff'
} transparent transparent`
}
setPosition(position?: LatLng) {
setPosition(position?: GLatLng | QLatLng) {
this.position = position
this.draw()
}
......@@ -111,7 +129,9 @@ export function createCallout(maps: QQMaps) {
if (!this.position || !this.div || !overlayProjection) {
return
}
const pixel = overlayProjection.fromLatLngToDivPixel(this.position)
const pixel = overlayProjection.fromLatLngToDivPixel(
this.position as GLatLng & QLatLng
)!
const divStyle = this.div.style
divStyle.left = pixel.x + 'px'
divStyle.top = pixel.y + 'px'
......@@ -120,12 +140,8 @@ export function createCallout(maps: QQMaps) {
const divStyle = this.div.style
divStyle.display = this.visible ? 'block' : 'none'
}
destroy() {
const parentNode = this.div.parentNode
if (parentNode) {
parentNode.removeChild(this.div)
}
}
onRemove = onRemove
destroy = onRemove
}
return Callout
}
/// <reference types="google.maps" />
export type GoogleMaps = typeof google.maps
export type OverlayView = google.maps.OverlayView
export type LatLng = google.maps.LatLng
export type Polyline = google.maps.Polyline
export type Map = google.maps.Map
export type Marker = google.maps.Marker
export type Label = google.maps.MarkerLabel
export type Circle = google.maps.Circle
export type Icon = google.maps.Icon
export * from './types'
import { QQMaps } from './qq/types'
import { GoogleMaps } from './google/types'
import { createCallout } from './Callout'
export { CalloutOptions } from './Callout'
export type Callout = ReturnType<typeof createCallout>
interface MapsWithCallout {
Callout: Callout
}
interface GoogleMapsWithCallout extends GoogleMaps, MapsWithCallout {}
interface QQMapsWithCallout extends QQMaps, MapsWithCallout {}
export type Maps = GoogleMapsWithCallout | QQMapsWithCallout
export enum MapType {
QQ = 'qq',
GOOGLE = 'google',
}
let maps: Maps
const callbacksMap: Partial<Record<MapType, Array<(maps: Maps) => void>>> = {}
const GOOGLE_MAP_CALLBACKNAME = '__map_callback__'
interface WindowExt extends Window {
[key: string]: any
}
export function loadMaps(callback: (maps: Maps) => void) {
let type: MapType
let key: string
if (__uniConfig.qqMapKey) {
type = MapType.QQ
key = __uniConfig.qqMapKey
} else if (__uniConfig.googleMapKey) {
type = MapType.GOOGLE
key = __uniConfig.googleMapKey
} else {
console.error('Map key not configured.')
return
}
const callbacks = (callbacksMap[type] = callbacksMap[type] || [])
if (maps) {
callback(maps)
} else if ((window as WindowExt)[type] && (window as WindowExt)[type].maps) {
maps = (window as WindowExt)[type].maps
maps.Callout = maps.Callout || createCallout(maps)
callback(maps)
} else if (callbacks.length) {
callbacks.push(callback)
} else {
callbacks.push(callback)
const globalExt = window as WindowExt
const callbackName = GOOGLE_MAP_CALLBACKNAME + type
globalExt[callbackName] = function () {
delete globalExt[callbackName]
maps = (window as WindowExt)[type].maps
maps.Callout = createCallout(maps)
callbacks.forEach((callback) => callback(maps))
callbacks.length = 0
}
const script = document.createElement('script')
const src =
type === MapType.GOOGLE
? 'https://maps.googleapis.com/maps/api/js?'
: 'https://map.qq.com/api/js?v=2.exp&libraries=geometry&'
script.src = `${src}key=${key}&callback=${callbackName}`
script.onerror = function () {
console.error('Map load failed.')
}
document.body.appendChild(script)
}
}
......@@ -3,7 +3,7 @@ class Base {
set(key: string, val: any): void
setOptions(options: any): void
bindTo(a, b, c, e)
bindsTo(a, b, c, e)
bindsTo?: (a, b, c, e) => void
changed(a)
notify(a)
setValues(a)
......@@ -94,7 +94,7 @@ export class Overlay extends Base {
/**
*
*/
map_changed()
map_changed?: () => void
}
export class LatLng {
......
import {
Map as GMap,
LatLng as GLatLng,
Polyline as GPolyline,
Circle as GCircle,
} from './google/types'
import {
Map as QMap,
LatLng as QLatLng,
Polyline as QPolyline,
Circle as QCircle,
} from './qq/types'
export type Map = GMap | QMap
export type LatLng = GLatLng | QLatLng
export type Polyline = GPolyline | QPolyline
export type Circle = GCircle | QCircle
import { QQMaps } from './types'
import { createCallout } from './Callout'
export { CalloutOptions } from './Callout'
export type Callout = ReturnType<typeof createCallout>
export interface QQMapsExt extends QQMaps {
Callout: Callout
}
let maps: QQMapsExt
const callbacks: Array<(maps: QQMaps) => void> = []
const QQ_MAP_CALLBACKNAME = '__qq_map_callback__'
interface WindowExt extends Window {
[key: string]: any
}
export function loadMaps(callback: (maps: QQMaps) => void) {
if (maps) {
callback(maps)
} else if (window.qq && window.qq.maps) {
maps = window.qq.maps
callback(maps)
} else if (callbacks.length) {
callbacks.push(callback)
} else {
callbacks.push(callback)
const key = __uniConfig.qqMapKey
const globalExt = window as WindowExt
globalExt[QQ_MAP_CALLBACKNAME] = function () {
delete globalExt[QQ_MAP_CALLBACKNAME]
maps = window.qq.maps
maps.Callout = createCallout(maps)
callbacks.forEach((callback) => callback(maps))
callbacks.length = 0
}
const script = document.createElement('script')
script.src = `https://map.qq.com/api/js?v=2.exp&key=${key}&callback=${QQ_MAP_CALLBACKNAME}&libraries=geometry`
document.body.appendChild(script)
}
}
......@@ -2452,6 +2452,11 @@
"@types/minimatch" "*"
"@types/node" "*"
"@types/google.maps@^3.45.6":
version "3.45.6"
resolved "https://registry.yarnpkg.com/@types/google.maps/-/google.maps-3.45.6.tgz#441a7bc76424243b307596fc8d282a435a979ebd"
integrity sha512-BzGzxs8UXFxeP8uN/0nRgGbsbpYQxSCKsv/7S8OitU7wwhfFcqQSm5aAcL1nbwueMiJ/VVmIZKPq69s0kX5W+Q==
"@types/graceful-fs@^4.1.2":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册