@sword916/vae-map-plus 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +3 -0
  2. package/build/index.mjs +113 -0
  3. package/examples/App.vue +18 -0
  4. package/examples/index.js +13 -0
  5. package/examples/router/index.js +35 -0
  6. package/examples/views/amap.vue +29 -0
  7. package/examples/views/amarker.vue +58 -0
  8. package/examples/views/buffer.vue +66 -0
  9. package/examples/views/cluster.vue +74 -0
  10. package/examples/views/cover.vue +85 -0
  11. package/examples/views/draw-line.vue +49 -0
  12. package/examples/views/draw.vue +54 -0
  13. package/examples/views/echarts.vue +142 -0
  14. package/examples/views/emarker.vue +39 -0
  15. package/examples/views/image.vue +182 -0
  16. package/examples/views/index.vue +61 -0
  17. package/examples/views/lrmap.vue +108 -0
  18. package/examples/views/map.vue +82 -0
  19. package/examples/views/measure.vue +86 -0
  20. package/examples/views/parts/popup.vue +39 -0
  21. package/examples/views/parts/tooltip.vue +39 -0
  22. package/examples/views/push-area.vue +52 -0
  23. package/examples/views/push-line.vue +84 -0
  24. package/examples/views/trace.vue +49 -0
  25. package/index.html +13 -0
  26. package/jsconfig.json +17 -0
  27. package/package.json +47 -0
  28. package/public/favicon.ico +0 -0
  29. package/public/images/game.png +0 -0
  30. package/public/images/grid.png +0 -0
  31. package/public/images/marker.png +0 -0
  32. package/public/index.html +30 -0
  33. package/src/components/resize-listener/component.jsx +30 -0
  34. package/src/components/resize-listener/index.js +3 -0
  35. package/src/composables/useAutoMessage.js +41 -0
  36. package/src/composables/useContextMenu.js +99 -0
  37. package/src/composables/useMapMeasure.js +191 -0
  38. package/src/composables/useResizeObserver.js +81 -0
  39. package/src/mixins/message.js +1 -0
  40. package/src/packages/index.js +16 -0
  41. package/src/packages/vae-amap/index.js +8 -0
  42. package/src/packages/vae-amap/style.less +9 -0
  43. package/src/packages/vae-amap/vae-amap.jsx +98 -0
  44. package/src/packages/vae-cloudmap/ctrl-context-menu/index.vue +74 -0
  45. package/src/packages/vae-cloudmap/ctrl-draw/index.vue +499 -0
  46. package/src/packages/vae-cloudmap/ctrl-draw-line/index.vue +161 -0
  47. package/src/packages/vae-cloudmap/index.js +57 -0
  48. package/src/packages/vae-cloudmap/scripts/L.MarkerCluster/index.js +2690 -0
  49. package/src/packages/vae-cloudmap/scripts/L.MarkerCluster/style.css +14 -0
  50. package/src/packages/vae-cloudmap/scripts/L.Vae.CRS/index.js +212 -0
  51. package/src/packages/vae-cloudmap/scripts/L.Vae.Client/index.js +780 -0
  52. package/src/packages/vae-cloudmap/scripts/Mixin.ContextMenu/index.js +101 -0
  53. package/src/packages/vae-cloudmap/style.less +163 -0
  54. package/src/packages/vae-cloudmap/vae-cloudmap.jsx +272 -0
  55. package/src/packages/vae-map/ctrl-context-menu/index.vue +74 -0
  56. package/src/packages/vae-map/ctrl-draw/index.vue +498 -0
  57. package/src/packages/vae-map/ctrl-draw-line/index.vue +128 -0
  58. package/src/packages/vae-map/index.js +59 -0
  59. package/src/packages/vae-map/scripts/L.MarkerCluster/index.js +2690 -0
  60. package/src/packages/vae-map/scripts/L.MarkerCluster/style.css +14 -0
  61. package/src/packages/vae-map/scripts/L.Vae.CRS/index.js +114 -0
  62. package/src/packages/vae-map/scripts/L.Vae.Client/index.js +548 -0
  63. package/src/packages/vae-map/scripts/Mixin.ContextMenu/index.js +1 -0
  64. package/src/packages/vae-map/style.less +161 -0
  65. package/src/packages/vae-map/vae-lrmap.jsx +237 -0
  66. package/src/packages/vae-map/vae-map.jsx +135 -0
  67. package/src/plugins/L.AnimatedMarker/index.js +158 -0
  68. package/src/plugins/L.EchartsLayer/index.js +339 -0
  69. package/src/plugins/L.ElasticMarker/index.js +162 -0
  70. package/src/plugins/L.FootageCalculator.Area/index.js +263 -0
  71. package/src/plugins/L.FootageCalculator.Line/index.js +273 -0
  72. package/src/plugins/L.GeoUtil/buffer.js +67 -0
  73. package/src/plugins/L.GeoUtil/index.js +284 -0
  74. package/src/plugins/L.Glyphicon/index.js +91 -0
  75. package/src/plugins/L.Glyphicon/style.less +37 -0
  76. package/src/plugins/L.MarkerClusterX/index.js +93 -0
  77. package/src/plugins/L.MarkerClusterX/style.less +162 -0
  78. package/src/plugins/L.SafeDivOverlay/index.js +55 -0
  79. package/src/plugins/L.TileLayer.ChinaProvider/index.js +108 -0
  80. package/src/plugins/L.VuePopup/index.js +67 -0
  81. package/src/plugins/L.VueTooltip/index.js +63 -0
  82. package/src/plugins/Mixin.Map.Measure/index.js +248 -0
  83. package/src/plugins/globals/index.js +7 -0
  84. package/src/utils/index.js +36 -0
  85. package/src/utils/resize-event.js +45 -0
  86. package/vite.config.mjs +25 -0
