| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336 |
- import * as KMap from "@/utils/ol-map/KMap";
- import * as util from "@/common/ol_common.js";
- import config from "@/api/config.js";
- import { Vector as VectorSource } from "ol/source.js";
- import { Point } from 'ol/geom';
- import { newPoint, newAreaFeature } from "@/utils/map";
- import { GeoJSON, WKT } from 'ol/format'
- import { Feature } from "ol";
- import { getArea } from "ol/sphere"
- import * as turf from "@turf/turf"
- import Style from "ol/style/Style";
- import Icon from "ol/style/Icon";
- import { Fill, Text, Stroke } from "ol/style";
- import Overlay from "ol/Overlay";
- import * as proj from "ol/proj";
- import { buffer as bufferExtent, getWidth, getHeight } from "ol/extent";
- import proj4 from "proj4"
- import { register } from "ol/proj/proj4";
- proj4.defs("EPSG:38572", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs");
- register(proj4);
- /**
- *
- */
- class AreaMap {
- constructor() {
- this.labelOverlays = [];
- this.gardenPolygonLayer = new KMap.VectorLayer("gardenPolygonLayer", 999, {
- minZoom: 8,
- maxZoom: 22,
- source: new VectorSource({}),
- style: (f) => this.getZoneStyle(f),
- });
- // 位置图标
- this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
- style: (f) => {
- let pointIcon = new Style({
- image: new Icon({
- src: require("@/assets/img/home/garden-point.png"),
- scale: 0.5,
- anchor: [0.5, 1],
- }),
- });
- let nameText = new Style({
- text: new Text({
- font: "14px sans-serif",
- text: f.get("name"),
- offsetY: 10,
- fill: new Fill({ color: "#fff" }), // 字体颜色
- stroke: new Stroke({
- color: "#000",
- width: 0.5,
- }),
- }),
- });
- return [pointIcon, nameText]
- },
- });
- }
- getZoneStyle(f) {
- const flySpeed = f.get("fly_speed");
- const labelStyle = f.get("label_style") || (flySpeed ? "card" : "legacy");
- const fillColor = f.get("fill_color") || "#00000080";
- const strokeColor = f.get("stroke_color") || "#2199F8";
- const zoneName = f.get("zone_name") || (f.get("mianji") ? `${f.get("mianji")}亩` : "");
- const styles = [
- new Style({
- fill: new Fill({ color: fillColor }),
- stroke: new Stroke({ color: strokeColor, width: 2 }),
- }),
- ];
- if (!zoneName) return styles;
- if (labelStyle === "legacy") {
- styles.push(
- new Style({
- text: new Text({
- font: "14px sans-serif",
- text: zoneName,
- offsetY: 10,
- fill: new Fill({ color: "#fff" }),
- stroke: new Stroke({
- color: "#000",
- width: 0.5,
- }),
- }),
- })
- );
- return styles;
- }
- if (labelStyle === "simple") {
- styles.push(
- new Style({
- text: new Text({
- text: zoneName,
- font: "13px sans-serif",
- fill: new Fill({ color: "#ffffff" }),
- backgroundFill: new Fill({ color: "rgba(80, 80, 80, 0.85)" }),
- padding: [4, 8, 4, 8],
- }),
- })
- );
- return styles;
- }
- return styles;
- }
- createZoneCardLabelElement(zoneName, flySpeed) {
- const wrap = document.createElement("div");
- Object.assign(wrap.style, {
- background: "#ffffff",
- borderRadius: "4px",
- padding: "6px 10px",
- boxShadow: "0 1px 4px rgba(0, 0, 0, 0.08)",
- textAlign: "center",
- pointerEvents: "none",
- whiteSpace: "nowrap",
- });
- const title = document.createElement("div");
- title.textContent = zoneName;
- Object.assign(title.style, {
- fontSize: "13px",
- fontWeight: "600",
- color: "#262626",
- lineHeight: "18px",
- });
- wrap.appendChild(title);
- if (flySpeed) {
- const sub = document.createElement("div");
- sub.textContent = `飞巡速度:${flySpeed}`;
- Object.assign(sub.style, {
- fontSize: "11px",
- color: "#999999",
- lineHeight: "16px",
- marginTop: "2px",
- });
- wrap.appendChild(sub);
- }
- return wrap;
- }
- clearLabelOverlays() {
- if (!this.labelOverlays?.length || !this.kmap?.map) return;
- this.labelOverlays.forEach((overlay) => {
- this.kmap.map.removeOverlay(overlay);
- });
- this.labelOverlays = [];
- }
- syncLabelOverlays() {
- this.clearLabelOverlays();
- if (!this.kmap?.map || !this.gardenPolygonLayer?.source) return;
- this.gardenPolygonLayer.source.getFeatures().forEach((f) => {
- const flySpeed = f.get("fly_speed");
- const labelStyle = f.get("label_style") || (flySpeed ? "card" : "legacy");
- if (labelStyle !== "card") return;
- const zoneName = f.get("zone_name");
- if (!zoneName) return;
- const geom = f.getGeometry();
- if (!geom?.getInteriorPoint) return;
- const coord = geom.getInteriorPoint().getCoordinates();
- const overlay = new Overlay({
- element: this.createZoneCardLabelElement(zoneName, flySpeed),
- position: coord,
- positioning: "center-center",
- stopEvent: false,
- });
- this.kmap.map.addOverlay(overlay);
- this.labelOverlays.push(overlay);
- });
- }
- initMap(location, target, options = {}) {
- const { interactive = false } = options;
- let level = 16;
- let coordinate = util.wktCastGeom(location).getFirstCoordinate();
- // dragPan / mouseWheelZoom 需在 Map 构造时传入,interactive 为 true 时才能拖拽与缩放
- this.kmap = new KMap.Map(
- target,
- level,
- coordinate[0],
- coordinate[1],
- null,
- 8,
- 22,
- undefined,
- interactive,
- interactive
- );
- if (!interactive && this.kmap?.map) {
- this.kmap.map.getInteractions().forEach((i) => i.setActive(false));
- }
- let xyz2 = config.base_img_url3 + "map/lby/{z}/{x}/{y}.png";
- this.kmap.addXYZLayer(xyz2, { minZoom: 8, maxZoom: 22 }, 2);
- this.kmap.addLayer(this.gardenPolygonLayer.layer);
- this.kmap.addLayer(this.clickPointLayer.layer);
- }
- initLayer(rangeWkt) {
- if (!rangeWkt) {
- this.initZones([]);
- return;
- }
- this.initZones([{ zone_geometry: rangeWkt }]);
- }
- /** @param {{ zone_geometry?: string, zone_name?: string, fly_speed?: string, fill_color?: string, stroke_color?: string, label_style?: 'card'|'simple' }[]} zones */
- initZones(zones) {
- this.clearLabelOverlays();
- if (this.gardenPolygonLayer.source) {
- this.gardenPolygonLayer.source.clear();
- }
- if (this.clickPointLayer.source) {
- this.clickPointLayer.source.clear();
- }
- const list = Array.isArray(zones) ? zones : [];
- const seen = new Set();
- list.forEach((zone) => {
- const wkt =
- typeof zone?.zone_geometry === "string"
- ? zone.zone_geometry.trim()
- : "";
- if (!wkt || seen.has(wkt)) return;
- seen.add(wkt);
- try {
- const f = newAreaFeature({ geomWkt: wkt }, "geomWkt");
- f.set("zone_name", zone.zone_name ?? "");
- if (zone.fly_speed) f.set("fly_speed", zone.fly_speed);
- if (zone.fill_color) f.set("fill_color", zone.fill_color);
- if (zone.stroke_color) f.set("stroke_color", zone.stroke_color);
- if (zone.label_style) f.set("label_style", zone.label_style);
- this.gardenPolygonLayer.source.addFeature(f);
- } catch (e) {
- console.warn("[AreaMap] zone_geometry parse failed", e);
- }
- });
- this.syncLabelOverlays();
- this.fitView();
- }
- /**
- * 调整地图视图以适应地块范围
- */
- fitView() {
- if (!this.kmap?.map) return;
- const map = this.kmap.map;
- map.updateSize();
- let extent = this.gardenPolygonLayer.source.getExtent();
- if (!extent || !Number.isFinite(extent[0])) return;
- const ew = getWidth(extent);
- const eh = getHeight(extent);
- if (ew <= 0 || eh <= 0) return;
- // 略外扩,避免描边贴边、视觉上像被裁切
- extent = bufferExtent(extent, Math.max(ew, eh) * 0.04);
- const size = map.getSize();
- if (!size || size[0] < 4 || size[1] < 4) return;
- const [sw, sh] = size;
- // padding 不能过大:小高度容器里固定 80 会导致内框高度为负,地块无法完整显示
- let padX = Math.max(8, Math.min(48, Math.floor(sw * 0.1)));
- let padY = Math.max(8, Math.min(48, Math.floor(sh * 0.1)));
- let padTop = Math.min(sh - padY - 4, padY + 14);
- let padBottom = padY;
- let padLeft = padX;
- let padRight = padX;
- if (padTop + padBottom >= sh - 2) {
- const p = Math.max(4, Math.floor(sh / 6));
- padTop = padBottom = p;
- }
- if (padLeft + padRight >= sw - 2) {
- const p = Math.max(4, Math.floor(sw / 6));
- padLeft = padRight = p;
- }
- this.kmap.getView().fit(extent, {
- size,
- duration: 80,
- padding: [padTop, padRight, padBottom, padLeft],
- maxZoom: 22,
- });
- }
- fitByGardenId(gardenId, hasMapAnimate) {
- this.gardenPolygonLayer.source.forEachFeature((f) => {
- if (f.get("organId") == gardenId) {
- const extent = f.getGeometry().getExtent()
- this.kmap.getView().fit(extent, { padding: [60, 60, 60, 60], duration: hasMapAnimate ? 1500 : 0 });
- const currentZoom = this.kmap.getView().getZoom();
- if (currentZoom > 16) {
- // this.kmap.getView().setZoom(16);
- this.kmap.getView().animate({
- zoom: 16,
- duration: hasMapAnimate ? 1500 : 0 // 动画持续时间,单位为毫秒
- });
- }
- }
- })
- }
- destroyMap() {
- this.clearLabelOverlays();
- if (this.gardenPolygonLayer?.source) {
- this.gardenPolygonLayer.source.clear();
- }
- if (this.clickPointLayer?.source) {
- this.clickPointLayer.source.clear();
- }
- if (this.kmap && typeof this.kmap.destroy === "function") {
- this.kmap.destroy();
- }
- this.kmap = null;
- }
- }
- export default AreaMap;
|