|
@@ -19,54 +19,118 @@ import { boundingExtent, getCenter } from "ol/extent.js";
|
|
import RegionLayer from "./map/regionLayer";
|
|
import RegionLayer from "./map/regionLayer";
|
|
import eventBus from "@/api/eventBus";
|
|
import eventBus from "@/api/eventBus";
|
|
import albumCarousel from "./album_compoents/albumCarousel.vue";
|
|
import albumCarousel from "./album_compoents/albumCarousel.vue";
|
|
-// import MockFarmLayer from "./map/mockFarmLayer";
|
|
|
|
-
|
|
|
|
import { onMounted, ref } from "vue";
|
|
import { onMounted, ref } from "vue";
|
|
import { useStore } from "vuex";
|
|
import { useStore } from "vuex";
|
|
import { unByKey } from "ol/Observable";
|
|
import { unByKey } from "ol/Observable";
|
|
-let store = useStore();
|
|
|
|
-
|
|
|
|
-// 选中样式(高亮)
|
|
|
|
-// const selectedStyle = new Style({
|
|
|
|
-// image: new Icon({
|
|
|
|
-// src: require("@/assets/images/map/status/active-icon.png"),
|
|
|
|
-// scale: 0.6,
|
|
|
|
-// }),
|
|
|
|
-// });
|
|
|
|
|
|
|
|
-let kmap = null;
|
|
|
|
|
|
+const store = useStore();
|
|
const areaRef = ref(null);
|
|
const areaRef = ref(null);
|
|
-// let mockFarmLayer = null;
|
|
|
|
-let dragBox;
|
|
|
|
|
|
+const currentTree = ref(null);
|
|
|
|
+const isDrawing = ref(false);
|
|
|
|
+const mapPoint = ref([]);
|
|
|
|
+let kmap = null;
|
|
|
|
+let treeClusterLayer = null;
|
|
|
|
+let dragBox = null;
|
|
|
|
+let listenKey = null;
|
|
|
|
+let regionLayer = null;
|
|
|
|
+let clusterSource = null;
|
|
|
|
+
|
|
|
|
+// 样式缓存优化
|
|
|
|
+// 样式缓存优化 - 确保所有样式都正确初始化
|
|
|
|
+const styleCache = {
|
|
|
|
+ default: new Style({
|
|
|
|
+ image: new Circle({
|
|
|
|
+ radius: 10,
|
|
|
|
+ fill: new Fill({ color: "#ffffff00" }),
|
|
|
|
+ stroke: new Stroke({ color: "#fff", width: 1 }),
|
|
|
|
+ }),
|
|
|
|
+ }),
|
|
|
|
+ selected: new Style({
|
|
|
|
+ image: new Icon({
|
|
|
|
+ src: require("@/assets/images/map/status/active-icon.png"),
|
|
|
|
+ scale: 0.6,
|
|
|
|
+ crossOrigin: 'anonymous' // 添加crossOrigin属性
|
|
|
|
+ }),
|
|
|
|
+ }),
|
|
|
|
+ current: new Style({
|
|
|
|
+ image: new Icon({
|
|
|
|
+ src: require("@/assets/images/map/status/current-icon.png"),
|
|
|
|
+ scale: 0.8,
|
|
|
|
+ crossOrigin: 'anonymous'
|
|
|
|
+ }),
|
|
|
|
+ }),
|
|
|
|
+ renYang1: new Style({
|
|
|
|
+ image: new Circle({
|
|
|
|
+ radius: 12,
|
|
|
|
+ fill: new Fill({ color: "#EEEEEE" }),
|
|
|
|
+ stroke: new Stroke({ color: "#fff", width: 1 }),
|
|
|
|
+ }),
|
|
|
|
+ }),
|
|
|
|
+ renYang2: new Style({
|
|
|
|
+ image: new Circle({
|
|
|
|
+ radius: 12,
|
|
|
|
+ fill: new Fill({ color: "#F0AC37" }),
|
|
|
|
+ stroke: new Stroke({ color: "#fff", width: 1 }),
|
|
|
|
+ }),
|
|
|
|
+ }),
|
|
|
|
+ clusterText: (size, isRenyang) => new Style({
|
|
|
|
+ text: new Text({
|
|
|
|
+ text: size.toString(),
|
|
|
|
+ font: "bold 10px sans-serif",
|
|
|
|
+ fill: new Fill({ color: isRenyang === 1 ? "#000" : "#fff" }),
|
|
|
|
+ }),
|
|
|
|
+ zIndex: 3,
|
|
|
|
+ }),
|
|
|
|
+ photoStyle: (src) => {
|
|
|
|
+ try {
|
|
|
|
+ return new Style({
|
|
|
|
+ image: new Photo({
|
|
|
|
+ src: src,
|
|
|
|
+ kind: "circle",
|
|
|
|
+ radius: 22,
|
|
|
|
+ shadow: 0,
|
|
|
|
+ crop: false,
|
|
|
|
+ displacement: [0, 0],
|
|
|
|
+ stroke: new Stroke({ width: 2, color: "#fff" }),
|
|
|
|
+ }),
|
|
|
|
+ zIndex: 4
|
|
|
|
+ });
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.warn('Failed to create photo style:', e);
|
|
|
|
+ return new Style({
|
|
|
|
+ image: new Circle({
|
|
|
|
+ radius: 12,
|
|
|
|
+ fill: new Fill({ color: "#F0AC37" }),
|
|
|
|
+ stroke: new Stroke({ color: "#fff", width: 1 }),
|
|
|
|
+ }),
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
|
|
-const currentTree = ref(null)
|
|
|
|
|
|
+// 初始化地图
|
|
|
|
+onMounted(() => {
|
|
|
|
+ const level = 16;
|
|
|
|
+ const coordinate = util.wktCastGeom(store.getters.userinfo.location).getFirstCoordinate();
|
|
|
|
+ kmap = new KMap.Map(areaRef.value, level, coordinate[0], coordinate[1], null, 1, 22, "img", true, true);
|
|
|
|
+ regionLayer = new RegionLayer(kmap);
|
|
|
|
+});
|
|
|
|
|
|
-const isDrawing = ref(false);
|
|
|
|
|
|
+// 启用框选
|
|
const enableBoxSelect = () => {
|
|
const enableBoxSelect = () => {
|
|
- const data = mapPoint.value.filter((item) => !item.isRenyang);
|
|
|
|
- addCluster(data, 1);
|
|
|
|
|
|
+ const data = mapPoint.value.filter(item => !item.isRenyang);
|
|
|
|
+ updateClusterData(data, 1);
|
|
isDrawing.value = true;
|
|
isDrawing.value = true;
|
|
|
|
+
|
|
dragBox = new DragBox({
|
|
dragBox = new DragBox({
|
|
- condition: platformModifierKeyOnly, // 按住 Ctrl 才可框选(可去掉)
|
|
|
|
|
|
+ condition: platformModifierKeyOnly,
|
|
});
|
|
});
|
|
|
|
|
|
- // 添加键盘事件监听
|
|
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
window.addEventListener("keydown", handleKeyDown);
|
|
window.addEventListener("keyup", handleKeyUp);
|
|
window.addEventListener("keyup", handleKeyUp);
|
|
|
|
|
|
kmap.map.addInteraction(dragBox);
|
|
kmap.map.addInteraction(dragBox);
|
|
- // areaRef.value.style.cursor = 'crosshair';
|
|
|
|
- dragBox.on("boxend", () => {
|
|
|
|
- const extent = dragBox.getGeometry().getExtent();
|
|
|
|
-
|
|
|
|
- treeClusterLayer.layer.getSource().getSource().getFeatures().forEach((feature) => {
|
|
|
|
- const isInside = feature.getGeometry().intersectsExtent(extent);
|
|
|
|
- if (isInside) {
|
|
|
|
- // feature.setStyle(selectedStyle);
|
|
|
|
- feature.set("highlight", true);
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- });
|
|
|
|
|
|
+ dragBox.on("boxend", handleBoxEnd);
|
|
};
|
|
};
|
|
|
|
|
|
const handleKeyDown = (e) => {
|
|
const handleKeyDown = (e) => {
|
|
@@ -81,309 +145,272 @@ const handleKeyUp = (e) => {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+const handleBoxEnd = () => {
|
|
|
|
+ const extent = dragBox.getGeometry().getExtent();
|
|
|
|
+ treeClusterLayer.layer.getSource().getSource().getFeatures().forEach(feature => {
|
|
|
|
+ // 只对当前框选范围内且未被认养的树进行操作
|
|
|
|
+ if (feature.getGeometry().intersectsExtent(extent)) {
|
|
|
|
+ // 累加选中状态(不会取消之前选中的)
|
|
|
|
+ if (!feature.get("isRenyang")) {
|
|
|
|
+ feature.set("highlight", true);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ refreshClusterStyle();
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 停止框选
|
|
const stopBoxSelect = () => {
|
|
const stopBoxSelect = () => {
|
|
- addCluster(mapPoint.value);
|
|
|
|
|
|
+ updateClusterData(mapPoint.value);
|
|
kmap.map.removeInteraction(dragBox);
|
|
kmap.map.removeInteraction(dragBox);
|
|
- isDrawing.value = false
|
|
|
|
- // 移除事件监听
|
|
|
|
|
|
+ isDrawing.value = false;
|
|
window.removeEventListener("keydown", handleKeyDown);
|
|
window.removeEventListener("keydown", handleKeyDown);
|
|
window.removeEventListener("keyup", handleKeyUp);
|
|
window.removeEventListener("keyup", handleKeyUp);
|
|
};
|
|
};
|
|
|
|
|
|
-function saveSelect(callback) {
|
|
|
|
- let sampleIds = []
|
|
|
|
- treeClusterLayer.layer.getSource().getSource().getFeatures().forEach((feature) => {
|
|
|
|
|
|
+// 保存选择
|
|
|
|
+const saveSelect = (callback) => {
|
|
|
|
+ const sampleIds = [];
|
|
|
|
+ treeClusterLayer.layer.getSource().getSource().getFeatures().forEach(feature => {
|
|
if (feature.get("highlight")) {
|
|
if (feature.get("highlight")) {
|
|
- sampleIds.push(feature.get("sampleId"))
|
|
|
|
|
|
+ sampleIds.push(feature.get("sampleId"));
|
|
}
|
|
}
|
|
- })
|
|
|
|
|
|
+ });
|
|
|
|
+
|
|
const params = {
|
|
const params = {
|
|
sampleIds,
|
|
sampleIds,
|
|
isRenyang: 1,
|
|
isRenyang: 1,
|
|
farmId: Number(sessionStorage.getItem("currentFarmId"))
|
|
farmId: Number(sessionStorage.getItem("currentFarmId"))
|
|
- }
|
|
|
|
- VE_API.manage_interface.batchOpenOrCloseSample(params).then(() => {
|
|
|
|
- callback && callback()
|
|
|
|
- })
|
|
|
|
- console.log('sampleIds', sampleIds);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-let treeClusterLayer;
|
|
|
|
-onMounted(() => {
|
|
|
|
- let level = 16;
|
|
|
|
- let coordinate = util.wktCastGeom(store.getters.userinfo.location).getFirstCoordinate();
|
|
|
|
- kmap = new KMap.Map(areaRef.value, level, coordinate[0], coordinate[1], null, 1, 22, "img", true, true);
|
|
|
|
- regionLayer = new RegionLayer(kmap);
|
|
|
|
- // mockFarmLayer = new MockFarmLayer(kmap)
|
|
|
|
- // VE_API.info.contactsList().then(res => {
|
|
|
|
- // if(res.code ===0){
|
|
|
|
- // mockFarmLayer.setData(res.data)
|
|
|
|
- // }
|
|
|
|
- // })
|
|
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ VE_API.manage_interface.batchOpenOrCloseSample(params).then(() => {// 保存成功后刷新数据
|
|
|
|
+ callback?.();
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
|
|
-});
|
|
|
|
-let styleCache = {};
|
|
|
|
-let listenKey;
|
|
|
|
-const mapPoint = ref([]);
|
|
|
|
-let clusterSource;
|
|
|
|
-// --------聚合-----------
|
|
|
|
-function addCluster(treeListData, distanceVal) {
|
|
|
|
- if (!distanceVal) {
|
|
|
|
|
|
+// 更新集群数据而不重新渲染整个图层
|
|
|
|
+const updateClusterData = (treeListData, distanceVal = 20) => {
|
|
|
|
+ if (!treeListData || !Array.isArray(treeListData)) {
|
|
|
|
+ console.error('Invalid data provided to updateClusterData');
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ if (distanceVal === 20) {
|
|
mapPoint.value = treeListData;
|
|
mapPoint.value = treeListData;
|
|
}
|
|
}
|
|
- clearCluster();
|
|
|
|
- let features = [];
|
|
|
|
- // 根据状态加上对应的图标
|
|
|
|
- for (let item of treeListData) {
|
|
|
|
|
|
+ const features = treeListData.map(item => {
|
|
try {
|
|
try {
|
|
- item.wkt = item.geom
|
|
|
|
- let point = newPoint(item);
|
|
|
|
- features.push(point);
|
|
|
|
|
|
+ item.wkt = item.geom;
|
|
|
|
+ return newPoint(item);
|
|
} catch (err) {
|
|
} catch (err) {
|
|
- console.error('err', err)
|
|
|
|
|
|
+ console.error('Error creating point:', err);
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+ }).filter(Boolean);
|
|
|
|
+
|
|
|
|
+ if (!treeClusterLayer) {
|
|
|
|
+ createClusterLayer(features, distanceVal);
|
|
|
|
+ } else {
|
|
|
|
+ // 只更新数据源而不重新创建图层
|
|
|
|
+ clusterSource.getSource().clear();
|
|
|
|
+ clusterSource.getSource().addFeatures(features);
|
|
|
|
+ clusterSource.setDistance(distanceVal);
|
|
|
|
+
|
|
|
|
+ if (!distanceVal) {
|
|
|
|
+ zoomToFeatures(features);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- const source = new VectorSource({
|
|
|
|
- features: features,
|
|
|
|
- });
|
|
|
|
- clusterSource = new Cluster({
|
|
|
|
- distance: distanceVal ? distanceVal : 20, // 集合范围
|
|
|
|
- // minDistance: 60,
|
|
|
|
- source: source,
|
|
|
|
- });
|
|
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 创建集群图层
|
|
|
|
+const createClusterLayer = (features, distance) => {
|
|
|
|
+ const source = new VectorSource({ features });
|
|
|
|
+ clusterSource = new Cluster({ distance, source });
|
|
|
|
|
|
treeClusterLayer = new KMap.VectorLayer("forest-cluster", 1000, {
|
|
treeClusterLayer = new KMap.VectorLayer("forest-cluster", 1000, {
|
|
minZoom: 15,
|
|
minZoom: 15,
|
|
source: clusterSource,
|
|
source: clusterSource,
|
|
- style: (feature) => {
|
|
|
|
- const size = feature.get("features").length;
|
|
|
|
- let testStyle;
|
|
|
|
- // 只有一个数据,不需要聚合,直接使用第一项数据的图标
|
|
|
|
- if (size == 1) {
|
|
|
|
- let featureOne = feature.get("features")[0];
|
|
|
|
- const key = featureOne.get('isRenyang')+"status"
|
|
|
|
- let style = styleCache[key];
|
|
|
|
- // let style = false;
|
|
|
|
- if (!style) {
|
|
|
|
- const highlight = featureOne.get("highlight");
|
|
|
|
- const currentTree = featureOne.get("currentTree");
|
|
|
|
- if (highlight) {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Icon({
|
|
|
|
- src: require("@/assets/images/map/status/active-icon.png"),
|
|
|
|
- scale: 0.6,
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- } else if (currentTree) {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Icon({
|
|
|
|
- src: require("@/assets/images/map/status/current-icon.png"),
|
|
|
|
- scale: 0.8,
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Circle({
|
|
|
|
- radius: featureOne.get("isRenyang") === 0 || !featureOne.get("isRenyang") ? 10 : 12,
|
|
|
|
- fill: new Fill({
|
|
|
|
- color:
|
|
|
|
- featureOne.get("isRenyang") === 0
|
|
|
|
- ? "#ffffff00"
|
|
|
|
- : featureOne.get("isRenyang") === 1
|
|
|
|
- ? "#EEEEEE"
|
|
|
|
- : featureOne.get("isRenyang") === 2
|
|
|
|
- ? "#F0AC37"
|
|
|
|
- : "#ffffff00",
|
|
|
|
- }),
|
|
|
|
- stroke: new Stroke({
|
|
|
|
- color: "#fff",
|
|
|
|
- width: 1,
|
|
|
|
- }),
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- // styleCache[key] = style;
|
|
|
|
- }
|
|
|
|
- const imgIcon = featureOne.get('icon')
|
|
|
|
- if (imgIcon) {
|
|
|
|
- style = new Style({
|
|
|
|
- // image: new Icon({
|
|
|
|
- // src: imgIcon,
|
|
|
|
- // scale: 1,
|
|
|
|
- // }),
|
|
|
|
- image: new Photo({
|
|
|
|
- src: imgIcon,
|
|
|
|
- kind: "circle",
|
|
|
|
- radius: 22,
|
|
|
|
- shadow: 0,
|
|
|
|
- crop: false,
|
|
|
|
- displacement: [0, 0],
|
|
|
|
- stroke: new Stroke({
|
|
|
|
- width: 2,
|
|
|
|
- color: "#fff",
|
|
|
|
- }),
|
|
|
|
- }),
|
|
|
|
- zIndex: 4
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- return style;
|
|
|
|
- }
|
|
|
|
- // 多个点位聚合,循环处理得到图标
|
|
|
|
- const featureObj = feature.get("features")[0];
|
|
|
|
- // let pointId = featureObj.get('isRenyang')
|
|
|
|
- // let style = styleCache[pointId];
|
|
|
|
- const imgIcon = featureObj.get('icon')
|
|
|
|
- let style = false;
|
|
|
|
- if (!style) {
|
|
|
|
- testStyle = new Style({
|
|
|
|
- text: new Text({
|
|
|
|
- text: size + "",
|
|
|
|
- offsetX: 0,
|
|
|
|
- offsetY: 0,
|
|
|
|
- font: "bold 10px sans-serif",
|
|
|
|
- fill: new Fill({ color: featureObj.get("isRenyang") === 1 ? "#000" : "#fff" }), // 字体颜色
|
|
|
|
- // stroke: new Stroke({ color: "green" }), // 字体颜色
|
|
|
|
- }),
|
|
|
|
- zIndex: 3,
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- const highlight = featureObj.get("highlight");
|
|
|
|
- const currentTree = featureObj.get("currentTree");
|
|
|
|
- if (highlight) {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Icon({
|
|
|
|
- src: require("@/assets/images/map/status/active-icon.png"),
|
|
|
|
- scale: 0.6,
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- } else if (currentTree) {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Icon({
|
|
|
|
- src: require("@/assets/images/map/status/current-icon.png"),
|
|
|
|
- scale: 0.8,
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- // 已认养--显示图标
|
|
|
|
- if (imgIcon) {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Photo({
|
|
|
|
- src: imgIcon,
|
|
|
|
- kind: "circle",
|
|
|
|
- radius: 22,
|
|
|
|
- shadow: 0,
|
|
|
|
- crop: false,
|
|
|
|
- displacement: [0, 0],
|
|
|
|
- stroke: new Stroke({
|
|
|
|
- width: 2,
|
|
|
|
- color: "#fff",
|
|
|
|
- }),
|
|
|
|
- }),
|
|
|
|
- zIndex: 4
|
|
|
|
- });
|
|
|
|
- } else {
|
|
|
|
- style = new Style({
|
|
|
|
- image: new Circle({
|
|
|
|
- radius: featureObj.get("isRenyang") === 0 || !featureObj.get("isRenyang") ? 10 : 12,
|
|
|
|
- fill: new Fill({
|
|
|
|
- color:
|
|
|
|
- featureObj.get("isRenyang") === 0
|
|
|
|
- ? "#ffffff00"
|
|
|
|
- : featureObj.get("isRenyang") === 1
|
|
|
|
- ? "#EEEEEE"
|
|
|
|
- : featureObj.get("isRenyang") === 2
|
|
|
|
- ? "#F0AC37"
|
|
|
|
- : "#ffffff00",
|
|
|
|
- }),
|
|
|
|
- stroke: new Stroke({
|
|
|
|
- color: "#fff",
|
|
|
|
- width: 1,
|
|
|
|
- }),
|
|
|
|
- }),
|
|
|
|
- });
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // styleCache[pointId] = style;
|
|
|
|
- }
|
|
|
|
- return [style, testStyle];
|
|
|
|
- },
|
|
|
|
|
|
+ style: clusterStyleFunction
|
|
});
|
|
});
|
|
|
|
|
|
kmap.addLayer(treeClusterLayer.layer);
|
|
kmap.addLayer(treeClusterLayer.layer);
|
|
|
|
+ // if (!distance) {
|
|
|
|
+ // }
|
|
|
|
+ zoomToFeatures(features);
|
|
|
|
+
|
|
|
|
+ setupMapClickHandler();
|
|
|
|
+};
|
|
|
|
|
|
- if(!distanceVal) {
|
|
|
|
- zoomToFeatures(features)
|
|
|
|
|
|
+// 更新后的集群样式函数
|
|
|
|
+const clusterStyleFunction = (feature) => {
|
|
|
|
+ const size = feature.get("features").length;
|
|
|
|
+ const features = feature.get("features");
|
|
|
|
+
|
|
|
|
+ if (!features || features.length === 0) {
|
|
|
|
+ return new Style({}); // 返回空样式作为fallback
|
|
}
|
|
}
|
|
- // kmap.getView().fit(this.treeClusterLayer.layer.getSource().getSource().getExtent(), { duration: 1000, padding: [120, 120, 200, 120] });
|
|
|
|
- // 监听聚合点位的点击,点击后缩放到范围内
|
|
|
|
- listenKey = kmap.on("click", (e) => {
|
|
|
|
- if (treeClusterLayer) {
|
|
|
|
- treeClusterLayer.layer.getFeatures(e.pixel).then((clickedFeatures, layer) => {
|
|
|
|
- let hasFeatures = false
|
|
|
|
- if (clickedFeatures.length) {
|
|
|
|
- const features = clickedFeatures[0].get("features");
|
|
|
|
- if (features.length > 1) {
|
|
|
|
- hasFeatures = true
|
|
|
|
- const extent = boundingExtent(features.map((r) => r.getGeometry().getCoordinates()));
|
|
|
|
- kmap.getView().fit(extent, { duration: 1000, padding: [250, 250, 250, 250] });
|
|
|
|
-
|
|
|
|
- const currentZoom = kmap.getView().getZoom();
|
|
|
|
- if (currentZoom > 17) {
|
|
|
|
- // this.kmap.getView().setZoom(16);
|
|
|
|
- // kmap.getView().animate({
|
|
|
|
- // zoom: 14,
|
|
|
|
- // duration: 0 // 动画持续时间,单位为毫秒
|
|
|
|
- // });
|
|
|
|
- kmap.getView().setZoom(17)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (isDrawing.value) {
|
|
|
|
- features[0].set("highlight", true);
|
|
|
|
- // features[0].setStyle(selectedStyle)
|
|
|
|
- } else if (!hasFeatures) {
|
|
|
|
- resetCurrentTree()
|
|
|
|
- features[0].set("currentTree", true)
|
|
|
|
- const fs = features[0]
|
|
|
|
- currentTree.value = features[0]
|
|
|
|
- console.log('hasFeatures', fs);
|
|
|
|
- eventBus.emit("click:point", { farmId: Number(sessionStorage.getItem("currentFarmId")), sampleId: fs.get("sampleId"), data: fs.getProperties() })
|
|
|
|
- // eventBus.emit("clickMapPoint", features[0])
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
|
|
+
|
|
|
|
+ if (size === 1) {
|
|
|
|
+ return getSingleFeatureStyle(features[0]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return getClusterFeatureStyle(features[0], size);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 更新后的获取单个要素样式函数
|
|
|
|
+const getSingleFeatureStyle = (feature) => {
|
|
|
|
+ if (!feature) return new Style({}); // 防御性编程
|
|
|
|
+
|
|
|
|
+ // 有图标的使用照片样式优先
|
|
|
|
+ const imgIcon = feature.get('icon');
|
|
|
|
+ if (imgIcon) {
|
|
|
|
+ try {
|
|
|
|
+ return styleCache.photoStyle(imgIcon);
|
|
|
|
+ } catch (e) {
|
|
|
|
+ console.warn('Failed to create photo style:', e);
|
|
|
|
+ return styleCache.default;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // 高亮样式其次
|
|
|
|
+ if (feature.get("highlight")) {
|
|
|
|
+ return styleCache.selected;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 当前树样式其次
|
|
|
|
+ if (feature.get("currentTree")) {
|
|
|
|
+ return styleCache.current;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // 根据认养状态返回不同样式
|
|
|
|
+ const isRenyang = feature.get("isRenyang");
|
|
|
|
+ switch (isRenyang) {
|
|
|
|
+ case 1: return styleCache.renYang1;
|
|
|
|
+ case 2: return styleCache.renYang2;
|
|
|
|
+ default: return styleCache.default;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 更新后的获取集群要素样式函数
|
|
|
|
+const getClusterFeatureStyle = (feature, size) => {
|
|
|
|
+ if (!feature) return [styleCache.default];
|
|
|
|
+
|
|
|
|
+ const styles = [];
|
|
|
|
+ const baseStyle = getSingleFeatureStyle(feature);
|
|
|
|
+
|
|
|
|
+ // 确保基础样式有效
|
|
|
|
+ if (baseStyle) {
|
|
|
|
+ styles.push(baseStyle);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 添加集群文字样式
|
|
|
|
+ if (size > 1) {
|
|
|
|
+ const textStyle = styleCache.clusterText(size, feature.get("isRenyang"));
|
|
|
|
+ if (textStyle) {
|
|
|
|
+ styles.push(textStyle);
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return styles.length > 0 ? styles : [styleCache.default];
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 刷新集群样式(不重新创建图层)
|
|
|
|
+const refreshClusterStyle = () => {
|
|
|
|
+ if (treeClusterLayer) {
|
|
|
|
+ treeClusterLayer.layer.getSource().refresh();
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 设置地图点击处理
|
|
|
|
+const setupMapClickHandler = () => {
|
|
|
|
+ if (listenKey) {
|
|
|
|
+ unByKey(listenKey);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ listenKey = kmap.on("click", (e) => {
|
|
|
|
+ if (!treeClusterLayer) return;
|
|
|
|
+
|
|
|
|
+ treeClusterLayer.layer.getFeatures(e.pixel).then((clickedFeatures) => {
|
|
|
|
+ if (!clickedFeatures.length) return;
|
|
|
|
+
|
|
|
|
+ const features = clickedFeatures[0].get("features");
|
|
|
|
+ if (features.length > 1) {
|
|
|
|
+ handleClusterClick(features);
|
|
|
|
+ } else {
|
|
|
|
+ handleSingleFeatureClick(features[0]);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
});
|
|
});
|
|
-}
|
|
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 处理集群点击
|
|
|
|
+const handleClusterClick = (features) => {
|
|
|
|
+ const extent = boundingExtent(features.map(r => r.getGeometry().getCoordinates()));
|
|
|
|
+ kmap.getView().fit(extent, { duration: 1000, padding: [250, 250, 250, 250] });
|
|
|
|
+
|
|
|
|
+ const currentZoom = kmap.getView().getZoom();
|
|
|
|
+ if (currentZoom > 17) {
|
|
|
|
+ kmap.getView().setZoom(17);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 处理单个要素点击
|
|
|
|
+const handleSingleFeatureClick = (feature) => {
|
|
|
|
+ if (isDrawing.value) {
|
|
|
|
+ feature.set("highlight", true);
|
|
|
|
+ refreshClusterStyle();
|
|
|
|
+ } else {
|
|
|
|
+ resetCurrentTree();
|
|
|
|
+ feature.set("currentTree", true);
|
|
|
|
+ currentTree.value = feature;
|
|
|
|
+
|
|
|
|
+ eventBus.emit("click:point", {
|
|
|
|
+ farmId: Number(sessionStorage.getItem("currentFarmId")),
|
|
|
|
+ sampleId: feature.get("sampleId"),
|
|
|
|
+ data: feature.getProperties()
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
|
|
-// 清除聚合图层,解除绑定
|
|
|
|
-function clearCluster() {
|
|
|
|
|
|
+// 清除集群图层
|
|
|
|
+const clearCluster = () => {
|
|
if (treeClusterLayer) {
|
|
if (treeClusterLayer) {
|
|
treeClusterLayer.layer.getSource().getSource().clear();
|
|
treeClusterLayer.layer.getSource().getSource().clear();
|
|
- treeClusterLayer.layer.getSource().clear();
|
|
|
|
|
|
+ kmap.removeLayer(treeClusterLayer.layer);
|
|
treeClusterLayer = null;
|
|
treeClusterLayer = null;
|
|
unByKey(listenKey);
|
|
unByKey(listenKey);
|
|
}
|
|
}
|
|
-}
|
|
|
|
|
|
+};
|
|
|
|
|
|
-function zoomToFeatures(features) {
|
|
|
|
- const extent = boundingExtent(features.map((r) => r.getGeometry().getCoordinates()));
|
|
|
|
|
|
+// 缩放到要素范围
|
|
|
|
+const zoomToFeatures = (features) => {
|
|
|
|
+ const extent = boundingExtent(features.map(r => r.getGeometry().getCoordinates()));
|
|
kmap.getView().fit(extent, { duration: 500, padding: [80, 250, 100, 250] });
|
|
kmap.getView().fit(extent, { duration: 500, padding: [80, 250, 100, 250] });
|
|
|
|
+};
|
|
|
|
|
|
- // const center = getCenter(extent);
|
|
|
|
- // kmap.setCenter2(center);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-function resetCurrentTree() {
|
|
|
|
- currentTree.value && currentTree.value.set("currentTree", false)
|
|
|
|
-}
|
|
|
|
|
|
+// 重置当前树
|
|
|
|
+const resetCurrentTree = () => {
|
|
|
|
+ if (currentTree.value) {
|
|
|
|
+ currentTree.value.set("currentTree", false);
|
|
|
|
+ refreshClusterStyle();
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
|
|
-defineExpose({ addCluster, enableBoxSelect, stopBoxSelect, initAreaMap, resetCurrentTree, saveSelect });
|
|
|
|
|
|
+// 初始化区域地图
|
|
|
|
+const initAreaMap = (arr) => {
|
|
|
|
+ regionLayer?.initData(arr);
|
|
|
|
+};
|
|
|
|
|
|
-// 分区
|
|
|
|
-let regionLayer = null;
|
|
|
|
-function initAreaMap(arr) {
|
|
|
|
- regionLayer.initData(arr);
|
|
|
|
-}
|
|
|
|
|
|
+defineExpose({
|
|
|
|
+ addCluster: updateClusterData,
|
|
|
|
+ enableBoxSelect,
|
|
|
|
+ stopBoxSelect,
|
|
|
|
+ initAreaMap,
|
|
|
|
+ resetCurrentTree,
|
|
|
|
+ saveSelect,
|
|
|
|
+ refreshClusterStyle // 暴露刷新方法
|
|
|
|
+});
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
@@ -391,4 +418,4 @@ function initAreaMap(arr) {
|
|
width: 100%;
|
|
width: 100%;
|
|
height: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
-</style>
|
|
|
|
|
|
+</style>
|