locationSelectMap.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. import * as KMap from "@/utils/ol-map/KMap";
  2. import config from "@/api/config";
  3. import { wktCastGeom, newAreaFeature } from "@/common/ol_common";
  4. import { unByKey } from "ol/Observable";
  5. import Feature from "ol/Feature";
  6. import { Point } from "ol/geom";
  7. import Style from "ol/style/Style";
  8. import Icon from "ol/style/Icon";
  9. import mapPointImg from "@/assets/page/map-point.png";
  10. /** 与 workDetail/areaMap 默认中心一致 */
  11. const DEFAULT_LOCATION = "POINT(113.61448114737868 23.585550924763083)";
  12. /**
  13. * 存放点位选择地图
  14. * - 展示蓝区范围(不可点选)
  15. * - 地图中心默认点位图标,点击地图移动点位
  16. */
  17. export default class LocationSelectMap {
  18. constructor() {
  19. const vectorStyle = new KMap.VectorStyle();
  20. this.vectorStyle = vectorStyle;
  21. this.kmap = null;
  22. this.clickKey = null;
  23. this.pointFeature = null;
  24. this.blueRegionLayer = new KMap.VectorLayer("blueRegionLayer", 99999, {
  25. minZoom: 1,
  26. maxZoom: 22,
  27. style: () =>
  28. vectorStyle.getPolygonStyle(
  29. "rgba(0, 0, 0, 0.45)",
  30. "rgba(255, 212, 137, 0.85)",
  31. 1.5
  32. ),
  33. });
  34. this.pointLayer = new KMap.VectorLayer("locationPointLayer", 100000, {
  35. minZoom: 1,
  36. maxZoom: 22,
  37. style: new Style({
  38. image: new Icon({
  39. src: mapPointImg,
  40. scale: 0.55,
  41. anchor: [0.5, 1],
  42. anchorXUnits: "fraction",
  43. anchorYUnits: "fraction",
  44. }),
  45. }),
  46. });
  47. }
  48. /**
  49. * @param {HTMLElement} target
  50. * @param {string} location WKT,优先用于点位初始位置
  51. */
  52. init(target, location = DEFAULT_LOCATION) {
  53. this.destroy();
  54. const level = 16;
  55. const coordinate = wktCastGeom(location).getFirstCoordinate();
  56. this.kmap = new KMap.Map(
  57. target,
  58. level,
  59. coordinate[0],
  60. coordinate[1],
  61. null,
  62. 1,
  63. 22,
  64. "vec",
  65. true,
  66. true
  67. );
  68. this.kmap.addLayer(this.blueRegionLayer.layer);
  69. this.kmap.addLayer(this.pointLayer.layer);
  70. const xyz = config.base_img_url + "map/lby/{z}/{x}/{y}.png";
  71. this.kmap.addXYZLayer(xyz, { minZoom: 8, maxZoom: 22 }, 2);
  72. // 点位等区域加载并 fit 完成后再放置,避免闪一下
  73. this.addMapSingleClick();
  74. setTimeout(() => this.updateSize(), 80);
  75. }
  76. addMapSingleClick() {
  77. this.clickKey = this.kmap.on("singleclick", (evt) => {
  78. this.setPoint(evt.coordinate);
  79. });
  80. }
  81. /** @param {[number, number]} coordinate [lng, lat] */
  82. setPoint(coordinate) {
  83. if (!this.pointLayer?.source || !coordinate) return;
  84. if (this.pointFeature) {
  85. this.pointFeature.getGeometry().setCoordinates(coordinate);
  86. return;
  87. }
  88. this.pointFeature = new Feature({
  89. geometry: new Point(coordinate),
  90. });
  91. this.pointFeature.set("nodeType", "location");
  92. this.pointLayer.addFeature(this.pointFeature);
  93. }
  94. /**
  95. * 仅展示蓝区,不可点击选择
  96. * @param {Array} list
  97. */
  98. setRegions(list = []) {
  99. if (!this.blueRegionLayer?.source) return;
  100. this.blueRegionLayer.source.clear();
  101. for (const item of list) {
  102. const wkt = item.geom || item.wkt;
  103. if (!wkt) continue;
  104. const id = item.blueZoneCode ?? item.id;
  105. const feature = newAreaFeature({
  106. ...item,
  107. geom: wkt,
  108. id,
  109. name: item.name || item.regionName || item.blueZoneName || String(id),
  110. });
  111. this.blueRegionLayer.addFeature(feature);
  112. }
  113. this.fitToRegions();
  114. }
  115. fitToRegions() {
  116. const extent = this.blueRegionLayer?.source?.getExtent?.();
  117. if (!extent || !isFinite(extent[0]) || !this.kmap) return;
  118. // 无动画,避免 fit 过程中点位位置错乱
  119. this.kmap.fit(extent, { padding: [40, 40, 40, 40], duration: 0, maxZoom: 18 });
  120. }
  121. /** 将点位放到当前地图中心 */
  122. setPointToCenter() {
  123. const center = this.kmap?.view?.getCenter?.();
  124. if (center) this.setPoint(center);
  125. }
  126. getPoint() {
  127. if (!this.pointFeature) return null;
  128. const [lng, lat] = this.pointFeature.getGeometry().getCoordinates();
  129. return {
  130. lng,
  131. lat,
  132. wkt: `POINT(${lng} ${lat})`,
  133. label: `POINT(${Number(lng).toFixed(6)} ${Number(lat).toFixed(6)})`,
  134. };
  135. }
  136. updateSize() {
  137. this.kmap?.updateSize?.() || this.kmap?.map?.updateSize?.();
  138. }
  139. destroy() {
  140. if (this.clickKey) {
  141. unByKey(this.clickKey);
  142. this.clickKey = null;
  143. }
  144. this.blueRegionLayer?.source?.clear?.();
  145. this.pointLayer?.source?.clear?.();
  146. this.pointFeature = null;
  147. this.kmap?.destroy?.();
  148. this.kmap = null;
  149. }
  150. }