<template>
|
<div class="relative bg-white">
|
<div ref="containerRef" class="h-full"></div>
|
<div ref="infoWindowRef" v-show="infoWindowIsShow">
|
<div
|
class="bg-white rounded-md text-nowrap flex flex-col w-fit border border-solid border-blue-600 relative z-[1]"
|
style="padding: 12px"
|
>
|
<span
|
@click="closeInfoWindow"
|
class="guanbi absolute ywifont ywicon-guanbi right-[4px] top-[-2px] font-bold text-[#c3c3c3] cursor-pointer"
|
></span>
|
|
<div class="space-x-4 flex w-full">
|
<div class="flex flex-col w-1/2 key-list">
|
<span
|
v-for="(col, index) in colsArray"
|
:key="index"
|
class="flex-items-center justify-start text-gray-600"
|
style="height: 20px"
|
>{{ col.title ?? '' }}</span
|
>
|
</div>
|
|
<div class="flex flex-col w-1/2 value-list" v-if="infoWindowMapRow">
|
<span
|
v-for="(col, index) in colsArray"
|
:key="index"
|
class="flex-items-center justify-end text-black"
|
style="height: 20px"
|
>{{ infoWindowMapRow[index] ?? '' }}</span
|
>
|
</div>
|
</div>
|
</div>
|
</div>
|
<LayerControl v-if="olMap" :olMap="olMap" class="absolute top-3 left-3 z-10" />
|
|
<!-- <PropertyPanel class="absolute top-14 left-10 z-14"></PropertyPanel> -->
|
<PanelTool
|
ref="panelToolRef"
|
:propertyMap="propertyMap"
|
:propertyConfigMap="propertyConfigMap"
|
class="absolute top-24 left-2 z-14"
|
></PanelTool>
|
<el-button class="absolute top-3 right-4" @click="changeTheme" type="primary">切换主题</el-button>
|
</div>
|
</template>
|
|
<script setup lang="ts" name="BasicMap">
|
import type { Overlay } from 'ol';
|
import 'ol/ol.css';
|
import PanelTool from './panelTool/index.vue';
|
import { computed, onMounted, ref, shallowRef } from 'vue';
|
import equipSelectPic from './img/equip-select.svg';
|
import equipPic from './img/equip.svg';
|
import LayerControl from './LayerControl.vue';
|
import { GaoDeSourceType, OLMap } from '/@/model/map/OLMap';
|
import { getMapLayersByPost, getMapVpropsByPost, getMapVpropsConfigByPost, switchMapTheme } from '/@/api/map';
|
import PropertyPanel from './PropertyPanel.vue';
|
import { useCompRef } from '/@/utils/types';
|
import { reverse } from 'lodash-es';
|
import { MAIN_URL } from '/@/constants';
|
import VectorTileLayer from 'ol/layer/VectorTile';
|
import Style from 'ol/style/Style';
|
import Circle from 'ol/style/Circle';
|
import Fill from 'ol/style/Fill';
|
|
const panelToolRef = useCompRef(PanelTool);
|
const props = withDefaults(
|
defineProps<{
|
data: any;
|
config?: {
|
sourceType: GaoDeSourceType;
|
markerIsVisible: boolean;
|
};
|
}>(),
|
{
|
config: () => ({
|
sourceType: GaoDeSourceType.Vector,
|
markerIsVisible: true,
|
}),
|
}
|
);
|
|
const changeTheme = async () => {
|
const res = await switchMapTheme();
|
const styles = (res?.styles ?? []).map((item) =>
|
item.PSIZE
|
? new Style({
|
image: new Circle({
|
radius: item.PSIZE,
|
fill: new Fill({ color: `#${item.PCOLOR}` }),
|
}),
|
})
|
: null
|
);
|
const junctionsStyle = res?.['O_WDM_JUNCTIONS'] ?? {};
|
junctionLayer?.setStyle((feature) => {
|
const oname = feature.get('oname');
|
if (!oname) return null;
|
const styleIndex = junctionsStyle[oname]?.style_id;
|
if (styleIndex == null) return null;
|
const style = styles[styleIndex];
|
return style;
|
});
|
};
|
const colsArray = computed(() => {
|
return props.data.cols ?? [];
|
});
|
const emit = defineEmits(['markerClick', 'closeInfoWindow']);
|
|
const containerRef = ref<HTMLDivElement>(null);
|
const infoWindowRef = ref<HTMLDivElement>(null);
|
const infoWindowIsShow = ref(false);
|
const infoWindowMapRow = ref(null);
|
const olMap = shallowRef<OLMap>();
|
let infoWindowOverlay: Overlay;
|
let lastOverlay: Overlay;
|
const setMarkerIcon = (overlay: Overlay, icon: string) => {
|
if (!overlay) return;
|
const ele = overlay.getElement() as HTMLImageElement;
|
if (!ele) return;
|
ele.src = icon;
|
};
|
const showInfoWindow = (overlay: Overlay) => {
|
const position = overlay.getPosition();
|
const row = overlay.get('extData')?.value;
|
if (!row) return;
|
lastOverlay && setMarkerIcon(lastOverlay, equipPic);
|
infoWindowIsShow.value = true;
|
infoWindowOverlay.setPosition(position);
|
infoWindowMapRow.value = row;
|
setMarkerIcon(overlay, equipSelectPic);
|
lastOverlay = overlay;
|
emit('markerClick', row);
|
};
|
|
const closeInfoWindow = () => {
|
infoWindowIsShow.value = false;
|
infoWindowMapRow.value = null;
|
setMarkerIcon(lastOverlay, equipPic);
|
emit('closeInfoWindow');
|
};
|
const addMarkerLayer = () => {
|
const map = props.data.map;
|
if (map.pos_x == null && map.pos_y == null) return;
|
const dataList = (props.data?.values ?? []).map((item) => {
|
const x = item[map.pos_x];
|
const y = item[map.pos_y];
|
|
return {
|
position: [x, y],
|
// textColor: item.color,
|
extData: {
|
value: item,
|
recordSetTable: props.data,
|
},
|
};
|
});
|
olMap.value.addMarkerLayer(dataList, {
|
markerOpt: {
|
icon: {
|
url: equipPic,
|
size: 30,
|
selectUrl: equipSelectPic,
|
},
|
click(e, label, extData, position) {
|
showInfoWindow(label);
|
},
|
},
|
layerOpt: {
|
// allowCollision:false
|
},
|
});
|
};
|
|
const handleVectorTileClick = (event) => {
|
const features = olMap.value.map.getFeaturesAtPixel(event.pixel);
|
const feature = features[0];
|
feature && panelToolRef.value.featureClick(feature);
|
};
|
const propertyMap = ref({});
|
const propertyConfigMap = ref({});
|
const getPropertyList = async () => {
|
const res = await getMapVpropsByPost();
|
const otypes = res?.otypes ?? {};
|
propertyMap.value = otypes;
|
|
const res1 = await getMapVpropsConfigByPost();
|
propertyConfigMap.value = res1?.values ?? {};
|
};
|
|
let junctionLayer: VectorTileLayer = null;
|
const initVectorTileLayer = async () => {
|
const res = await getMapLayersByPost();
|
const layers = reverse(res?.layers ?? []);
|
if (layers.length === 0) return;
|
for (const item of layers) {
|
if (item.id === 'junction') {
|
const styleMap = {};
|
|
const layer = olMap.value.addCustomLayer(
|
`${MAIN_URL}map/get_vector_tile?x={x}&y={y}&z={z}&layer_id=${item.id}`,
|
function (feature, resolution) {
|
if (feature.getGeometry().getType() === 'Point') {
|
const size = feature.get('psize');
|
const color = feature.get('pcolor');
|
const otype = feature.get('otype');
|
if (!size) return null;
|
const key = `${size}_${color}`;
|
if (!styleMap[key]) {
|
styleMap[key] = new Style({
|
image: new Circle({
|
radius: size,
|
fill: new Fill({ color: `#${color}` }),
|
// stroke: new Stroke({ color: '#ff0000', width: 1 }),
|
}),
|
});
|
}
|
|
return styleMap[key];
|
} else {
|
return null;
|
}
|
}
|
);
|
|
junctionLayer = layer;
|
} else {
|
const layer = olMap.value.addCustomLayer(`${MAIN_URL}map/get_vector_tile?x={x}&y={y}&z={z}&layer_id=${item.id}`);
|
}
|
}
|
getPropertyList();
|
olMap.value.map.on('click', handleVectorTileClick);
|
};
|
const initMap = () => {
|
olMap.value = new OLMap({
|
container: containerRef.value,
|
sourceType: props.config?.sourceType,
|
markerIsVisible: props.config?.markerIsVisible,
|
});
|
|
addMarkerLayer();
|
infoWindowOverlay = olMap.value.createEleOverlay(infoWindowRef.value);
|
olMap.value.map.addOverlay(infoWindowOverlay);
|
initVectorTileLayer();
|
};
|
|
defineExpose({
|
olMap: olMap,
|
});
|
|
onMounted(() => {
|
initMap();
|
// window.olMap = olMap.value;
|
// window.map = olMap.value.map;
|
});
|
</script>
|
<style scoped lang="scss"></style>
|