@@ -0,0 +1,161 @@
1
+ .vae-map,
2
+ .vae-lrmap {
3
+ position: relative;
4
+
5
+ .leaflet-map {
6
+ height: 100%;
7
+ width: 100%;
8
+ background: transparent;
9
+
10
+ #tooltips();
11
+ }
12
+
13
+ .loading-mask {
14
+ position: absolute;
15
+ z-index: 2000;
16
+ background: rgba(255, 255, 255, 0.8);
17
+ top: 0;
18
+ right: 0;
19
+ bottom: 0;
20
+ left: 0;
21
+ transition: opacity 0.3s;
22
+
23
+ .wrapper {
24
+ display: flex;
25
+ flex-direction: column;
26
+ align-items: center;
27
+ justify-content: center;
28
+ height: 100%;
29
+
30
+ .loading-icon {
31
+ font-size: 42px;
32
+ color: #409eff;
33
+ }
34
+
35
+ .loading-text {
36
+ font-size: 14px;
37
+ color: #409eff;
38
+ margin-top: 5px;
39
+ }
40
+ }
41
+ }
42
+ }
43
+
44
+ #tooltips() {
45
+ .icon--simple-text {
46
+ background: rgba(255, 255, 255, 0.8);
47
+ border: 1px solid #dcdfe6;
48
+ color: #303133;
49
+ font-size: 12px;
50
+ font-weight: bold;
51
+ padding: 2px 4px;
52
+ text-align: center;
53
+ margin-top: -25px !important;
54
+ box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1);
55
+
56
+ &.dark {
57
+ color: white;
58
+ background: #343a40;
59
+ }
60
+ }
61
+
62
+ .ht-tooltip {
63
+ font-size: 12px;
64
+ padding: 2px 4px;
65
+
66
+ .action {
67
+ margin-right: 2px;
68
+ }
69
+
70
+ .green {
71
+ color: seagreen;
72
+ font-weight: bold;
73
+ }
74
+
75
+ .red {
76
+ color: firebrick;
77
+ font-weight: bold;
78
+ }
79
+ }
80
+ }
81
+
82
+ .vae-map-ctrl--draw {
83
+ position: absolute;
84
+ left: 10px;
85
+ top: 10px;
86
+ z-index: 1000;
87
+ border-radius: 5px;
88
+
89
+ .item-group {
90
+ background: #f4f4f5;
91
+ border-radius: 4px;
92
+ box-shadow: 1px 2px 6px 0 rgba(0, 0, 0, 0.2);
93
+
94
+ &:not(:first-child) {
95
+ margin-top: 6px;
96
+ }
97
+
98
+ .item {
99
+ display: flex;
100
+ align-items: center;
101
+ position: relative;
102
+
103
+ &:not(:first-child) {
104
+ border-top: 1px solid #e4e7ed;
105
+ }
106
+
107
+ .item-icon {
108
+ display: inline-flex;
109
+ align-items: center;
110
+ justify-content: center;
111
+ height: 34px;
112
+ width: 36px;
113
+ color: #606266;
114
+ font-size: 16px;
115
+ cursor: pointer;
116
+
117
+ &:hover {
118
+ color: #409eff;
119
+ }
120
+
121
+ &.disabled {
122
+ color: #909399;
123
+ }
124
+ }
125
+
126
+ .tooltips {
127
+ position: absolute;
128
+ font-size: 12px;
129
+ color: #606266;
130
+ left: 100%;
131
+ margin-left: 6px;
132
+ width: max-content;
133
+
134
+ span {
135
+ padding: 6px 9px;
136
+ background: #3a8ee6;
137
+ color: white;
138
+ cursor: pointer;
139
+
140
+ &:hover {
141
+ background: #409eff;
142
+ }
143
+
144
+ &:not(:first-child) {
145
+ border-left: 1px solid white;
146
+ }
147
+
148
+ &:first-child {
149
+ border-top-left-radius: 2px;
150
+ border-bottom-left-radius: 2px;
151
+ }
152
+
153
+ &:last-child {
154
+ border-top-right-radius: 2px;
155
+ border-bottom-right-radius: 2px;
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
@@ -0,0 +1,237 @@
1
+ import { computed, defineComponent, nextTick, onBeforeUnmount, onMounted, ref, toRef, watch } from 'vue'
2
+ import { idGen } from '@/utils'
3
+ import ResizeListener from '@/components/resize-listener/index.js'
4
+ import { useAutoMessage } from '@/composables/useAutoMessage'
5
+ import { useContextMenu } from '@/composables/useContextMenu'
6
+
7
+ export default defineComponent({
8
+ name: 'VaeLrmap',
9
+ props: {
10
+ height: {
11
+ type: String,
12
+ default: '100%'
13
+ },
14
+ width: {
15
+ type: String,
16
+ default: '100%'
17
+ },
18
+ options: {
19
+ type: Object,
20
+ default: () => ({})
21
+ },
22
+ beforeCreate: {
23
+ type: Function,
24
+ default: _.noop
25
+ },
26
+ contextMenu: {
27
+ type: Array,
28
+ default: () => []
29
+ }
30
+ },
31
+ emits: ['init-map', 'reload-map'],
32
+ setup(props, { emit }) {
33
+ const autoMessage = useAutoMessage()
34
+ const destroyed = ref(false)
35
+ const client = ref(null)
36
+ const uuid = ref(`vae_lrmap_${idGen()}`)
37
+ const map = ref(null)
38
+ const inited = ref(false)
39
+ const loading = ref(false)
40
+ const loadingText = ref('')
41
+ const innerLoading = ref(false)
42
+ const innerLoadingText = ref('')
43
+ const tileLayer = ref(null)
44
+ const mapContainerRef = ref(null)
45
+
46
+ const { addContextMenu, renderContextMenu } = useContextMenu({
47
+ mapRef: map,
48
+ mapContainerRef,
49
+ menusRef: toRef(props, 'contextMenu')
50
+ })
51
+
52
+ const createContextInstance = (includeMap) => {
53
+ const {
54
+ leafletOptions, requestOptions, treeLayers, visibleKeys,
55
+ requestServer, queryEntity, showLayers, showLayerSets, getThumbnail
56
+ } = client.value
57
+
58
+ const properties = _.merge({ el: uuid.value, client: client.value }, leafletOptions, requestOptions)
59
+ const layerProperties = includeMap ? { treeLayers, visibleKeys } : {}
60
+ const requestFunctions = {
61
+ requestServer: requestServer.bind(client.value),
62
+ queryEntity: queryEntity.bind(client.value),
63
+ showLayers: showLayers.bind(client.value),
64
+ showLayerSets: showLayerSets.bind(client.value),
65
+ getThumbnail: getThumbnail.bind(client.value)
66
+ }
67
+ const mapFunctions = includeMap ? {
68
+ refreshMap: () => {
69
+ refreshTileLayer()
70
+ setDefaultView()
71
+ },
72
+ reloadMap
73
+ } : null
74
+
75
+ return _.merge(properties, layerProperties, requestFunctions, mapFunctions)
76
+ }
77
+
78
+ const openInnerMask = (text) => {
79
+ innerLoading.value = true
80
+ innerLoadingText.value = text
81
+ }
82
+
83
+ const closeInnerMask = () => {
84
+ innerLoading.value = false
85
+ innerLoadingText.value = ''
86
+ }
87
+
88
+ const refreshTileLayer = () => {
89
+ if (!map.value || !client.value) {
90
+ return
91
+ }
92
+ if (tileLayer.value) {
93
+ map.value.removeLayer(tileLayer.value)
94
+ }
95
+ tileLayer.value = client.value.currentTileLayer().addTo(map.value)
96
+ }
97
+
98
+ const refreshClient = () => {
99
+ client.value = new L.Vae.Client(L.extend({ uid: uuid.value }, props.options))
100
+ client.value.on('message', (event) => {
101
+ autoMessage({
102
+ message: event.message,
103
+ type: event.messageType
104
+ })
105
+ })
106
+ client.value.on('openmask', (event) => {
107
+ openInnerMask(event.text)
108
+ })
109
+ client.value.on('closemask', closeInnerMask)
110
+ client.value.on('refreshtilelayer', refreshTileLayer)
111
+ }
112
+
113
+ const setDefaultView = (animate = true) => {
114
+ if (map.value) {
115
+ if (props.options.zoom && props.options.center) {
116
+ return
117
+ }
118
+ map.value.fitBounds(client.value.leafletOptions.bounds, { animate })
119
+ }
120
+ }
121
+
122
+ const createMap = () => {
123
+ if (!map.value) {
124
+ const options = L.extend(
125
+ {
126
+ zoomControl: false,
127
+ attributionControl: false,
128
+ doubleClickZoom: false
129
+ },
130
+ _.omit(props.options, ['url', 'dsname', 'layerTreeType', 'defaultLayers', 'defaultLayerSets']),
131
+ _.pick(client.value.leafletOptions, ['crs', 'center', 'maxZoom'])
132
+ )
133
+ map.value = L.map(uuid.value, options)
134
+ setDefaultView(false)
135
+
136
+ return new Promise((resolve) => {
137
+ map.value.whenReady(resolve)
138
+ })
139
+ }
140
+
141
+ return Promise.resolve()
142
+ }
143
+
144
+ const extendMapInstance = () => {
145
+ map.value.vae = {}
146
+ _.merge(map.value.vae, createContextInstance(true))
147
+ }
148
+
149
+ const requestMeta = ({ event = 'init-map', alert = true } = {}) => {
150
+ refreshClient()
151
+ client.value.start(alert).then(async (metaReady) => {
152
+ if (!metaReady) {
153
+ return
154
+ }
155
+
156
+ await props.beforeCreate(createContextInstance(false))
157
+ await client.value.setDefaultLayers()
158
+ await createMap()
159
+ addContextMenu()
160
+ refreshTileLayer()
161
+ extendMapInstance()
162
+ emit(event, map.value)
163
+
164
+ if (event === 'init-map') {
165
+ inited.value = true
166
+ }
167
+ })
168
+ }
169
+
170
+ const resizeMap = () => {
171
+ map.value?.invalidateSize()
172
+ }
173
+
174
+ const reloadMap = () => {
175
+ map.value?.remove()
176
+ map.value = null
177
+ tileLayer.value = null
178
+ destroyed.value = true
179
+ nextTick(() => {
180
+ destroyed.value = false
181
+ nextTick(() => {
182
+ requestMeta({ event: 'reload-map' })
183
+ })
184
+ })
185
+ }
186
+
187
+ const mapLoading = computed(() => loading.value || innerLoading.value)
188
+ const mapLoadingText = computed(() => loadingText.value || innerLoadingText.value)
189
+
190
+ watch(
191
+ () => props.options,
192
+ () => {
193
+ if (!inited.value) {
194
+ requestMeta({ alert: true })
195
+ }
196
+ },
197
+ { deep: true }
198
+ )
199
+
200
+ onMounted(() => {
201
+ requestMeta({ alert: false })
202
+ })
203
+
204
+ onBeforeUnmount(() => {
205
+ map.value?.remove()
206
+ })
207
+
208
+ return () => {
209
+ if (destroyed.value) {
210
+ return null
211
+ }
212
+
213
+ const loadingMask = mapLoading.value ? (
214
+ <div class="loading-mask">
215
+ <div class="wrapper">
216
+ <div class="loading-icon">
217
+ <i class="fas fa-circle-notch fa-spin"></i>
218
+ </div>
219
+ <div class="loading-text">{mapLoadingText.value}</div>
220
+ </div>
221
+ </div>
222
+ ) : null
223
+
224
+ return (
225
+ <ResizeListener
226
+ ref={mapContainerRef}
227
+ class="vae-lrmap"
228
+ style={{ height: props.height, width: props.width }}
229
+ onResize={resizeMap}>
230
+ <div class="leaflet-map" id={uuid.value}></div>
231
+ {renderContextMenu()}
232
+ {loadingMask}
233
+ </ResizeListener>
234
+ )
235
+ }
236
+ }
237
+ })
@@ -0,0 +1,135 @@
1
+ import { defineComponent, nextTick, onBeforeUnmount, ref, toRef, watch } from 'vue'
2
+ import { idGen } from '@/utils'
3
+ import ResizeListener from '@/components/resize-listener/index.js'
4
+ import { useContextMenu } from '@/composables/useContextMenu'
5
+
6
+ export default defineComponent({
7
+ name: 'VaeMap',
8
+ props: {
9
+ height: {
10
+ type: String,
11
+ default: '100%'
12
+ },
13
+ width: {
14
+ type: String,
15
+ default: '100%'
16
+ },
17
+ options: {
18
+ type: Object,
19
+ default: () => ({})
20
+ },
21
+ baseLayers: {
22
+ type: [String, Array],
23
+ default: () => []
24
+ },
25
+ contextMenu: {
26
+ type: Array,
27
+ default: () => []
28
+ }
29
+ },
30
+ emits: ['init-map'],
31
+ setup(props, { emit }) {
32
+ const destroyed = ref(false)
33
+ const uuid = ref(`vae_map_${idGen()}`)
34
+ const map = ref(null)
35
+ const tileLayers = ref(null)
36
+ const mapContainerRef = ref(null)
37
+
38
+ const { addContextMenu, renderContextMenu } = useContextMenu({
39
+ mapRef: map,
40
+ mapContainerRef,
41
+ menusRef: toRef(props, 'contextMenu')
42
+ })
43
+
44
+ const initTileLayers = () => {
45
+ if (!map.value) {
46
+ return
47
+ }
48
+
49
+ if (!tileLayers.value) {
50
+ tileLayers.value = L.layerGroup().addTo(map.value)
51
+ }
52
+
53
+ tileLayers.value.clearLayers()
54
+ let layers = props.baseLayers
55
+ if (_.isString(layers)) {
56
+ layers = [layers]
57
+ }
58
+ if (Array.isArray(layers)) {
59
+ layers.forEach((value) => {
60
+ L.tileLayer.chinaProvider(value).addTo(tileLayers.value)
61
+ })
62
+ }
63
+ }
64
+
65
+ const createMap = () => {
66
+ if (!map.value) {
67
+ const options = L.extend({
68
+ center: [34.2943, 117.357],
69
+ zoom: 12,
70
+ maxZoom: 25,
71
+ zoomControl: false,
72
+ attributionControl: false
73
+ }, props.options)
74
+
75
+ map.value = L.map(uuid.value, options)
76
+ map.value.whenReady(() => {
77
+ addContextMenu()
78
+ initTileLayers()
79
+ emit('init-map', map.value)
80
+ })
81
+ }
82
+ }
83
+
84
+ const resizeMap = () => {
85
+ if (!map.value) {
86
+ createMap()
87
+ }
88
+ map.value?.invalidateSize()
89
+ }
90
+
91
+ const reloadMap = () => {
92
+ map.value?.remove()
93
+ map.value = null
94
+ tileLayers.value = null
95
+ destroyed.value = true
96
+ nextTick(() => {
97
+ destroyed.value = false
98
+ nextTick(() => {
99
+ createMap()
100
+ })
101
+ })
102
+ }
103
+
104
+ watch(
105
+ () => props.baseLayers,
106
+ () => {
107
+ if (map.value) {
108
+ initTileLayers()
109
+ }
110
+ },
111
+ { deep: true }
112
+ )
113
+
114
+ onBeforeUnmount(() => {
115
+ map.value?.remove()
116
+ })
117
+
118
+ return () => {
119
+ if (destroyed.value) {
120
+ return null
121
+ }
122
+
123
+ return (
124
+ <ResizeListener
125
+ ref={mapContainerRef}
126
+ class="vae-map"
127
+ style={{ height: props.height, width: props.width }}
128
+ onResize={resizeMap}>
129
+ <div class="leaflet-map" id={uuid.value}></div>
130
+ {renderContextMenu()}
131
+ </ResizeListener>
132
+ )
133
+ }
134
+ }
135
+ })
@@ -0,0 +1,158 @@
1
+ // 计算两点距离
2
+ function calcDistance(p1, p2) {
3
+ function toPoint(v) {
4
+ if (Array.isArray(v) && v.length == 2) {
5
+ return { x: v[0], y: v[1] }
6
+ } else if (v.lat && v.lng) {
7
+ return { x: v.lat, y: v.lng }
8
+ } else {
9
+ return v
10
+ }
11
+ }
12
+ p1 = toPoint(p1)
13
+ p2 = toPoint(p2)
14
+
15
+ return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y))
16
+ }
17
+
18
+ // 活动Marker
19
+ L.AnimatedMarker = L.Marker.extend({
20
+
21
+ /**
22
+ * 活动状态
23
+ * 1. disabled 不可用
24
+ * 2. free 空闲
25
+ * 3. move 移动中
26
+ * 4. pause 暂停中
27
+ */
28
+ _status: 'disabled',
29
+
30
+ chunkMoveTimer: null,
31
+
32
+ options: {
33
+ // 持续时间
34
+ duration: 5000,
35
+ // 轨迹序列
36
+ latLngs: [],
37
+ // 浮于其他Marker上层
38
+ zIndexOffset: 1000
39
+ },
40
+
41
+ initialize(options) {
42
+ L.setOptions(this, options)
43
+ const latLngs = this.options.latLngs
44
+ if (latLngs && latLngs.length > 1) {
45
+ L.Marker.prototype.initialize.call(this, latLngs[0], this.options)
46
+ this._status = 'free'
47
+ } else {
48
+ console.error('invalid latLngs')
49
+ }
50
+ },
51
+
52
+ // 开始动画
53
+ startMove() {
54
+ if (this._status == 'free') {
55
+ const { duration, latLngs } = this.options
56
+ let totalDistance = 0
57
+ let stepDistances = []
58
+ let stepDurations = []
59
+ for (let i = 0; i < latLngs.length - 1; i++) {
60
+ const d = calcDistance(latLngs[i], latLngs[i + 1])
61
+ totalDistance += d
62
+ stepDistances.push(d)
63
+ }
64
+ stepDistances.forEach(v => {
65
+ stepDurations.push(v / totalDistance * duration)
66
+ })
67
+ this.stepDurations = stepDurations
68
+ this.chunkIndex = 0
69
+ this._status = 'move'
70
+
71
+ // 加入延迟,确保popup和tooltip显示正常
72
+ this.setLatLng(latLngs[0])
73
+ _.delay(() => {
74
+ this.chunkMove()
75
+ this.fire('startmove')
76
+ })
77
+ } else {
78
+ console.error('instance is not free')
79
+ }
80
+ },
81
+
82
+ // 分段移动
83
+ chunkMove() {
84
+ if (this.chunkIndex < this.stepDurations.length) {
85
+ if (this._status == 'pause') {
86
+ return
87
+ }
88
+ const stepDuration = this.stepDurations[this.chunkIndex]
89
+ const transition = `transform ${stepDuration}ms linear`
90
+ this.setTransition(transition)
91
+ this.chunkIndex += 1
92
+ _.delay(() => {
93
+ this.fire('chunkmove', { index: this.chunkIndex, duration: stepDuration })
94
+ this.setLatLng(this.options.latLngs[this.chunkIndex])
95
+ this.chunkMoveTimer = _.delay(this.chunkMove.bind(this), stepDuration)
96
+ })
97
+ } else {
98
+ this.stopMove()
99
+ }
100
+ },
101
+
102
+ // 设置动画参数
103
+ setTransition(transition) {
104
+ const transitionProperties = L.DomUtil.TRANSITION
105
+ const iconStyle = this._icon ? this._icon.style : ""
106
+ if (iconStyle) {
107
+ iconStyle[transitionProperties] = transition
108
+ }
109
+ const shadowStyle = this._shadow ? this._shadow.style : ""
110
+ if (shadowStyle) {
111
+ shadowStyle[transitionProperties] = transition
112
+ }
113
+ const toolTip = this.getTooltip()
114
+ const toolTipStyle = (toolTip && toolTip._container) ? toolTip._container.style : ""
115
+ if (toolTipStyle) {
116
+ toolTipStyle[transitionProperties] = transition
117
+ }
118
+ const popup = this.getPopup()
119
+ const popupStyle = (popup && popup._container) ? popup._container.style : ""
120
+ if (popupStyle) {
121
+ popupStyle[transitionProperties] = transition
122
+ }
123
+ },
124
+
125
+ // 停止动画
126
+ stopMove() {
127
+ this._status = 'free'
128
+ this.setTransition(null)
129
+ if (this.chunkMoveTimer) {
130
+ clearTimeout(this.chunkMoveTimer)
131
+ this.chunkMoveTimer = null
132
+ }
133
+ this.setLatLng(_.last(this.options.latLngs))
134
+ this.fire('stopmove')
135
+ },
136
+
137
+ // 暂停动画
138
+ pauseMove() {
139
+ if (this._status == 'move') {
140
+ this._status = 'pause'
141
+ this.fire('pausemove')
142
+ }
143
+ },
144
+
145
+ // 继续动画
146
+ continueMove() {
147
+ if (this._status == 'pause') {
148
+ this._status = 'move'
149
+ this.fire('continuemove')
150
+ this.chunkMove()
151
+ }
152
+ }
153
+
154
+ })
155
+
156
+ L.animatedMarker = (options) => {
157
+ return new L.AnimatedMarker(options)
158
+ }