Commit cdc77c41 authored by 郭铭瑶's avatar 郭铭瑶 🤘

文件目录调整&添加线状覆盖物

parent 6f71d48c
...@@ -5,19 +5,21 @@ ...@@ -5,19 +5,21 @@
<div @click="zoomOut">-</div> <div @click="zoomOut">-</div>
<div @click="zoomTo">To</div> <div @click="zoomTo">To</div>
<div @click="move">Move</div> <div @click="move">Move</div>
<div @click="addPoints">Add</div> <div @click="addPoints">Point</div>
<div @click="removePoints">Remove</div> <div @click="addLines">Line</div>
<div @click="removeLayers">Remove</div>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import icon1 from '@/assets/images/icon1.png' import icon1 from '@/assets/images/icon1.png'
import MyMap from '@/map/my-map' import MyMap from '@/my-map/my-map'
import useMap from '@/map' import useMap from '@/my-map'
import { nextTick, onMounted } from 'vue' import { nextTick, onMounted } from 'vue'
let map: MyMap let map: MyMap
let pointsLayer: any let pointsLayer: any
let linesLayer: any
onMounted(async () => { onMounted(async () => {
await nextTick() await nextTick()
...@@ -42,7 +44,7 @@ onMounted(async () => { ...@@ -42,7 +44,7 @@ onMounted(async () => {
map map
.on('load', addControls) .on('load', addControls)
.on('click', (a, b) => console.log('click', a, b)) .on('click', (a, b) => console.log(a, b))
.on('zoom', (e) => console.log('zoom: ', e)) .on('zoom', (e) => console.log('zoom: ', e))
.on('move', (e) => console.log('move: ', e)) .on('move', (e) => console.log('move: ', e))
.on('blur', (e) => console.log('blur: ', e)) .on('blur', (e) => console.log('blur: ', e))
...@@ -101,8 +103,20 @@ function addPoints() { ...@@ -101,8 +103,20 @@ function addPoints() {
}, },
}) })
} }
function removePoints() { function addLines() {
linesLayer = map.add('line', {
data: {
path: [
[0, 0],
[121.59751247938203, 29.835174764721145],
],
text: 'test message',
},
})
}
function removeLayers() {
map.remove(pointsLayer) map.remove(pointsLayer)
map.remove(linesLayer)
} }
</script> </script>
......
import MyMap from './my-map' import MyMap from '../my-map'
import { import {
CallBack, CallBack,
MapConfig, MapConfig,
...@@ -10,19 +10,10 @@ import { ...@@ -10,19 +10,10 @@ import {
ClickCallBack, ClickCallBack,
Controls, Controls,
AIMapConfig, AIMapConfig,
Markers, Layers,
PointData, LayerOption,
} from './types' } from '../types'
import { toLines, toPoints } from './util'
declare const aimap: {
Map: any
accessToken: string
baseApiUrl: string
NavigationControl: any
CompassControl: any
ScaleControl: any
MassMarkerLayer: any
}
export default class AI_Map extends MyMap { export default class AI_Map extends MyMap {
private _clickCb: ClickCallBack | null = null private _clickCb: ClickCallBack | null = null
...@@ -52,7 +43,7 @@ export default class AI_Map extends MyMap { ...@@ -52,7 +43,7 @@ export default class AI_Map extends MyMap {
super(instance) super(instance)
this._setListeners() this._setListeners()
this._setControls() this._setControls()
this._setMarkers() this._setLayers()
} }
/** 设置监听事件 */ /** 设置监听事件 */
...@@ -126,62 +117,28 @@ export default class AI_Map extends MyMap { ...@@ -126,62 +117,28 @@ export default class AI_Map extends MyMap {
this._controls = Object.assign(this._controls, _controls) this._controls = Object.assign(this._controls, _controls)
} }
/** 转化点状覆盖物 */ /** 设置覆盖物 */
private _toPoints(options: PointData) { private _setLayers() {
const { const _markers: Partial<Layers> = {
data, point: (data: LayerOption) => {
size = 20, const layer = new aimap.MassMarkerLayer(toPoints(this.map, data))
icon, // 维智的覆盖物点击事件需特别定义
labelKey, layer.on('click', (e: any) => {
spatialReference = 'gcj02', const arg = {
labelOptions, type: e.type,
} = options center: [e.lngLat.lng, e.lngLat.lat],
const [horizontal, vertical] = labelOptions?.offset || [] event: e.originalEvent,
return { clientX: e.point.x,
map: this.map, clientY: e.point.y,
spatialReference: spatialReference, originData: e,
data: data.map((item, i: number) => {
const x = item.X || item.x || item.gpsx
const y = item.Y || item.y || item.gpsy
if ((x !== 0 && !x) || (y !== 0 && !y)) {
console.error(`add point: 非法的坐标[${x}, ${y}] 存在于数据: ${item}`)
}
const z = item.Z || item.z || item.gpsz || 0
return {
...item,
id: item.id || i,
icon: item.icon ? `icon${i}` : 'icon',
spatialReference: spatialReference || item.spatialReference,
coordinates: z ? [x, y, z] : [x, y],
}
}),
images: data.map((item: any, i: number) => {
return {
id: item.icon ? `icon${i}` : 'icon',
url: item.icon || icon,
} }
}), // 点击覆盖物获取自定义数据
style: { this._clickCb && this._clickCb(arg, e?.features?.[0]?.properties)
'text-field': `{${labelKey}}`, })
'text-color': labelOptions?.color, return layer
// 偏移相比测绘院地图大概小了10倍,且竖直偏移相反
'text-offset': [
horizontal ? horizontal / 10 : 0,
vertical ? vertical / -10 : 0,
],
'icon-anchor': 'center',
'icon-image': ['get', 'icon'],
// size相比测绘院地图大概小了50倍
'icon-size': Array.isArray(size) ? size[0] / 50 : size / 50,
}, },
} line: (data: LayerOption) => {
} const layer = new aimap.MassMarkerLayer(toLines(this.map, data))
/** 设置覆盖物方法 */
private _setMarkers() {
const _markers: Partial<Markers> = {
point: (data: PointData) => {
const layer = new aimap.MassMarkerLayer(this._toPoints(data))
// 维智的覆盖物点击事件需特别定义 // 维智的覆盖物点击事件需特别定义
layer.on('click', (e: any) => { layer.on('click', (e: any) => {
const arg = { const arg = {
...@@ -217,6 +174,6 @@ export default class AI_Map extends MyMap { ...@@ -217,6 +174,6 @@ export default class AI_Map extends MyMap {
}) })
} }
remove(layer: any) { remove(layer: any) {
layer.remove() layer && layer.remove()
} }
} }
import { LayerOption, PointsData } from '../types'
/** 转化点状覆盖物 */
export function toPoints(map: unknown, options: LayerOption) {
const {
data,
size = 20,
icon,
labelKey,
spatialReference = 'gcj02',
labelOptions,
} = options
const [horizontal, vertical] = labelOptions?.offset || []
const result: any = { data: [], images: [] }
const transData = (item: PointsData, i: number) => {
const x = item.X || item.x || item.gpsx
const y = item.Y || item.y || item.gpsy
if ((x !== 0 && !x) || (y !== 0 && !y)) {
console.error(`add point: 非法的坐标[${x}, ${y}] 存在于数据: ${item}`)
}
const z = item.Z || item.z || item.gpsz || 0
result.data.push({
...item,
id: item.id || i,
icon: item.icon ? `icon${i}` : 'icon',
spatialReference: spatialReference || item.spatialReference,
coordinates: z ? [x, y, z] : [x, y],
})
result.images.push({
id: item.icon ? `icon${i}` : 'icon',
url: item.icon || icon,
})
}
if (Array.isArray(data)) {
data.forEach(transData)
} else {
transData(data, 0)
}
return {
map,
spatialReference: spatialReference,
data: result.data,
images: result.images,
style: {
'text-field': `{${labelKey}}`,
'text-color': labelOptions?.color,
// 偏移相比测绘院地图大概小了10倍,且竖直偏移相反
'text-offset': [
horizontal ? horizontal / 10 : 0,
vertical ? vertical / -10 : 0,
],
'icon-anchor': 'center',
'icon-image': ['get', 'icon'],
// size相比测绘院地图大概小了50倍
'icon-size': Array.isArray(size) ? size[0] / 50 : size / 50,
},
}
}
/** 转化线状覆盖物 */
export function toLines(map: unknown, options: LayerOption) {
const {
data,
lineWidth = 3,
color = 'blue',
labelKey,
spatialReference = 'gcj02',
labelOptions,
lineJoin = 'round',
} = options
const [horizontal, vertical] = labelOptions?.offset || []
return {
map,
spatialReference: spatialReference,
data: {
coordinates: Array.isArray(data)
? data.map(({ path }) => path?.map((e) => e))
: data.path,
...data,
},
style: {
'line-width': lineWidth,
'line-color': color,
'line-join': lineJoin,
'text-field': `{${labelKey}}`,
'text-color': labelOptions?.color,
// 偏移相比测绘院地图大概小了10倍,且竖直偏移相反
'text-offset': [
horizontal ? horizontal / 10 : 0,
vertical ? vertical / -10 : 0,
],
},
}
}
...@@ -31,3 +31,20 @@ const whichMap = { ...@@ -31,3 +31,20 @@ const whichMap = {
export default function useMap<K extends keyof typeof whichMap>(key: K) { export default function useMap<K extends keyof typeof whichMap>(key: K) {
return whichMap[key] return whichMap[key]
} }
// function _injectSource(sources: any[]): Promise<unknown[]> {
// const promises = sources.map((source: string, index: number) => {
// return new Promise((resolve) => {
// const id = `_my_map_source${index}`
// if (document.getElementById(id)) return resolve(true)
// const mapSource = document.createElement('script')
// mapSource.type = 'text/javascript'
// mapSource.src = source
// mapSource.setAttribute('id', id)
// document.body.appendChild(mapSource)
// mapSource.onload = () => resolve(true)
// })
// })
// return Promise.all(promises)
// }
declare const SMap: {
Map: any
MapEvent: any
Size: any
Icon: any
Label: any
Marker: any
Polyline: any
OverlayGroup: any
Network: any
Home: any
Zoom: any
Compass: any
Fullscreen: any
LayerListControl: any
MeasureLine: any
MeasureArea: any
BasemapToggle: any
UndergroundSwitch: any
BMapGallery: any
BMapGalleryExpand: any
LngLat: any
}
declare const Plugins: {
MaskBoundary: any
}
declare const aimap: {
Map: any
accessToken: string
baseApiUrl: string
NavigationControl: any
CompassControl: any
ScaleControl: any
MassMarkerLayer: any
}
...@@ -6,15 +6,15 @@ import { ...@@ -6,15 +6,15 @@ import {
ZoomOptions, ZoomOptions,
FocusOptions, FocusOptions,
Location, Location,
Markers, Layers,
PointData, LayerOption,
} from './types' } from './types'
export default abstract class MyMap { export default abstract class MyMap {
protected map protected map
protected _listeners: Listeners protected _listeners: Listeners
protected _controls: Controls protected _controls: Controls
protected _markers: Markers protected _markers: Layers
constructor(instance: any) { constructor(instance: any) {
this.map = instance this.map = instance
...@@ -89,7 +89,8 @@ export default abstract class MyMap { ...@@ -89,7 +89,8 @@ export default abstract class MyMap {
}, },
} }
this._markers = { this._markers = {
point: () => console.error('add:此地图不存在 point 撒点!'), point: () => console.error('add:此地图不存在 point 覆盖物!'),
line: () => console.error('add:此地图不存在 line 覆盖物!'),
} }
} }
...@@ -128,7 +129,7 @@ export default abstract class MyMap { ...@@ -128,7 +129,7 @@ export default abstract class MyMap {
* @param type 覆盖物类型 * @param type 覆盖物类型
* @param data 覆盖物数据 * @param data 覆盖物数据
*/ */
add<K extends keyof Markers>(type: K, data: PointData) { add<K extends keyof Layers>(type: K, data: LayerOption) {
return this._markers[type](data) return this._markers[type](data)
} }
......
import MyMap from './my-map' import MyMap from '../my-map'
import { import {
CallBack, CallBack,
MapConfig, MapConfig,
...@@ -8,35 +8,11 @@ import { ...@@ -8,35 +8,11 @@ import {
FocusOptions, FocusOptions,
Controls, Controls,
SMapConfig, SMapConfig,
Markers, Layers,
PointData, LayerOption,
ClickCallBack, ClickCallBack,
} from './types' } from '../types'
import { toLines, toPoints } from './util'
declare const SMap: {
Map: any
MapEvent: any
Size: any
Icon: any
Label: any
Marker: any
OverlayGroup: any
Network: any
Home: any
Zoom: any
Compass: any
Fullscreen: any
LayerListControl: any
MeasureLine: any
MeasureArea: any
BasemapToggle: any
UndergroundSwitch: any
BMapGallery: any
BMapGalleryExpand: any
}
declare const Plugins: {
MaskBoundary: any
}
export default class S_Map extends MyMap { export default class S_Map extends MyMap {
constructor(config: MapConfig<SMapConfig>) { constructor(config: MapConfig<SMapConfig>) {
...@@ -58,7 +34,7 @@ export default class S_Map extends MyMap { ...@@ -58,7 +34,7 @@ export default class S_Map extends MyMap {
super(instance) super(instance)
this._setListeners() this._setListeners()
this._setControls() this._setControls()
this._setMarkers() this._setLayers()
this.on('load', this._clearFooter) this.on('load', this._clearFooter)
} }
...@@ -221,50 +197,17 @@ export default class S_Map extends MyMap { ...@@ -221,50 +197,17 @@ export default class S_Map extends MyMap {
this._controls = Object.assign(this._controls, _controls) this._controls = Object.assign(this._controls, _controls)
} }
/** 转化点状覆盖物 */ /** 设置覆盖物 */
private _toPoints(options: PointData) { private _setLayers() {
const { data, size = 20, icon, labelKey, labelOptions } = options const _markers: Partial<Layers> = {
point: (data: LayerOption) => {
return data.map((item) => { const layer = new SMap.OverlayGroup(toPoints(data), {})
const iconSize = Array.isArray(size) this.map.add(layer)
? new SMap.Size(...size) return layer
: new SMap.Size(size, size)
const x = item.X || item.x || item.gpsx
const y = item.Y || item.y || item.gpsy
if ((x !== 0 && !x) || (y !== 0 && !y)) {
console.error(`add point: 非法的坐标[${x}, ${y}] 存在于数据: ${item}`)
}
const z = item.Z || item.z || item.gpsz || 0
const result: any = {
icon: {
size: iconSize,
image: item.icon || icon,
}, },
attributes: { ...item }, line: (data: LayerOption) => {
position: z ? [x, y, z] : [x, y], const layer = new SMap.OverlayGroup(toLines(data), {})
} this.map.add(layer)
if (labelKey) {
result.label = new SMap.Label({
text: item[labelKey] + '',
size: labelOptions?.size,
color: labelOptions?.color,
xoffset: labelOptions?.offset?.[0],
yoffset: labelOptions?.offset?.[1],
zoffset: labelOptions?.offset?.[2],
verticalAlignment: 'middle',
horizontalAlignment: 'center',
})
}
return new SMap.Marker(result)
})
}
/** 设置覆盖物方法 */
private _setMarkers() {
const _markers: Partial<Markers> = {
point: (data: PointData) => {
const layer = new SMap.OverlayGroup(this._toPoints(data), {})
this.instance.add(layer)
return layer return layer
}, },
} }
...@@ -285,6 +228,6 @@ export default class S_Map extends MyMap { ...@@ -285,6 +228,6 @@ export default class S_Map extends MyMap {
this.map.setZoomAndCenter(level, location) this.map.setZoomAndCenter(level, location)
} }
remove(layer: unknown) { remove(layer: unknown) {
this.map.remove(layer) layer && this.map.remove(layer)
} }
} }
import { LayerOption, PointsData } from '../types'
/** 转化点状覆盖物 */
export function toPoints(options: LayerOption) {
const { data, size = 20, icon, labelKey, labelOptions } = options
const transData = (item: PointsData) => {
const iconSize = Array.isArray(size)
? new SMap.Size(...size)
: new SMap.Size(size, size)
const x = item.X || item.x || item.gpsx
const y = item.Y || item.y || item.gpsy
if ((x !== 0 && !x) || (y !== 0 && !y)) {
console.error(`add point: 非法的坐标[${x}, ${y}] 存在于数据: ${item}`)
}
const z = item.Z || item.z || item.gpsz || 0
const result: any = {
icon: {
size: iconSize,
image: item.icon || icon,
},
attributes: { ...item },
position: z ? [x, y, z] : [x, y],
}
if (labelKey) {
result.label = new SMap.Label({
text: item[labelKey] + '',
size: labelOptions?.size,
color: labelOptions?.color,
xoffset: labelOptions?.offset?.[0],
yoffset: labelOptions?.offset?.[1],
zoffset: labelOptions?.offset?.[2],
verticalAlignment: 'middle',
horizontalAlignment: 'center',
})
}
return new SMap.Marker(result)
}
if (Array.isArray(data)) {
return data.map(transData)
} else {
return [transData(data)]
}
}
/** 转化线状覆盖物 */
export function toLines(options: LayerOption) {
const {
data,
color = 'blue',
labelKey,
labelOptions,
lineCap = 'square',
lineStyle = 'solid',
lineJoin = 'round',
lineWidth = 1,
} = options
const transData = (item: PointsData) => {
const result: any = {
path: item.path?.map(([x, y]) => new SMap.LngLat(x, y)),
attributes: { ...item },
cap: lineCap,
strokeColor: color,
style: lineStyle,
lineJoin: lineJoin,
lineWidth, // 测绘院地图貌似没法设置线段粗细
}
if (labelKey) {
result.label = new SMap.Label({
text: item[labelKey] + '',
size: labelOptions?.size,
color: labelOptions?.color,
xoffset: labelOptions?.offset?.[0],
yoffset: labelOptions?.offset?.[1],
verticalAlignment: 'middle',
horizontalAlignment: 'center',
})
}
return new SMap.Polyline(result)
}
if (Array.isArray(data)) {
return data.map(transData)
} else {
return [transData(data)]
}
}
...@@ -112,6 +112,10 @@ export interface Listeners { ...@@ -112,6 +112,10 @@ export interface Listeners {
} }
type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' type Position = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
/**
* 控制器选项
*/
export interface ControlOptions { export interface ControlOptions {
show?: boolean show?: boolean
/** 控件位置 */ /** 控件位置 */
...@@ -121,6 +125,10 @@ export interface ControlOptions { ...@@ -121,6 +125,10 @@ export interface ControlOptions {
/** ScaleControl控件的距离单位 */ /** ScaleControl控件的距离单位 */
unit?: 'imperial' | 'metric' | 'nautical' unit?: 'imperial' | 'metric' | 'nautical'
} }
/**
* 控制器列表
*/
export interface Controls { export interface Controls {
home: (options?: ControlOptions) => unknown home: (options?: ControlOptions) => unknown
compass: (options?: ControlOptions) => unknown compass: (options?: ControlOptions) => unknown
...@@ -135,6 +143,8 @@ export interface Controls { ...@@ -135,6 +143,8 @@ export interface Controls {
bMapGallery: (options?: ControlOptions) => unknown bMapGallery: (options?: ControlOptions) => unknown
bMapGalleryexpand: (options?: ControlOptions) => unknown bMapGalleryexpand: (options?: ControlOptions) => unknown
} }
export interface ZoomOptions { export interface ZoomOptions {
/** 如果 false ,则没有动画效果(默认true) */ /** 如果 false ,则没有动画效果(默认true) */
animate?: boolean animate?: boolean
...@@ -163,15 +173,16 @@ export interface FocusOptions { ...@@ -163,15 +173,16 @@ export interface FocusOptions {
maxDuration?: number maxDuration?: number
} }
export interface Markers {
point: (data: PointData) => unknown
}
/** /**
* 点状覆盖物数据 * 覆盖物列表
*/ */
export interface PointData { export interface Layers {
data: { point: (data: LayerOption) => unknown
line: (data: LayerOption) => unknown
}
/** 覆盖物点位数据 */
export interface PointsData {
id?: string id?: string
x?: number x?: number
y?: number y?: number
...@@ -184,8 +195,15 @@ export interface PointData { ...@@ -184,8 +195,15 @@ export interface PointData {
gpsz?: number gpsz?: number
icon?: string icon?: string
spatialReference?: LocationType spatialReference?: LocationType
path?: [number, number][]
[key: string]: any [key: string]: any
}[] }
/**
* 覆盖物选项
*/
export interface LayerOption {
data: PointsData | PointsData[]
size?: number | [number, number] size?: number | [number, number]
icon?: string icon?: string
spatialReference?: LocationType spatialReference?: LocationType
...@@ -196,4 +214,9 @@ export interface PointData { ...@@ -196,4 +214,9 @@ export interface PointData {
offset?: [number, number] | [number, number, number] offset?: [number, number] | [number, number, number]
color?: string color?: string
} }
color?: string
lineCap?: string
lineStyle?: string
lineJoin?: 'bevel' | 'round' | 'miter'
lineWidth?: number
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment