<template>
<div class="relation">
<div id="mapContainer" class="relation-container"></div>
<div class="relation-search">
<Select
ref="select"
style="width: 150px; margin-right: 20px"
v-model:value="timeVal"
:options="timeOption"
@focus="focus"
@change="handleChange"
></Select>
<InputSearch
id="numericInput"
style="width: 200px"
v-model:value="inputVal"
suffix="km"
placeholder="请输入"
@search="onSearch"
/>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted, Ref, ref } from 'vue';
import { Select, InputSearch } from 'ant-design-vue';
import mapboxgl from 'mapbox-gl';
import imgPoint from '../../../../assets/images/map/point12.png';
import * as turf from '@turf/turf';
import { bbox } from '@turf/turf';
let map: any;
const publick = `${import.meta.env.BASE_URL}`;
const selectValue = ref(1);
const timeVal = ref('一小时');
const inputVal: Ref<number> = ref(1);
const secrchVal: Ref<number> = ref(1);
let point = turf.point([104.0668, 30.5728]);
// 生成若干随机点
let randomPoints: AnyObject = [];
const timeOption = [
{
value: 1,
label: '一小时',
},
{
value: 2,
label: '二小时',
},
{
value: 3,
label: '三小时',
},
];
const init = () => {
mapboxgl.accessToken = null;
class Cjmapbox extends mapboxgl.Map {}
// eslint-disable-next-line @typescript-eslint/no-empty-function
Cjmapbox.prototype.__proto__._authenticate = function () {};
map = new mapboxgl.Map({
container: 'mapContainer',
style: {
version: 8,
name: 'BlankMap',
glyphs: `${publick}lib/glyphs/{fontstack}/{range}.pbf`,
sources: {},
layers: [
{
id: 'background',
type: 'background',
paint: {
'background-color': '#08294A',
} /* 背景颜色 */,
},
],
},
center: [104.0668, 30.5728], // Set the initial center of the map
zoom: 14,
});
map.on('load', () => {
map.addSource('DZDT_Vector_BZB', {
type: 'raster',
tiles: [
'http://t3.tianditu.com/DataServer?T=vec_w&tk=915de993ea6873664830bf5d8217723c&x={x}&y={y}&l={z}',
],
tileSize: 256,
});
map.addLayer({
id: 'DZDT_Vector_BZB',
type: 'raster',
source: 'DZDT_Vector_BZB',
paint: {},
});
map.loadImage(
imgPoint,
function (error: AnyObject, imgPoint: AnyObject) {
if (error) throw error;
map.addImage('imgPoint', imgPoint);
},
);
bufferEvt(point, 1);
randomPointsEvt(1);
});
};
onMounted(() => {
init();
});
// 缓冲
const bufferEvt = (point: any, distant: number) => {
let buffered = turf.buffer(point, distant, { units: 'kilometers' });
if (map.getLayer('circlePOI')) {
map.removeLayer('circlePOI');
map.removeSource('circlePOI');
}
map.addLayer({
id: 'circlePOI',
type: 'fill',
source: {
type: 'geojson',
data: buffered,
},
layout: {},
paint: {
'fill-color': '#5388e1',
'fill-opacity': 0.5,
},
});
let listArrBounds = bbox(buffered);
map.fitBounds(listArrBounds, { padding: 100 });
};
// 缓冲距离
const onSearch = (e: string) => {
let t = e.replace(/[^0-9.]/g, '');
if (t.length <= 0) return;
bufferEvt(point, Number(e));
if (Number(e) < secrchVal.value) randomPoints = [];
secrchVal.value = Number(e);
randomPointsEvt(Number(e));
};
// 随机点
const randomPointsEvt = (dist: number) => {
let pointsGeoJSON = {};
for (let i = 0; i < 10; i++) {
// 生成10个随机点
randomPoints.push(getRandomPointInCircle([104.0668, 30.5728], dist));
pointsGeoJSON = {
type: 'FeatureCollection',
features: randomPoints.map((coord: AnyObject) => ({
type: 'Feature',
geometry: {
type: 'Point',
coordinates: coord,
},
properties: {}, // 可以在此处添加任何需要的属性
})),
};
}
addPointEvt(pointsGeoJSON);
};
// 时间
const handleChange = (e: number) => {
if (e < selectValue.value) {
randomPoints = [];
}
selectValue.value = e;
randomPointsEvt(secrchVal.value);
};
// 加载点位
const addPointEvt = (geojson: AnyObject) => {
if (map.getLayer('pointLayer')) {
map.removeLayer('pointLayer');
map.removeSource('pointLayer');
}
// 添加点图层
map.addLayer({
id: 'pointLayer',
type: 'symbol',
source: {
type: 'geojson',
data: geojson,
},
layout: {
'icon-image': 'imgPoint',
'icon-size': 0.15,
},
});
};
// 随机生成点位
function getRandomPointInCircle(poi: any, radius: number) {
const [longitude, latitude] = poi;
// 随机生成距离和角度
const distance = Math.sqrt(Math.random()) * radius * 800; // 距离,确保在圈内
const angle = Math.random() * 2 * Math.PI; // 角度
// 根据距离和角度计算点的偏移
const offsetLongitude =
(distance * Math.cos(angle)) /
(111320 * Math.cos((latitude * Math.PI) / 180));
const offsetLatitude = (distance * Math.sin(angle)) / 110540;
return [longitude + offsetLongitude, latitude + offsetLatitude];
}
</script>
<style lang="scss" scoped>
.relation {
width: 100%;
height: 100%;
position: relative;
&-container {
width: 100%;
height: 100%;
}
&-search {
position: absolute;
right: 50px;
top: 15px;
display: flex;
align-items: center;
}
}
:deep(.ant-input-search-button) {
border: 1px solid #d9d9d9 !important;
}
</style>