123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- <template>
- <div class="search-layout">
- <el-input v-model="keyword" placeholder="输入名称搜索" style="width: 350px" clearable>
- <template #append>
- <el-button :icon="Search" />
- </template>
- </el-input>
- <div class="rrr">
- <div class="search-result" v-show="keyword && showSearch" ref="resultEl"></div>
- <div class="search-sh" v-show="keyword">
- <el-button style="width: 100%" @click="showSearch = !showSearch">
- {{ showSearch ? "收起" : "展开" }}搜索结果
- </el-button>
- </div>
- </div>
- </div>
- <div class="def-select-map-layout">
- <div class="def-select-map" ref="mapEl"></div>
- </div>
- <div class="def-map-info" v-if="info">
- <p><span>纬度</span>{{ info.lat }}</p>
- <p><span>经度</span>{{ info.lng }}</p>
- <p><span>缩放级别</span>{{ info.zoom }}</p>
- </div>
- </template>
- <script setup lang="ts">
- import AMapLoader from "@amap/amap-jsapi-loader";
- import { Search } from "@element-plus/icons-vue";
- import { ref, watchEffect, onMounted } from "vue";
- import { QuiskExpose } from "@/helper/mount";
- import { debounce } from "@/util";
- import html2canvas from "html2canvas"
- import L from 'leaflet'
- import 'leaflet/dist/leaflet.css'
- export type MapImage = { blob: Blob | null; search: MapInfo | null };
- type MapInfo = { lat: number; lng: number; zoom: number; text: string };
- let map = null;
- const keyword = ref("");
- const showSearch = ref(true);
- const info = ref<MapInfo>();
- const searchInfo = ref<MapInfo>();
- watchEffect(() => {
- if (keyword.value) {
- showSearch.value = true;
- }
- });
- const mapEl = ref<HTMLDivElement>();
- const resultEl = ref<HTMLDivElement>();
- const searchAMap = ref<any>();
- watchEffect(async (onCleanup) => {
- if (!mapEl.value || !resultEl.value) {
- return;
- }
- const AMap = await AMapLoader.load({
- plugins: ["AMap.PlaceSearch", "AMap.Event"],
- key: "e661b00bdf2c44cccf71ef6070ef41b8",
- version: "2.0",
- });
- map = new AMap.Map(mapEl.value, {
- WebGLParams: {
- preserveDrawingBuffer: true,
- },
- resizeEnable: true,
- });
- const placeSearch = new AMap.PlaceSearch({
- pageSize: 5,
- showCover: false,
- pageIndex: 1,
- map: map,
- panel: resultEl.value,
- autoFitView: true,
- });
- const setSearch = (data) => {
- console.log('setSearch', data);
- let city = data.cityname == data.adname? data.cityname : (data.cityname + data.adname);
- searchInfo.value = {
- text: data.pname + city + data.address,
- lat: data.location.lat,
- lng: data.location.lng,
- zoom: 0,
- };
- };
- placeSearch.on("listElementClick", (e) => {
- setSearch(e.data);
- showSearch.value = false;
- });
- let clickMarker;
- map.on("click", function (e) {
- // 获取点击位置的经纬度坐标
- var latitude = e.lnglat.lat;
- var longitude = e.lnglat.lng;
- searchInfo.value = {
- text: "",
- lat: latitude,
- lng: longitude,
- zoom: 0,
- };
- clickMarker && map.remove(clickMarker);
- clickMarker = null;
- // 在地图上添加标记
- clickMarker = new AMap.Marker({
- position: [longitude, latitude],
- title: "点击位置",
- });
- map.add(clickMarker);
- });
- placeSearch.on("complete", function (result) {
- setTimeout(() => {
- const markers = map.getAllOverlays("marker");
- for (const marker of markers) {
- marker.on("click", () => {
- clickMarker && map.remove(clickMarker);
- clickMarker = null;
- setSearch(marker._data);
- });
- }
- }, 500);
- });
- const getMapInfo = (): MapInfo => {
- var zoom = map.getZoom(); //获取当前地图级别
- var center = map.getCenter();
- return {
- text: "",
- zoom,
- lat: center.lat,
- lng: center.lng,
- };
- };
- //绑定地图移动与缩放事件
- map.on("moveend", () => {
- info.value = getMapInfo();
- });
- map.on("zoomend", () => {
- info.value = getMapInfo();
- });
- searchAMap.value = placeSearch;
- onCleanup(() => {
- searchAMap.value = null;
- map.destroy();
- });
- });
- var dataURLtoBlob = function (dataurl){
- var arr = dataurl.split(','),
- mime = arr[0].match(/:(.*?);/)[1],
- bstr = atob(arr[1]),
- n = bstr.length,
- u8arr = new Uint8Array(n);
- while (n--) {
- u8arr[n] = bstr.charCodeAt(n);
- }
- return new Blob([u8arr], { type: mime })
- }
- const search = debounce((keyword: string) => {
- searchAMap.value.search(keyword);
- }, 1000);
- const getblc = () => {
- console.log('map', map);
- if (!map) {
- ElMessage.error('地图未初始化')
- return
- }
- try {
- // 获取当前地图的可视区域边界
- const bounds = map.getBounds()
- const southwest = bounds.getSouthWest() // 西南角
- const northeast = bounds.getNorthEast() // 东北角
- const northwest = new (window as any).AMap.LngLat(southwest.lng, northeast.lat) // 西北角
- const southeast = new (window as any).AMap.LngLat(northeast.lng, southwest.lat) // 东南角
-
- // 使用高德地图的几何工具计算距离(单位:米)
- const AMap = (window as any).AMap
-
- // 计算宽度(东西方向距离)
- const width = AMap.GeometryUtil.distance(southwest, southeast)
-
- // 计算高度(南北方向距离)
- const height = AMap.GeometryUtil.distance(southwest, northwest)
-
- // 计算面积(平方米)
- const area = width * height
-
- // 获取当前缩放级别
- const zoom = map.getZoom()
-
- // 获取地图中心点
- const center = map.getCenter()
-
- const viewportInfo = {
- width: width, // 宽度(米)
- height: height, // 高度(米)
- area: Math.round(area), // 面积(平方米)
- zoom: zoom, // 缩放级别
- center: {
- lat: center.lat,
- lng: center.lng
- },
- bounds: {
- southwest: { lat: southwest.lat, lng: southwest.lng },
- northeast: { lat: northeast.lat, lng: northeast.lng }
- }
- }
-
- console.log('当前可视区域信息:', viewportInfo)
-
- // ElMessage.success(`
- // 可视区域信息:
- // 宽度:${viewportInfo.width.toLocaleString()} 米
- // 高度:${viewportInfo.height.toLocaleString()} 米
- // 面积:${viewportInfo.area.toLocaleString()} 平方米
- // 缩放级别:${viewportInfo.zoom.toFixed(2)}
- // `)
- return {
- width: viewportInfo.width,
- height: viewportInfo.height,
- }
- } catch (error) {
- console.error('计算可视区域失败:', error)
- ElMessage.error('计算可视区域失败')
- }
- }
- watchEffect(() => {
- searchAMap.value && search(keyword.value);
- });
- defineExpose<QuiskExpose>({
- submit() {
- return new Promise<MapImage>((resolve) => {
- const info = getblc();
- let firstElement = document.querySelector('.leaflet-control-container');
- firstElement.style.visibility = 'hidden';
- console.log('searchInfo',info, searchInfo.value, mapEl.value);
- if (mapEl.value) {
- // const canvas = mapEl.value.querySelector("canvas") as HTMLCanvasElement;
- // console.log(canvas, 'canvas');
- // canvas && canvas.toBlob((blob) => resolve({ blob, search: searchInfo.value! }))// || resolve({ search: searchInfo.value! });
- // if(!canvas){
- //div内容生成图片
- html2canvas(mapEl.value, {
- useCORS: true, // 添加这个选项以解决跨域问题
- }).then((canvas) => {
- let imgUrl = canvas.toDataURL("image/png");
- let blob = dataURLtoBlob(imgUrl)
- resolve({ blob, search: searchInfo.value!, ...info })// || resolve({ search: searchInfo.value!, ...info });
- });
- // }
- } else {
- resolve({ blob: null, search: null });
- }
- });
- },
- });
- </script>
- <style lang="scss" scoped>
- .search-layout {
- display: inline-block;
- position: relative;
- margin-bottom: 15px;
- z-index: 2;
- }
- .rrr {
- position: absolute;
- left: 0;
- right: 0;
- z-index: 1;
- }
- .search-sh,
- .search-result {
- overflow: hidden;
- &.show {
- max-height: 450px;
- overflow-y: auto;
- }
- }
- .def-map-info {
- margin-top: 10px;
- p {
- font-size: 14px;
- color: rgba(0, 0, 0, 0.85);
- display: inline;
- &:not(:last-child)::after {
- content: ",";
- margin-right: 6px;
- }
- }
- span::after {
- content: ":";
- }
- }
- .def-select-map-layout {
- --scale: 1.5;
- width: 100%;
- padding-top: calc((390 / 540) * 100%);
- position: relative;
- z-index: 1;
- }
- .def-select-map {
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- }
- </style>
|