| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349 |
- import * as KMap from "@/utils/ol-map/KMap";
- import * as util from "@/common/ol_common.js";
- import config from "@/api/config.js";
- import Style from "ol/style/Style";
- import Icon from "ol/style/Icon";
- import { Fill, Stroke, Text } from "ol/style.js";
- import { Point } from 'ol/geom';
- import Feature from "ol/Feature";
- import * as proj from "ol/proj";
- import { getArea } from 'ol/sphere.js';
- import WKT from "ol/format/WKT.js";
- 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);
- /**
- * @description 地图层对象
- */
- class DrawRegionMap {
- constructor() {
- let that = this;
- let vectorStyle = new KMap.VectorStyle();
- this.vectorStyle = vectorStyle;
- // 是否允许编辑(勾画页 true,小弹窗回显页 false)
- this.editable = true;
- // 位置图标
- this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
- style: () => {
- return new Style({
- image: new Icon({
- src: require("@/assets/img/home/garden-point.png"),
- scale: 0.5,
- anchor: [0.5, 1],
- }),
- });
- },
- });
- // 只读状态区域图层(展示多 polygon,用于“已解决 / 未解决”等状态)
- this.staticRegionLayer = new KMap.VectorLayer("staticRegionLayer", 9998, {
- style: (f) => {
- const status = f.get("status"); // 'resolved' | 'unresolved'
- const isResolved = status === "resolved";
- // 已解决:深灰填充,浅白描边;未解决:浅蓝填充,亮蓝描边
- const fillColor = isResolved ? "rgba(0, 0, 0, 0.6)" : "rgba(0, 0, 0, 0.5)";
- const strokeColor = isResolved ? "#7C7C7C" : "#2199F8";
- const text = new Text({
- text: status === "resolved" ? "已解决" : "未解决",
- font: "12px sans-serif",
- fill: new Fill({ color: "#ffffff" }),
- backgroundFill: new Fill({
- color: isResolved ? "#949494" : "#2199F8"
- }),
- padding: [1, 5, 1, 5],
- });
- const style = new Style({
- fill: new Fill({ color: fillColor }),
- stroke: new Stroke({ color: strokeColor, width: 1 }),
- text: text,
- })
- const text2 = new Style({
- text: new Text({
- text: `发现时间:${f.get("updatedTime")}`,
- font: "12px sans-serif",
- offsetY: -24,
- fill: new Fill({ color: "#ffffff" }),
- backgroundFill: new Fill({
- color: isResolved ? "rgba(171, 171, 171, 0.4)" : "rgba(33, 153, 248, 0.6)"
- }),
- padding: [1, 5, 1, 5],
- }),
- });
- return [style, text2];
- },
- });
- }
- /**
- * 初始化地图
- * @param {string} location WKT 点位
- * @param {HTMLElement|string} target 地图容器
- * @param {boolean} editable 是否允许绘制/编辑地块
- * @param {boolean} movable 是否允许拖动/缩放地图
- * @param {boolean} showPoint 是否显示初始点位图标
- */
- initMap(location, target, editable = true, movable = true, showPoint = true) {
- let level = 16;
- let coordinate = util.wktCastGeom(location).getFirstCoordinate();
- this.kmap = new KMap.Map(target, level, coordinate[0], coordinate[1], null, 8, 22);
- // 记录当前地图是否可编辑,供样式控制使用
- this.editable = editable;
- 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.clickPointLayer.layer);
- this.kmap.addLayer(this.staticRegionLayer.layer);
- // 根据 showPoint 决定是否在初始化时落下点位图标
- if (showPoint) {
- this.setMapPoint(coordinate);
- } else {
- this.clickPointLayer.source.clear();
- }
- // 仅在 editable 为 true 时开启绘制/编辑能力(用于勾画页面)
- if (editable) {
- this.kmap.initDraw((e) => {
- // drawend事件:绘制结束后的处理(支持绘制多个地块)
- })
- this.kmap.startDraw()
- this.kmap.modifyDraw()
- }
- // movable 为 false 时,禁用地图拖动、缩放等交互(用于小弹窗只看不动)
- if (!movable && this.kmap && this.kmap.setStates) {
- this.kmap.setStates({
- DoubleClickZoom: false,
- DragAndDrop: false,
- MouseWheelZoom: false,
- });
- }
- }
- /**
- * 回显地块
- * @param {string[]} geometryArr 多边形 WKT 数组
- * @param {boolean} needFitView 是否自动缩放视图
- * @param {string|number} areaText 显示的面积(单位:亩),可选
- */
- setAreaGeometry(geometryArr, needFitView = false, areaText) {
- // 兜底保护:geometryArr 可能为 undefined/null 或空数组
- if (!Array.isArray(geometryArr) || geometryArr.length === 0) return;
- // 地图实例或图层尚未初始化时也直接返回,避免报错
- if (!this.kmap || !this.kmap.polygonLayer || !this.kmap.polygonLayer.source) return;
- let that = this;
- geometryArr.map(item => {
- // 不使用 setLayerWkt,而是手动添加要素,避免自动缩放视图
- const format = new WKT()
- const mapProjection = that.kmap.map.getView().getProjection()
- let geometry = format.readGeometry(item, {
- dataProjection: 'EPSG:4326',
- featureProjection: mapProjection
- })
- let f = new Feature({ geometry: geometry })
- // 只读模式下,为多边形单独设置样式:仅填充+边框 + 面积文本,不显示可拖动的顶点小圆点
- if (!this.editable) {
- const styles = [
- new Style({
- fill: new Fill({
- color: "rgba(0, 0, 0, 0.5)",
- }),
- stroke: new Stroke({
- color: "#2199F8",
- width: 2,
- }),
- }),
- ];
- // 面积文本(如:24亩),优先使用传入的 areaText
- const textValue = areaText != null && areaText !== ""
- ? `${areaText}亩`
- : "";
- if (textValue) {
- styles.push(
- new Style({
- text: new Text({
- text: textValue,
- font: "15px sans-serif",
- fill: new Fill({ color: "#ffffff" }),
- }),
- })
- );
- }
- f.setStyle(styles);
- }
- that.kmap.polygonLayer.source.addFeature(f)
- })
- // 根据参数决定是否需要自适应地块范围
- if (needFitView) {
- this.fitView()
- }
- }
- fitView() {
- let extent = this.kmap.polygonLayer.source.getExtent()
- // 地图自适应到区域可视范围
- this.kmap.getView().fit(extent, { duration: 500, padding: [100, 100, 100, 100] });
- }
- clearLayer() {
- // this.kmap.removeLayer(this.clickPointLayer.layer)
- if (this.kmap && this.kmap.polygonLayer) {
- this.kmap.polygonLayer.source.clear();
- }
- if (this.staticRegionLayer && this.staticRegionLayer.source) {
- this.staticRegionLayer.source.clear();
- }
- }
- /**
- * 销毁地图实例(用于从编辑态切换到仅查看时重新初始化)
- */
- destroyMap() {
- this.clearLayer();
- if (this.kmap && typeof this.kmap.destroy === "function") {
- this.kmap.destroy();
- }
- this.kmap = null;
- }
- getAreaGeometry() {
- const features = this.kmap.getLayerFeatures()
- let geometryArr = []
- let area = 0
- const format = new WKT()
- // 获取图层上的Polygon,转成WKT用于回显
- features.forEach(item => {
- // 使用 writeGeometry 而不是 writeFeature,因为 setLayerWkt 期望的是几何体的 WKT
- const geometry = item.getGeometry()
- geometryArr.push(format.writeGeometry(geometry, {
- dataProjection: 'EPSG:4326',
- featureProjection: this.kmap.map.getView().getProjection()
- }))
- let geom = geometry.clone()
- geom.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572"))
- let areaItem = getArea(geom)
- areaItem = (areaItem + areaItem / 2) / 1000;
- area += areaItem
- })
- return { geometryArr, mianji: area.toFixed(2) } // 修改为 mianji 字段,与创建页面保持一致
- }
- setMapPosition(center) {
- this.kmap.getView().animate({
- center,
- zoom: 17,
- duration: 500,
- });
- this.setMapPoint(center)
- }
- setMapPoint(coordinate) {
- this.clickPointLayer.source.clear()
- let point = new Feature(new Point(coordinate))
- this.clickPointLayer.addFeature(point)
- }
- // 删除当前地块(删除最新绘制的一个地块)
- deleteCurrentPolygon() {
- if (!this.kmap || !this.kmap.polygonLayer) return;
- const features = this.kmap.polygonLayer.source.getFeatures();
- if (features && features.length > 0) {
- const lastFeature = features[features.length - 1];
- this.kmap.polygonLayer.source.removeFeature(lastFeature);
- }
- }
- /**
- * 设置只读状态区域图层(多个 polygon,不可编辑)
- * @param {Array<{ geometry: string, status?: 'resolved' | 'unresolved' }>} regions
- *
- * 使用示例:
- * drawRegionMap.setStatusRegions([
- * { geometry: 'MULTIPOLYGON(((...)))', status: 'resolved' },
- * { geometry: 'MULTIPOLYGON(((...)))', status: 'unresolved' },
- * ]);
- */
- setStatusRegions(regions) {
- if (!this.kmap || !this.staticRegionLayer || !this.staticRegionLayer.source) return;
- // 仅操作只读图层,不影响当前地图的绘制 / 编辑状态
- this.staticRegionLayer.source.clear();
- if (!Array.isArray(regions) || regions.length === 0) return;
- const format = new WKT();
- const mapProjection = this.kmap.map.getView().getProjection();
- regions.forEach((region) => {
- if (!region || !region.geometry) return;
- try {
- const geometry = format.readGeometry(region.geometry, {
- dataProjection: "EPSG:4326",
- featureProjection: mapProjection,
- });
- const feature = new Feature({ geometry });
- feature.set("status", region.status || "unresolved");
- feature.set("updatedTime", region.updatedTime);
- this.staticRegionLayer.addFeature(feature);
- } catch (e) {
- // 单个区域解析失败时忽略
- }
- });
- // 不在这里直接缩放,避免只按某一层适配视图;
- // 由调用方在需要时统一调用 fitAllRegions 进行视图自适应
- }
- /**
- * 视图自适应到「只读区域图层 + 可编辑多边形图层」的联合范围
- * 适用于同时存在接口返回区域和本地勾画区域时,保证都能出现在视野内
- */
- fitAllRegions() {
- if (!this.kmap) return;
- const extents = [];
- // 只读状态区域图层范围
- if (this.staticRegionLayer && this.staticRegionLayer.source) {
- const features = this.staticRegionLayer.source.getFeatures();
- if (features && features.length > 0) {
- extents.push(this.staticRegionLayer.source.getExtent());
- }
- }
- // 可编辑 polygon 图层范围
- if (this.kmap.polygonLayer && this.kmap.polygonLayer.source) {
- const features = this.kmap.polygonLayer.source.getFeatures();
- if (features && features.length > 0) {
- extents.push(this.kmap.polygonLayer.source.getExtent());
- }
- }
- if (extents.length === 0) return;
- // 计算所有范围的并集 [minX, minY, maxX, maxY]
- const merged = extents.reduce(
- (acc, cur) => {
- if (!acc) return cur.slice();
- return [
- Math.min(acc[0], cur[0]),
- Math.min(acc[1], cur[1]),
- Math.max(acc[2], cur[2]),
- Math.max(acc[3], cur[3]),
- ];
- },
- null
- );
- if (merged) {
- this.kmap.getView().fit(merged, { duration: 500, padding: [100, 100, 100, 100] });
- }
- }
- }
- export default DrawRegionMap;
|