airLineStringLayer.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import * as KMap from "@/utils/ol-map/KMap";
  2. import { Circle, Fill, Stroke, Style, Text, Icon } from "ol/style.js";
  3. import LineString from "ol/geom/LineString";
  4. import { newPoint } from "@/utils/map.js";
  5. import Point from "ol/geom/Point";
  6. import { Feature } from "ol";
  7. import { Select } from 'ol/interaction';
  8. import { platformModifierKeyOnly } from 'ol/events/condition';
  9. /**
  10. * @description 地图层对象
  11. */
  12. class airLineStringLayer {
  13. constructor(map) {
  14. let that = this;
  15. this.vectorStyle = new KMap.VectorStyle();
  16. this.lineStringLayer = new KMap.VectorLayer("lineStringLayer", 9999, {
  17. style: this.styleFunction,
  18. });
  19. map.addLayer(this.lineStringLayer.layer);
  20. this.kmap = map;
  21. this.selectedFeatures = []; // 存储选中的要素
  22. this.editMode = false; // 编辑模式标志
  23. // 位置图标
  24. this.pointLayer = new KMap.VectorLayer("pointLayer", 9999, {
  25. style: () => {
  26. return new Style({
  27. image: new Icon({
  28. src: require(`@/assets/images/map/drone-icon.png`),
  29. scale: 0.38,
  30. }),
  31. });
  32. },
  33. });
  34. map.addLayer(this.pointLayer.layer);
  35. // 位置图标
  36. this.pointOfflineLayer = new KMap.VectorLayer("pointOfflineLayer", 9999, {
  37. style: () => {
  38. return new Style({
  39. image: new Icon({
  40. src: require(`@/assets/images/map/drone-offline-icon.png`),
  41. scale: 0.38,
  42. }),
  43. });
  44. },
  45. });
  46. map.addLayer(this.pointOfflineLayer.layer);
  47. // 添加选择交互
  48. this.selectInteraction = new Select({
  49. layers: [this.lineStringLayer.layer],
  50. style: this.getSelectStyle(), // 选中样式
  51. toggleCondition: platformModifierKeyOnly, // 按住Ctrl键多选
  52. multi: true // 允许多选
  53. });
  54. map.map.addInteraction(this.selectInteraction);
  55. // 监听选择变化
  56. this.selectInteraction.on('select', (event) => {
  57. this.selectedFeatures = event.selected;
  58. });
  59. }
  60. // 获取选中要素的样式
  61. getSelectStyle() {
  62. return new Style({
  63. image: new Circle({
  64. radius: 16,
  65. stroke: new Stroke({
  66. color: 'rgba(255, 0, 0, 0.7)',
  67. width: 3
  68. }),
  69. fill: new Fill({
  70. color: 'rgba(255, 0, 0, 0.3)'
  71. })
  72. }),
  73. stroke: new Stroke({
  74. color: 'rgba(255, 0, 0, 0.7)',
  75. width: 3
  76. })
  77. });
  78. }
  79. // 进入编辑模式
  80. enterEditMode() {
  81. this.editMode = true;
  82. this.selectInteraction.setActive(true);
  83. }
  84. // 退出编辑模式
  85. exitEditMode() {
  86. this.editMode = false;
  87. this.selectInteraction.setActive(false);
  88. this.selectInteraction.getFeatures().clear();
  89. this.selectedFeatures = [];
  90. }
  91. // 删除选中的点位
  92. deleteSelectedPoints() {
  93. if (!this.editMode || this.selectedFeatures.length === 0) return;
  94. console.log('this.selectedFeatures', this.selectedFeatures);
  95. const source = this.lineStringLayer.layer.getSource();
  96. // 删除选中的要素
  97. this.selectedFeatures.forEach(feature => {
  98. source.removeFeature(feature);
  99. });
  100. // 重新生成连线
  101. this.regenerateLineString();
  102. // 清空选择
  103. this.selectedFeatures = [];
  104. this.selectInteraction.getFeatures().clear();
  105. }
  106. // 重新生成连线
  107. regenerateLineString() {
  108. const source = this.lineStringLayer.layer.getSource();
  109. const features = source.getFeatures();
  110. // 获取所有点要素并按pointIndex排序
  111. const pointFeatures = features.filter(f => f.getGeometry().getType() === 'Point');
  112. pointFeatures.sort((a, b) => {
  113. return parseInt(a.get('pointIndex')) - parseInt(b.get('pointIndex'));
  114. });
  115. // 提取坐标数组
  116. const coordinates = pointFeatures.map(feature => {
  117. const geom = feature.getGeometry();
  118. return geom.getCoordinates();
  119. });
  120. // 删除旧的线要素
  121. const lineFeatures = features.filter(f => f.getGeometry().getType() === 'LineString');
  122. lineFeatures.forEach(f => source.removeFeature(f));
  123. // 创建新的线要素
  124. if (coordinates.length > 1) {
  125. const lineGeometry = new LineString(coordinates);
  126. const lineFeature = new Feature({
  127. geometry: lineGeometry
  128. });
  129. lineFeature.set("type", 'Online');
  130. source.addFeature(lineFeature);
  131. }
  132. }
  133. styleFunction(feature) {
  134. const type = feature.get('type');
  135. const geometry = feature.getGeometry();
  136. const styles = [];
  137. // 处理线段的样式
  138. if (geometry.getType() === 'LineString') {
  139. styles.push(
  140. new Style({
  141. stroke: new Stroke({
  142. color: type === 'Online' ? '#FFD689' : '#FFFFFF',
  143. width: 3,
  144. }),
  145. })
  146. );
  147. geometry.forEachSegment(function (start, end) {
  148. // 计算中间点坐标
  149. const midX = (start[0] + end[0]) / 2;
  150. const midY = (start[1] + end[1]) / 2;
  151. const midPoint = [midX, midY];
  152. // 计算线段方向角(弧度)
  153. const dx = end[0] - start[0];
  154. const dy = end[1] - start[1];
  155. const rotation = Math.atan2(dy, dx);
  156. // 添加箭头样式
  157. styles.push(
  158. new Style({
  159. geometry: new Point(midPoint),
  160. image: new Icon({
  161. src: require(`@/assets/images/map/${type === 'Online' ? 'arrow' : 'arrow-offline'}-icon.png`),
  162. anchor: [0.5, 0.5],
  163. scale: 0.8,
  164. zIndex: 2,
  165. rotateWithView: true,
  166. rotation: -rotation,
  167. }),
  168. })
  169. );
  170. });
  171. }
  172. // 处理点位的样式
  173. if (geometry.getType() === 'Point') {
  174. styles.push(
  175. new Style({
  176. image: new Icon({
  177. src: require(`@/assets/images/map/${type === 'Online' ? 'air' : 'air-offline'}-icon.png`),
  178. scale: 1,
  179. displacement: [0, 20],
  180. }),
  181. }),
  182. new Style({
  183. image: new Icon({
  184. src: require(`@/assets/images/map/${type === 'Online' ? 'text' : 'text-offline'}-bj.png`),
  185. scale: 0.42,
  186. displacement: [5, 110],
  187. zIndex: 2,
  188. }),
  189. }),
  190. new Style({
  191. text: new Text({
  192. font: "18px PangMenZhengDao",
  193. text: feature.get('pointIndex') || '', // 显示顺序编号
  194. offsetY: -47,
  195. fill: new Fill({ color: "#fff" }),
  196. }),
  197. })
  198. );
  199. }
  200. return styles;
  201. }
  202. initData(droneArr, dronePoint, name) {
  203. this.clearLayer();
  204. //在线数据
  205. const lineCoordinates = {
  206. type: 'Online',
  207. arr: droneArr
  208. };
  209. // 创建线特征
  210. let lineGeometry = new LineString(lineCoordinates.arr);
  211. let lineFeature = new Feature({
  212. geometry: lineGeometry,
  213. });
  214. lineFeature.set("type", lineCoordinates.type);
  215. this.lineStringLayer.addFeature(lineFeature);
  216. // 为每个点位创建单独的特征并设置顺序编号
  217. lineCoordinates.arr.forEach((coord, index) => {
  218. let pointFeature = new Feature({
  219. geometry: new Point(coord),
  220. });
  221. pointFeature.set("type", lineCoordinates.type);
  222. pointFeature.set("pointIndex", (index + 1).toString()); // 设置从1开始的顺序编号
  223. this.lineStringLayer.addFeature(pointFeature);
  224. });
  225. // 添加无人机位置点
  226. const pointVal = { id: 1, wkt: dronePoint, type: 'Online' };
  227. let point = newPoint(pointVal, 'wkt');
  228. this.pointLayer.addFeature(point);
  229. this.kmap.fit(this.lineStringLayer.source.getExtent(), { padding: [230, 230, 230, 230] });
  230. }
  231. clearLayer() {
  232. this.lineStringLayer && this.lineStringLayer.layer.getSource().clear();
  233. this.pointLayer && this.pointLayer.layer.getSource().clear();
  234. this.pointOfflineLayer && this.pointOfflineLayer.layer.getSource().clear();
  235. }
  236. }
  237. export default airLineStringLayer;