|
139 | 139 | }; |
140 | 140 | var VIDEO_DRAW_SOURCE_ID = 'huainan-video-draw-sync'; |
141 | 141 | var REAL_VIDEO_DRAW_SOURCE_ID = 'huainan-real-video-draw-sync'; |
142 | | - var VIDEO_FOOTPRINT_SOURCE_ID = 'huainan-video-footprint'; |
| 142 | + var VIDEO_BOUNDS_SOURCE_ID = 'huainan-video-bounds'; |
143 | 143 | var videoMap; |
144 | 144 | var map; |
145 | 145 | var mapDraw; |
|
149 | 149 | var dynamicLayerIds = []; |
150 | 150 | var measurementMarkers = {}; |
151 | 151 | var uploadedDatasetRefreshVersions = {}; |
| 152 | + // 天地图标绘要素 id -> 服务端 SmID,用于删除时定位已上传的要素 |
| 153 | + var mapDrawSmIDs = {}; |
152 | 154 | var mapBearing = 214; |
153 | 155 | var tk = '1d109683f4d84198e37a38c442d68311'; |
154 | 156 | var attribution = |
155 | 157 | "© <a href='https://www.tianditu.gov.cn' target='_blank'>天地图</a>" + |
156 | 158 | " with <span>© <a href='https://iclient.supermap.io' target='_blank'>SuperMap iClient</a></span> "; |
157 | 159 |
|
158 | | - function resolveVideoUrl(address) { |
159 | | - if (!address || /^https?:\/\//i.test(address)) { |
160 | | - return address; |
161 | | - } |
162 | | - return host + (address.charAt(0) === '/' ? address : '/' + address); |
163 | | - } |
164 | | - |
165 | 160 | function initMap() { |
166 | 161 | map = new mapboxgl.Map({ |
167 | 162 | container: 'map', |
|
185 | 180 | { id: 'tianditu-cia', type: 'raster', source: 'tianditu_cia', minzoom: 0, maxzoom: 18 } |
186 | 181 | ] |
187 | 182 | }, |
188 | | - center: [116.84922, 32.5758765], |
| 183 | + center: [116.8500991647519, 32.577504319585], |
189 | 184 | zoom: 16, |
190 | 185 | bearing: mapBearing, |
191 | 186 | pitch: 4.5, |
|
196 | 191 | displayControlsDefault: false, |
197 | 192 | controls: { point: true, line_string: true, polygon: true, trash: true } |
198 | 193 | }); |
| 194 | + window.map = map; |
199 | 195 | map.addControl(mapDraw, 'top-left'); |
200 | 196 | map.addControl(new mapboxgl.supermap.LogoControl({ link: 'https://iclient.supermap.io' }), 'bottom-right'); |
201 | 197 | ['draw.create', 'draw.update', 'draw.delete', 'draw.render'].forEach(function (eventName) { |
202 | 198 | map.on(eventName, syncMapDraw); |
203 | 199 | }); |
| 200 | + // 天地图上的新增标绘同样上传到 iServer,并支持删除 |
| 201 | + map.on('draw.create', function (event) { |
| 202 | + (event.features || []).forEach(uploadMapDrawFeature); |
| 203 | + }); |
| 204 | + map.on('draw.delete', function (event) { |
| 205 | + (event.features || []).forEach(deleteMapDrawFeature); |
| 206 | + }); |
204 | 207 | map.on('load', function () { |
205 | 208 | mapReady = true; |
206 | 209 | Object.keys(pendingRealSources).forEach(function (sourceId) { |
207 | 210 | var pending = pendingRealSources[sourceId]; |
208 | 211 | addOrUpdateRealSource(sourceId, pending.data, pending.color); |
209 | 212 | }); |
210 | 213 | pendingRealSources = {}; |
211 | | - updateVideoFootprint(); |
| 214 | + updateVideoBounds(); |
212 | 215 | }); |
213 | 216 | } |
214 | 217 |
|
215 | | - function updateVideoFootprint() { |
| 218 | + function updateVideoBounds() { |
216 | 219 | if (!videoMap || !mapReady || !videoMap.getVideoBounds) { |
217 | 220 | return; |
218 | 221 | } |
219 | | - var footprint = videoMap.getVideoBounds(); |
220 | | - if (!footprint) { |
| 222 | + var bounds = videoMap.getVideoBounds(); |
| 223 | + if (!bounds) { |
221 | 224 | return; |
222 | 225 | } |
223 | | - var featureCollection = { type: 'FeatureCollection', features: [footprint] }; |
224 | | - var source = map.getSource(VIDEO_FOOTPRINT_SOURCE_ID); |
| 226 | + var featureCollection = { type: 'FeatureCollection', features: [bounds] }; |
| 227 | + var source = map.getSource(VIDEO_BOUNDS_SOURCE_ID); |
225 | 228 | if (source) { |
226 | 229 | source.setData(featureCollection); |
227 | 230 | return; |
228 | 231 | } |
229 | | - map.addSource(VIDEO_FOOTPRINT_SOURCE_ID, { type: 'geojson', data: featureCollection }); |
| 232 | + map.addSource(VIDEO_BOUNDS_SOURCE_ID, { type: 'geojson', data: featureCollection }); |
230 | 233 | map.addLayer({ |
231 | | - id: VIDEO_FOOTPRINT_SOURCE_ID + '-fill', |
| 234 | + id: VIDEO_BOUNDS_SOURCE_ID + '-fill', |
232 | 235 | type: 'fill', |
233 | | - source: VIDEO_FOOTPRINT_SOURCE_ID, |
| 236 | + source: VIDEO_BOUNDS_SOURCE_ID, |
234 | 237 | paint: { 'fill-color': '#f59e0b', 'fill-opacity': 0.08 } |
235 | 238 | }); |
236 | 239 | map.addLayer({ |
237 | | - id: VIDEO_FOOTPRINT_SOURCE_ID + '-outline', |
| 240 | + id: VIDEO_BOUNDS_SOURCE_ID + '-outline', |
238 | 241 | type: 'line', |
239 | | - source: VIDEO_FOOTPRINT_SOURCE_ID, |
| 242 | + source: VIDEO_BOUNDS_SOURCE_ID, |
240 | 243 | paint: { 'line-color': '#f59e0b', 'line-width': 2, 'line-dasharray': [2, 1] } |
241 | 244 | }); |
242 | 245 | } |
|
427 | 430 | updateMeasurementMarkers('video-draw-video', videoMap, featureCollection, true); |
428 | 431 | } |
429 | 432 |
|
430 | | - function uploadVideoDrawFeature(feature) { |
| 433 | + function resolveDatasetPath(feature) { |
431 | 434 | if (!feature || !feature.geometry) { |
432 | | - return; |
| 435 | + return null; |
433 | 436 | } |
434 | 437 | var targetUrl = datasetUrl[feature.geometry.type]; |
435 | 438 | if (!targetUrl) { |
436 | | - return; |
| 439 | + return null; |
437 | 440 | } |
438 | | - var datasetPath = targetUrl.match(/^(.*)\/datasources\/([^/]+)\/datasets\/([^/?#]+)\/?$/); |
| 441 | + return targetUrl.match(/^(.*)\/datasources\/([^/]+)\/datasets\/([^/?#]+)\/?$/); |
| 442 | + } |
| 443 | + |
| 444 | + function uploadServerFeature(feature, onSuccess) { |
| 445 | + var datasetPath = resolveDatasetPath(feature); |
439 | 446 | if (!datasetPath) { |
440 | 447 | return; |
441 | 448 | } |
442 | 449 | var editFeaturesService = new mapboxgl.supermap.FeatureService(datasetPath[1]); |
443 | 450 | var editFeaturesParams = new mapboxgl.supermap.EditFeaturesParameters({ |
444 | | - features: feature, |
| 451 | + features: [feature], |
445 | 452 | dataSourceName: decodeURIComponent(datasetPath[2]), |
446 | 453 | dataSetName: decodeURIComponent(datasetPath[3]), |
447 | 454 | editType: 'add', |
448 | 455 | returnContent: true |
449 | 456 | }); |
450 | 457 | editFeaturesService.editFeatures(editFeaturesParams).then(function (serviceResult) { |
451 | | - if (!serviceResult || !serviceResult.result || !serviceResult.result.succeed) { |
| 458 | + var result = serviceResult && serviceResult.result; |
| 459 | + if (!result || result.succeed === false) { |
452 | 460 | return; |
453 | 461 | } |
| 462 | + // returnContent 为 true 时返回新建要素的 ID 数组,回填 SmID 以便删除时定位服务端要素 |
| 463 | + var SmID = Array.isArray(result) ? result[0] : result.SmID; |
| 464 | + if (SmID != null && onSuccess) { |
| 465 | + onSuccess(SmID); |
| 466 | + } |
454 | 467 | refreshUploadedDataset(decodeURIComponent(datasetPath[3])); |
455 | 468 | }).catch(function (error) { |
456 | 469 | console.error('视频标绘上传失败:', error); |
457 | 470 | }); |
458 | 471 | } |
459 | 472 |
|
460 | | - function deleteUploadedFeature(feature) { |
461 | | - if (!feature || !feature.geometry) { |
462 | | - return; |
| 473 | + function uploadVideoDrawFeature(feature, drawFeature) { |
| 474 | + uploadServerFeature(feature, function (SmID) { |
| 475 | + if (drawFeature) { |
| 476 | + drawFeature.properties = drawFeature.properties || {}; |
| 477 | + drawFeature.properties.SmID = SmID; |
| 478 | + } |
| 479 | + }); |
| 480 | + } |
| 481 | + |
| 482 | + function uploadMapDrawFeature(feature) { |
| 483 | + uploadServerFeature(feature, function (SmID) { |
| 484 | + if (feature.id != null) { |
| 485 | + mapDrawSmIDs[String(feature.id)] = SmID; |
| 486 | + } |
| 487 | + }); |
| 488 | + } |
| 489 | + |
| 490 | + function getFeatureSmID(feature) { |
| 491 | + if (!feature) { |
| 492 | + return null; |
463 | 493 | } |
464 | | - var targetUrl = datasetUrl[feature.geometry.type]; |
465 | | - if (!targetUrl) { |
| 494 | + var properties = feature.properties || {}; |
| 495 | + return properties.SmID != null ? properties.SmID : properties.SMID; |
| 496 | + } |
| 497 | + |
| 498 | + function deleteUploadedFeature(feature, SmID) { |
| 499 | + var datasetPath = resolveDatasetPath(feature); |
| 500 | + if (!datasetPath) { |
466 | 501 | return; |
467 | 502 | } |
468 | | - var datasetPath = targetUrl.match(/^(.*)\/datasources\/([^/]+)\/datasets\/([^/?#]+)\/?$/); |
469 | | - if (!datasetPath) { |
| 503 | + if (SmID == null) { |
| 504 | + SmID = getFeatureSmID(feature); |
| 505 | + } |
| 506 | + if (SmID != null) { |
| 507 | + deleteServerFeature(datasetPath, SmID); |
470 | 508 | return; |
471 | 509 | } |
| 510 | + // 未记录 SmID(如上传播报未返回)时,按几何从服务端反查后再删除 |
472 | 511 | var dataset = decodeURIComponent(datasetPath[3]); |
473 | 512 | var sqlParam = new mapboxgl.supermap.GetFeaturesBySQLParameters({ |
474 | 513 | queryParameter: { name: dataset + '@' + dataSourceName }, |
|
484 | 523 | if (!serverFeature || serverFeature.id == null) { |
485 | 524 | return; |
486 | 525 | } |
487 | | - var editFeaturesParams = new mapboxgl.supermap.EditFeaturesParameters({ |
488 | | - dataSourceName: decodeURIComponent(datasetPath[2]), |
489 | | - dataSetName: dataset, |
490 | | - IDs: [serverFeature.id], |
491 | | - editType: 'delete', |
492 | | - returnContent: true |
493 | | - }); |
494 | | - return new mapboxgl.supermap.FeatureService(datasetPath[1]) |
495 | | - .editFeatures(editFeaturesParams) |
496 | | - .then(function (deleteResult) { |
497 | | - if (deleteResult && deleteResult.result && deleteResult.result.succeed) { |
498 | | - refreshUploadedDataset(dataset); |
499 | | - } |
500 | | - }); |
| 526 | + deleteServerFeature(datasetPath, serverFeature.id); |
501 | 527 | }).catch(function (error) { |
502 | 528 | console.error('视频标绘删除失败:', error); |
503 | 529 | }); |
504 | 530 | } |
505 | 531 |
|
| 532 | + function deleteMapDrawFeature(feature) { |
| 533 | + var featureId = feature && feature.id != null ? String(feature.id) : null; |
| 534 | + var SmID = featureId != null ? mapDrawSmIDs[featureId] : null; |
| 535 | + if (featureId != null) { |
| 536 | + delete mapDrawSmIDs[featureId]; |
| 537 | + } |
| 538 | + deleteUploadedFeature(feature, SmID); |
| 539 | + } |
| 540 | + |
| 541 | + function deleteServerFeature(datasetPath, SmID) { |
| 542 | + var editFeaturesParams = new mapboxgl.supermap.EditFeaturesParameters({ |
| 543 | + dataSourceName: decodeURIComponent(datasetPath[2]), |
| 544 | + dataSetName: decodeURIComponent(datasetPath[3]), |
| 545 | + IDs: [SmID], |
| 546 | + editType: 'delete', |
| 547 | + returnContent: true |
| 548 | + }); |
| 549 | + new mapboxgl.supermap.FeatureService(datasetPath[1]) |
| 550 | + .editFeatures(editFeaturesParams) |
| 551 | + .then(function (deleteResult) { |
| 552 | + if (deleteResult && deleteResult.result && deleteResult.result.succeed) { |
| 553 | + refreshUploadedDataset(decodeURIComponent(datasetPath[3])); |
| 554 | + } |
| 555 | + }) |
| 556 | + .catch(function (error) { |
| 557 | + console.error('视频标绘删除失败:', error); |
| 558 | + }); |
| 559 | + } |
| 560 | + |
506 | 561 | function updateMeasurementMarkers(prefix, targetMap, featureCollection, projectToVideo) { |
507 | 562 | if (!targetMap || !featureCollection) { |
508 | 563 | return; |
|
597 | 652 | map.jumpTo({ center: initialCenter, zoom: 16, bearing: mapBearing }); |
598 | 653 | videoMap = new mapboxgl.supermap.VideoMap({ |
599 | 654 | container: 'videoMap', |
600 | | - url: resolveVideoUrl(feature.properties.address), |
| 655 | + url: feature.properties.address, |
601 | 656 | videoParameters: parameters, |
602 | 657 | interval: 0.1 |
603 | 658 | }); |
|
660 | 715 | }); |
661 | 716 | videoMap.on('drawcreate', function (event) { |
662 | 717 | syncVideoDraw(event.data || videoMap.getDrawData()); |
663 | | - uploadVideoDrawFeature(event.feature); |
| 718 | + var selectedFeatures = videoMap.getDrawSelected().features; |
| 719 | + uploadVideoDrawFeature(event.feature, selectedFeatures[0]); |
664 | 720 | }); |
665 | 721 | videoMap.on('drawdelete', function (event) { |
666 | 722 | syncVideoDraw(event.data || videoMap.getDrawData()); |
667 | | - (event.features || []).forEach(deleteUploadedFeature); |
| 723 | + (event.features || []).forEach(function (feature) { |
| 724 | + deleteUploadedFeature(feature); |
| 725 | + }); |
668 | 726 | }); |
669 | 727 | videoMap.on('drawclear', function () { |
670 | 728 | syncVideoDraw({ type: 'FeatureCollection', features: [] }); |
671 | 729 | }); |
672 | 730 | videoMap.on('videoparameterupdate', function () { |
673 | 731 | updateMeasurementMarkers('video', videoMap, mapDraw.getAll(), true); |
674 | 732 | updateMeasurementMarkers('video-draw-video', videoMap, videoMap.getDrawData(), true); |
675 | | - updateVideoFootprint(); |
| 733 | + updateVideoBounds(); |
676 | 734 | }); |
677 | | - updateVideoFootprint(); |
| 735 | + updateVideoBounds(); |
678 | 736 | videoMap.on('mousemove', function (event) { |
679 | 737 | var hits = dynamicLayerIds.length |
680 | 738 | ? videoMap.queryRenderedFeatures(event.point, { layers: dynamicLayerIds }) |
|
0 commit comments