提交 de1bf858 编写于 作者: D DCloud_LXH

feat(App): map

上级 cd43b9e6
......@@ -7,6 +7,30 @@ import {
CreateMapContextProtocol,
} from '../../protocols/context/context'
const operateMapCallback = (
options: { fail?: Function; success?: Function; complete?: Function },
res: { errMsg: string; [propName: string]: any }
) => {
const errMsg = res.errMsg || ''
if (new RegExp('\\:\\s*fail').test(errMsg)) {
options.fail && options.fail(res)
} else {
options.success && options.success(res)
}
options.complete && options.complete(res)
}
const operateMapWrap = (
id: string,
pageId: number,
type: string,
options?: Data
) => {
operateMap(id, pageId, type, options, (res) => {
options && operateMapCallback(options, res)
})
}
export class MapContext implements UniApp.MapContext {
private id: string
private pageId: number
......@@ -15,22 +39,27 @@ export class MapContext implements UniApp.MapContext {
this.pageId = pageId
}
getCenterLocation(options: any) {
operateMap(this.id, this.pageId, 'getCenterLocation', options)
operateMapWrap(this.id, this.pageId, 'getCenterLocation', options)
}
moveToLocation() {
operateMap(this.id, this.pageId, 'moveToLocation')
operateMapWrap(this.id, this.pageId, 'moveToLocation')
}
getScale(options: any) {
operateMap(this.id, this.pageId, 'getScale', options)
operateMapWrap(this.id, this.pageId, 'getScale', options)
}
getRegion(options: any) {
operateMap(this.id, this.pageId, 'getRegion', options)
operateMapWrap(this.id, this.pageId, 'getRegion', options)
}
includePoints(options: any) {
operateMap(this.id, this.pageId, 'includePoints', options)
operateMapWrap(this.id, this.pageId, 'includePoints', options)
}
translateMarker(options: any) {
operateMap(this.id, this.pageId, 'translateMarker', options)
operateMapWrap(this.id, this.pageId, 'translateMarker', options)
}
$getAppMap() {
if (__PLATFORM__ === 'app') {
return plus.maps.getMapById(this.pageId + '-map-' + this.id)
}
}
addCustomLayer() {}
removeCustomLayer() {}
......@@ -41,8 +70,7 @@ export class MapContext implements UniApp.MapContext {
addMarkers() {}
removeMarkers() {}
moveAlong() {}
openMapAp() {}
$getAppMap() {}
openMapApp() {}
}
export const createMapContext = <API_TYPE_CREATE_MAP_CONTEXT>defineSyncApi(
......
......@@ -8,19 +8,8 @@ import {
export { getBaseSystemInfo } from '../service/api/base/getBaseSystemInfo'
export { requestComponentInfo } from '../service/api/ui/requestComponentInfo'
export { getRealPath } from './getRealPath'
export function operateVideoPlayer(
videoId: string,
pageId: number,
type: string,
data?: unknown
) {}
export function operateMap(
id: string,
pageId: number,
type: string,
data?: unknown
) {}
export { operateVideoPlayer } from '../service/api/context/operateVideoPlayer'
export { operateMap } from '../service/api/context/operateMap'
export function addIntersectionObserver(
args: AddIntersectionObserverArgs,
......
export function operateMap(
id: string,
pageId: number,
type: string,
data?: unknown,
operateMapCallback?: (res: any) => void
) {
UniServiceJSBridge.invokeViewMethod(
'map.' + id,
{
type,
data,
},
pageId,
operateMapCallback
)
}
export function operateVideoPlayer(
videoId: string,
pageId: number,
type: string,
data?: unknown
) {
UniServiceJSBridge.invokeViewMethod(
'video.' + videoId,
{
videoId,
type,
data,
},
pageId
)
}
import { defineBuiltInComponent } from '@dcloudio/uni-components'
import {
Ref,
ref,
watch,
onBeforeUnmount,
computed,
ExtractPropTypes,
} from 'vue'
import { extend } from '@vue/shared'
import {
defineBuiltInComponent,
useCustomEvent,
CustomEventTrigger,
EmitEvent,
useSubscribe,
useContextInfo,
} from '@dcloudio/uni-components'
import { useNativeAttrs, useNative } from '../../../helpers/useNative'
import { getCurrentPageId } from '@dcloudio/uni-core'
import { getRealPath } from '../../../platform/getRealPath'
interface Coordinate {
latitude: number
longitude: number
}
type Coordinates = {
coord: Coordinate
}
const convertCoordinates = (
lng: number,
lat: number,
callback: (res: Coordinates) => void
) => {
callback({
coord: {
latitude: lat,
longitude: lng,
},
})
}
function parseHex(color: string) {
if (color.indexOf('#') !== 0) {
return {
color,
opacity: 1,
}
}
const opacity = color.substr(7, 2)
return {
color: color.substr(0, 7),
opacity: opacity ? Number('0x' + opacity) / 255 : 1,
}
}
interface Marker extends PlusMapsMarker {
id: number
latitude: number
longitude: number
iconPath: string
callout?: { content: string }
label?: { content: string }
}
interface Line extends PlusMapsPolyline {
points: Array<Coordinate>
color?: string
width?: number
}
interface Circle extends PlusMapsCircle, Coordinate {
radius: number
color?: string
fillColor?: string
strokeWidth?: number
}
type Markers = Array<Marker>
type Lines = Array<Line>
type Circles = Array<Circle>
type Control = {
id?: number
position: Data
iconPath: string
clickable: boolean
}
interface Map extends PlusMapsMap {
__markers__: Markers
__markers_map__: Record<string, PlusMapsMarker>
__lines__: Lines
__circles__: Circles
}
const props = {
id: {
type: String,
default: '',
},
latitude: {
type: [Number, String],
default: '',
},
longitude: {
type: [Number, String],
default: '',
},
scale: {
type: [String, Number],
default: 16,
},
markers: {
type: Array,
default() {
return []
},
},
polyline: {
type: Array,
default() {
return []
},
},
circles: {
type: Array,
default() {
return []
},
},
controls: {
type: Array,
default() {
return []
},
},
}
type Props = ExtractPropTypes<typeof props>
export default /*#__PURE__*/ defineBuiltInComponent({
name: 'Map',
props,
emits: ['click', 'regionchange', 'controltap', 'markertap', 'callouttap'],
setup(props, { emit }) {
const rootRef: Ref<HTMLElement | null> = ref(null)
const trigger = useCustomEvent<EmitEvent<typeof emit>>(rootRef, emit)
const containerRef: Ref<HTMLElement | null> = ref(null)
const attrs = useNativeAttrs(props, ['id'])
const { position, hidden, onParentReady } = useNative(containerRef)
let map: Map | undefined
const { _addMarkers, _addMapLines, _addMapCircles, _setMap } =
useMapMethods(props, trigger)
onParentReady(() => {
map = extend(
plus.maps.create(
getCurrentPageId() + '-map-' + (props.id || Date.now()),
Object.assign({}, attrs.value, position)
),
{
__markers__: [],
__markers_map__: {},
__lines__: [],
__circles__: [],
}
)
map.setZoom(parseInt(String(props.scale)))
plus.webview.currentWebview().append(map as any)
if (hidden.value) {
map.hide()
}
map.onclick = (e) => {
trigger('click', {} as Event, e)
}
map.onstatuschanged = (e) => {
trigger('regionchange', {} as Event, {})
}
_setMap(map)
_addMarkers(props.markers as Markers)
_addMapLines(props.polyline as Lines)
_addMapCircles(props.circles as Circles)
watch(
() => attrs.value,
(attrs) => map && map.setStyles(attrs as any),
{ deep: true }
)
watch(
() => position,
(position) => map && map.setStyles(position),
{ deep: true }
)
watch(
() => hidden.value,
(val) => {
map && map[val ? 'hide' : 'show']()
}
)
watch(
() => props.scale,
(val) => {
map && map.setZoom(parseInt(String(val)))
}
)
watch(
[() => props.latitude, () => props.longitude],
([latitude, longitude]) => {
map &&
map.setStyles({
center: new plus.maps.Point!(Number(latitude), Number(longitude)),
})
}
)
watch(
() => props.markers,
(val) => {
_addMarkers(val as Markers, true)
}
)
watch(
() => props.polyline,
(val) => {
_addMapLines(val as Lines)
}
)
watch(
() => props.circles,
(val) => {
_addMapCircles(val as Circles)
}
)
})
const mapControls = computed(() =>
(props.controls as Array<Control>).map((control) => {
const position = { position: 'absolute' }
;['top', 'left', 'width', 'height'].forEach((key) => {
if (control.position[key]) {
;(position as any)[key] = control.position[key] + 'px'
}
})
return {
id: control.id,
iconPath: getRealPath(control.iconPath),
position: position,
}
})
)
onBeforeUnmount(() => {
if (map) {
map.close()
}
})
return () => {
return (
<uni-map ref={rootRef} id={props.id}>
<div ref={containerRef} class="uni-map-container" />
{mapControls.value.map((control, index) => (
<v-uni-cover-image
key={index}
src={control.iconPath}
style={control.position}
auto-size
onClick={() =>
trigger('controltap', {} as Event, { controlId: control.id })
}
/>
))}
<div class="uni-map-slot"></div>
</uni-map>
)
}
},
})
type Callback = (res: any) => void
function useMapMethods(props: Props, trigger: CustomEventTrigger) {
let map: Map
function moveToLocation(
resolve: Callback,
{
longitude,
latitude,
}: { longitude?: Props['longitude']; latitude?: Props['latitude'] } = {}
) {
if (!map) return
map.setCenter(
// @ts-expect-error
new plus.maps.Point(
Number(longitude || props.longitude),
Number(latitude || props.latitude)
)
)
resolve({
errMsg: 'moveToLocation:ok',
})
}
function getCenterLocation(resolve: Callback) {
if (!map) return
map.getCurrentCenter((state, point) => {
resolve({
longitude: point.getLng(),
latitude: point.getLat(),
errMsg: 'getCenterLocation:ok',
})
})
}
function getRegion(resolve: Callback) {
if (!map) return
const rect = map.getBounds()
resolve({
southwest: rect.getSouthWest(),
northeast: rect.getNorthEast(), // 5plus API 名字写错了
errMsg: 'getRegion:ok',
})
}
function getScale(resolve: Callback) {
if (!map) return
resolve({
scale: map.getZoom(),
errMsg: 'getScale:ok',
})
}
function _addMarker(marker: Marker) {
if (!map) return
const {
id,
// title,
latitude,
longitude,
iconPath,
// width,
// height,
// rotate,
// alpha,
callout,
label,
} = marker
convertCoordinates(longitude, latitude, (res) => {
const { latitude, longitude } = res.coord
const nativeMarker = new plus.maps.Marker!(
new plus.maps.Point!(longitude, latitude)
)
if (iconPath) {
nativeMarker.setIcon(getRealPath(iconPath))
}
if (label && label.content) {
nativeMarker.setLabel(label.content as string)
}
let nativeBubble: PlusMapsBubble | undefined = undefined
if (callout && callout.content) {
nativeBubble = new plus.maps.Bubble!(callout.content)
}
if (nativeBubble) {
nativeMarker.setBubble(nativeBubble)
}
if (id || id === 0) {
nativeMarker.onclick = (e) => {
trigger('markertap', {} as Event, {
markerId: id,
})
}
if (nativeBubble) {
nativeBubble.onclick = () => {
trigger('callouttap', {} as Event, {
markerId: id,
})
}
}
}
map.addOverlay(nativeMarker as unknown as PlusMapsOverlay)
// 此处5+文档中PlusMapsMarker对象只有方法,没有属性
// @ts-expect-error
map.__markers__.push(nativeMarker)
map.__markers_map__[id + ''] = nativeMarker
})
}
function _clearMarkers() {
if (!map) return
const markers = map.__markers__
markers.forEach((marker) => {
map.removeOverlay(marker as unknown as PlusMapsOverlay)
})
map.__markers__ = []
map.__markers_map__ = {}
}
function _addMarkers(markers: Markers, clear?: boolean) {
if (clear) {
_clearMarkers()
}
markers.forEach((marker) => {
_addMarker(marker)
})
}
function _addMapLines(lines: Lines) {
if (!map) return
if (map.__lines__.length > 0) {
map.__lines__.forEach((circle) => {
map.removeOverlay(circle as unknown as PlusMapsOverlay)
})
map.__lines__ = []
}
lines.forEach((line: Line) => {
const {
color,
width,
// dottedLine,
// arrowLine,
// arrowIconPath,
// borderColor,
// borderWidth
} = line
const points = line.points.map(
(point) => new plus.maps.Point!(point.longitude, point.latitude)
)
const polyline = new plus.maps.Polyline!(points)
if (color) {
const strokeStyle = parseHex(color)
polyline.setStrokeColor(strokeStyle.color)
polyline.setStrokeOpacity(strokeStyle.opacity)
}
if (width) {
polyline.setLineWidth(width)
}
map.addOverlay(polyline as unknown as PlusMapsOverlay)
// 此处5+文档中PlusMapsPolyline对象只有方法,没有属性
// @ts-expect-error
map.__lines__.push(polyline)
})
}
function _addMapCircles(circles: Circles) {
if (!map) return
if (map.__circles__.length > 0) {
map.__circles__.forEach((circle) => {
map.removeOverlay(circle as unknown as PlusMapsOverlay)
})
map.__circles__ = []
}
circles.forEach((circle) => {
const { latitude, longitude, color, fillColor, radius, strokeWidth } =
circle
const nativeCircle = new plus.maps.Circle!(
new plus.maps.Point!(longitude, latitude),
radius
)
if (color) {
const strokeStyle = parseHex(color)
nativeCircle.setStrokeColor(strokeStyle.color)
nativeCircle.setStrokeOpacity(strokeStyle.opacity)
}
if (fillColor) {
const fillStyle = parseHex(fillColor)
nativeCircle.setFillColor(fillStyle.color)
nativeCircle.setFillOpacity(fillStyle.opacity)
}
if (strokeWidth) {
nativeCircle.setLineWidth(strokeWidth)
}
map.addOverlay(nativeCircle as unknown as PlusMapsOverlay)
// 此处5+文档中PlusMapsCircle对象只有方法,没有属性
// @ts-expect-error
map.__circles__.push(nativeCircle)
})
}
const methods = {
moveToLocation,
getCenterLocation,
getRegion,
getScale,
}
type Method = keyof typeof methods
useSubscribe(
(type, data: any, resolve) => {
methods[type as Method] && methods[type as Method](resolve, data)
},
useContextInfo(),
true
)
return {
_addMarkers,
_addMapLines,
_addMapCircles,
_setMap(_map: Map) {
map = _map
},
}
}
import { UniNodeJSON } from '@dcloudio/uni-shared'
import '../../../../../style/map.css'
import Map from '../../../components/map'
import { UniComponent } from './UniComponent'
......@@ -10,6 +11,14 @@ export class UniMap extends UniComponent {
refNodeId: number,
nodeJson: Partial<UniNodeJSON>
) {
super(id, 'uni-map', Map, parentNodeId, refNodeId, nodeJson)
super(
id,
'uni-map',
Map,
parentNodeId,
refNodeId,
nodeJson,
'.uni-map-slot'
)
}
}
uni-map {
width: 300px;
height: 225px;
display: inline-block;
line-height: 0;
overflow: hidden;
position: relative;
}
uni-map[hidden] {
display: none;
}
.uni-map-container {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
background-color: black;
}
.uni-map-slot {
position: absolute;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
}
\ No newline at end of file
......@@ -2,7 +2,8 @@ export function operateMap(
id: string,
pageId: number,
type: string,
data?: unknown
data?: unknown,
operateMapCallback?: (res: any) => void
) {
UniServiceJSBridge.invokeViewMethod(
'map.' + id,
......@@ -10,6 +11,7 @@ export function operateMap(
type,
data,
},
pageId
pageId,
operateMapCallback
)
}
......@@ -922,10 +922,10 @@
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@dcloudio/types@^2.3.3":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@dcloudio/types/-/types-2.3.4.tgz#24368f30ba9cb865d454fc183caa74f9920bb7ec"
integrity sha512-G86VT8YmlBdeN3Fzsq8QeI47AuKoOBSLkpBWBBilxC032p+lBx7ry/aY5ynriIjuqSVKUYvxA3LJ1DmXXXASmw==
"@dcloudio/types@^2.3.5":
version "2.3.5"
resolved "https://registry.nlark.com/@dcloudio/types/download/@dcloudio/types-2.3.5.tgz#01d1f4880dd6289b34e35792227bda28dd75493e"
integrity sha1-AdH0iA3WKJs041eSInvaKN11ST4=
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册