import { LineLayer, Marker, MarkerLayer, Popup } from "@antv/l7"; import Store from "../../../hpaas-core/base/store"; import Overlay from "./../Overlay"; import { IOverlayFilter, IOverlayOptions, ISegmentOverlayDataOption, SegmentOverlayData } from "./../overlay.types"; import HPaaSL7 from "../../HPaaSL7"; import { explode, Feature, featureCollection, Point, Polygon, Properties } from "@turf/turf"; import LineModel from "../../../models/LineModel"; import TWEEN from "@tweenjs/tween.js"; import { HpaasEventKey } from "../../types"; import { filterSegmentDataByFeatures } from "../../../../components/report/worker"; class LineTrackBySegmentsOverlay extends Overlay { layers = new Map(); data!: SegmentOverlayData[]; lastZoom = 0; private marker!: Marker; private popup!: Popup; private pointNowIndex = 0; private points: Feature[] = []; private markerLayer = new MarkerLayer({}); private stopLoop = false; constructor(hpaas: HPaaSL7, options: IOverlayOptions) { super(hpaas, options); this.dataOption.filters.forEach((filter) => { this.createOneLayer(filter); }); function animate(time: any) { requestAnimationFrame(animate); TWEEN.update(time); } const iconSize = this.dataOption.pathAnimateIconSize || 30; const el = document.createElement("img"); this.dataOption.pathAnimateIcon && (el.src = this.dataOption.pathAnimateIcon); Object.assign(el.style, { width: iconSize + "px", height: iconSize + "px", boxShadow: "1px 1px 5px #999", border: "2px solid #fff", borderRadius: iconSize + "px", }); this.marker = new Marker({ element: el, offsets: [0, (-1 * iconSize) / 2], }).setLnglat({ lng: 0, lat: 0, }); this.markerLayer.addMarker(this.marker); this.hpaas.l7Scene.addMarkerLayer(this.markerLayer); this.popup = new Popup({ offsets: [iconSize / 2, 0], closeButton: false, stopPropagation: false, anchor: "left", }).setLnglat({ lng: 0, lat: 0 }); // this.markerLayer.addMarker(this._marker); // this.scene.addMarkerLayer(this.markerLayer); this.hpaas.l7Scene.addPopup(this.popup); requestAnimationFrame(animate); } createOneLayer(filter: IOverlayFilter) { // this.hpaas.scene.on("mapmove", () => { // const zoom = this.hpaas.scene.getZoom(); // const w = parseFloat((6 * 1.4 ** (zoom - 17)).toFixed(1)) as any; // if (Math.abs(zoom - this.lastZoom) > 1) { // this.layer?.size(w); // this.checkedLayer?.size(w); // this.lastZoom = zoom; // } // }); } filterDataByDataOption() { console.log("filterDataByDataOption"); if (this.dataOption.show) { this.show(); this.points = []; this.dataOption.filters.forEach((filter) => { const filteredList = filter.checked ? this.data.filter((d) => { return filter.value == "*" || d.filterValue == filter.value; }) : []; filter.totalCount = filteredList.length; this.updateData(filter, filteredList); }); } else { this.hide(); this.layers.forEach((l) => { l.setData(featureCollection([])); }); } } /** * 渲染区域内车次或速度可视化 * @param linesData 渲染数据 * @param colorOption 颜色配置 * @param zIndex 渲染层级 */ renderData(linesData: SegmentOverlayData[]) { console.log("begin overlay line"); if (!this.hpaas.sceneLoaded) { this.hpaas.l7Scene.on("loaded", () => { this.renderData(linesData); }); return; } if (!this.hpaas.segmentLoaded) { this.hpaas.events.on(HpaasEventKey.SEGMENT_DATA_LOADED, () => { this.renderData(linesData); }); return; } linesData.forEach((l) => { const model = Store.segmentsRenderData.get(l.segroad_uid); l.model = model; }); this.data = linesData; this.filterDataByDataOption(); } updateData(filter: IOverlayFilter, linesData: SegmentOverlayData[]) { console.log("segment begin updatedata"); if (!this.hpaas.sceneLoaded) { this.hpaas.l7Scene.on("loaded", () => { this.updateData(filter, linesData); }); return; } const lineModels: LineModel[] = []; linesData.forEach((l) => { if (l.model) { lineModels.push(l.model); if (lineModels.length) { if (l.model.geometry) { const points = explode(l.model.geometry); points.features.forEach((f) => { this.points.push(f); f.properties = l.extends as Properties; }); } } } }); console.log("segment begin render data"); // const geometrys: Feature[] = []; // lineModels.forEach((d) => { // if (this.dataOption.lineArc) { // d.geometry && geometrys.push(d.geometry); // } else { // geometrys.push(d.toTurf()); // } // }); // const featureCollection = featureCollection(geometrys); // // requestAnimationFrame(() => { // console.log("segment start set data"); // this.layers.get(filter.name)?.setData(featureCollection); console.log("segment end render data"); // }); this.popup.open(); this.pointNowIndex = 0; this.startLoop(); } startLoop() { if (!this.points.length) { // this.startLoop(); setTimeout(() => { this.startLoop(); }, 1000); return; } if (this.stopLoop) { return; } this.popup.open(); if (this.pointNowIndex >= this.points.length - 1) { this.pointNowIndex = 0; } const lastPoint = { x: this.points[this.pointNowIndex].geometry.coordinates[0], y: this.points[this.pointNowIndex].geometry.coordinates[1], }; this.pointNowIndex++; const nextPoint = { x: this.points[this.pointNowIndex].geometry.coordinates[0], y: this.points[this.pointNowIndex].geometry.coordinates[1], }; this.dataOption.pathAnimateHTMLTemplate && this.points[this.pointNowIndex] && this.popup.setHTML(this.dataOption.pathAnimateHTMLTemplate(this.points[this.pointNowIndex].properties)); const tween = new TWEEN.Tween(lastPoint) // Create a new tween that modifies 'coords'. .to(nextPoint, 200) // Move to (300, 200) in 1 second. .easing(TWEEN.Easing.Quadratic.Out) // Use an easing function to make the animation smooth. .onUpdate((o) => { this.marker.setLnglat({ lng: o.x, lat: o.y, }); this.popup.setLnglat({ lng: o.x, lat: o.y, }); // Called after tween.js updates 'coords'. // Move 'box' to the position described by 'coords' with a CSS translation. }) .onComplete(() => { this.startLoop(); }); tween.start(); } hide() { this.layers.forEach((l) => { l.hide(); }); this.hpaas.l7Scene.removeMarkerLayer(this.markerLayer); this.stopLoop = true; this.popup.close(); this.pointNowIndex = 0; } show() { this.layers.forEach((l) => { l.show(); }); this.markerLayer.addMarker(this.marker); this.hpaas.l7Scene.addMarkerLayer(this.markerLayer); this.stopLoop = false; this.popup.open(); } async filterByFeature(features: Feature[]) { if (features.length == 0) { this.filterDataByDataOption(); return; } const result = await filterSegmentDataByFeatures(this.data, features); result.forEach((l) => { const model = Store.segmentsRenderData.get(l.segroad_uid); l.model = model; }); this.dataOption.filters.forEach((filter) => { const filteredList = filter.checked ? result.filter((d) => { return filter.value == "*" || d.filterValue == filter.value; }) : []; filter.totalCount = filteredList.length; this.updateData(filter, filteredList); }); } } export default LineTrackBySegmentsOverlay;