为什么有地图切换的需求?
总之,底图切换在GIS中是为了提供更好的地理信息展示和分析的灵活性和可定制性。它允许用户根据需要选择适当的底图,并根据上下文和需求更好地理解和分析地理数据。
“影像”底图
“电子地图”底图
/**
* @描述: 地图切换组件-widget-BasemapGalleryWidget
* @作者: 花姐夫JUN
* @创建时间: 2022-12-06 16:02:54
*/
<template>
<a-popover v-bind="$attrs" v-model="isExpand" trigger="click" placement="leftBottom">
<div slot="content" style="min-height: 155px;min-width: 160px;" v-if="activeView">
<basemap-gallery-card :key="activeView.type" :active-view="activeView" :all-basemap-list="allBasemapList"></basemap-gallery-card>
</div>
<div v-show="visible"
class="esri-component esri-home esri-widget--button esri-widget"
role="button"
tabindex="0"
:aria-label="title"
:title="title"
@mouseover="isHover=true"
@mouseleave="isHover=false"
@focus="active=true"
@blur="active=false"
style="width: 80px;height: 80px;position: relative;right: 28px;"
@click="handleClick()">
<div v-if="loading" aria-hidden="true" class="esri-icon">
<div :class="{'esri-icon-loading-indicator esri-rotating':loading}"></div>
</div>
<div v-else
aria-hidden="true"
class="esri-icon">
<img :src="thumbnailUrl|imgBasePath" alt="">
</div>
</div>
</a-popover>
</template>
<script lang="ts">
import { Component } from 'vue-property-decorator';
import MapView from '@c_arcgis/core/views/MapView';
import SceneView from '@c_arcgis/core/views/SceneView';
import { WidgetMixins } from '@/views/map/components/tools/widgetMixins';
import BasemapGalleryCard from '@/views/map/components/tools/BasemapGalleryWidget/BasemapGalleryCard.vue';
@Component({
name: 'BasemapGalleryWidget',
components: { BasemapGalleryCard },
})
export default class BasemapGalleryWidget extends WidgetMixins {
title = '底图';
isExpand = false;
thumbnailUrl = '';
activeView: MapView | SceneView = null;
allBasemapList: Record<string, any> = {};
// 初始化
init(activeView, allBasemapList = undefined) {
this.activeView = null;
this.activeView = activeView;
this.allBasemapList = allBasemapList;
debugger;
this.visible = !!(this.activeView && Object.keys(this.allBasemapList)?.length);
const {
thumbnailUrl,
title,
} = this.activeView.map.basemap;
this.title = title;
this.thumbnailUrl = thumbnailUrl;
// 监听底图切换
this.activeView.map.watch('basemap', ({
thumbnailUrl: thumbnailUrl_active,
title: title_active,
}) => {
// 是否有effect的图层,有的话清空,否则底图显示会异常
const regionEffect_groupLayer: any = this.activeView.map.findLayerById('regionEffect_groupLayer');
if (regionEffect_groupLayer?.opacity === 0) {
// 为了避免异常直接移除
this.activeView.map.remove(regionEffect_groupLayer);
// 清空
this.activeView.map.allLayers.forEach((layer: any) => {
debugger;
if (layer.effect === 'blur(15px) brightness(1.2) grayscale(0.6)') {
layer.effect = null;
}
});
}
this.title = title_active;
this.thumbnailUrl = thumbnailUrl_active;
});
return this.$el;
}
handleClick() {
if (this.activeView) {
this.isExpand = !this.isExpand;
}
}
}
</script>
<style scoped lang="less">
@widgetTextColor: '#8c8c8c';
.widgetLabel {
color: @widgetTextColor !important;
font-size: 12px;
width: 100%;
position: relative;
bottom: 5px;
}
/deep/ .ant-popover-inner-content {
padding: 5px;
}
</style>
以上BasemapGalleryWidget.js代码是为了实现地图切换组件作为地图的一个widget,从而可以使用view.ui.add(widget, position)的方式添加。并且也使用antd design的popover组件,来实现可选底图的弹出展示。
/**
* @描述: 底图切换备选地图展示-BasemapGalleryCard
* @作者: 花姐夫JUN
* @创建时间: 2022-12-06 16:41:57
*/
<template>
<div style="width: 200px;">
<a-list :grid="{ gutter: 0, column: 1 }" :data-source="dataSource" :loading="loading">
<a-list-item slot="renderItem" slot-scope="item" @click="onClick(item)">
<div class="flex hover:bg-gray-200 cursor-default border-l-4 border-transparent" :class="{'bg-gray-200 border-blue-500':activeBasemap.id===item.id}" :title="item.title">
<img :src="item.thumbnailUrl" class="p-1 border-inherit border-1">
<div class="text-lg pl-2" style="line-height: 84px;">{{ item.title }}</div>
</div>
</a-list-item>
</a-list>
</div>
</template>
<script lang="ts">
import {
Component, InjectReactive, Prop, Vue, Watch,
} from 'vue-property-decorator';
import BasemapGallery from '@c_arcgis/core/widgets/BasemapGallery';
import MapView from '@c_arcgis/core/views/MapView';
import SceneView from '@c_arcgis/core/views/SceneView';
@Component({ name: 'BasemapGalleryCard' })
export default class BasemapGalleryCard extends Vue {
@Prop({
type: Object,
default: () => ({}),
}) activeView: MapView | SceneView | undefined;
@Prop({
type: Object,
default: () => ({}),
}) allBasemapList: Record<string, any> | undefined;
dataSource: Record<string, any>[] = [];
widget;
activeBasemap: Record<string, any> = {};
loading = false;
handle = null;
init() {
if (this.activeView && Object.keys(this.allBasemapList)?.length) {
const { spatialReference } = this.activeView;
this.dataSource = Object.values(this.allBasemapList)
.filter((layer) => !!layer)
.map((layer) => {
layer.spatialReference = spatialReference;
return layer;
});
this.activeBasemap = this.activeView.map.basemap;
// 监听底图切换
this.handle = this.activeView.map.watch('basemap', (item) => {
this.loading = false;
this.activeBasemap = item;
});
}
}
mounted() {
this.init();
}
onClick(item) {
if (this.activeBasemap.id !== item.id) {
this.loading = true;
this.activeView.map.basemap = item;
}
}
destroyed() {
this.handle.remove();
}
@Watch('activeView', { immediate: false })
handleActiveViewChange(newVal, oldVal) {
if (!_.isEqual(newVal, oldVal)) {
this.$nextTick(() => {
this.init();
});
}
}
@Watch('allBasemapList', { immediate: false })
handleAllBasemapListChange(newVal, oldVal) {
if (!_.isEqual(newVal, oldVal)) {
this.$nextTick(() => {
this.init();
});
}
}
}
</script>
<style scoped lang="less">
</style>
BasemapGalleryCard.js代码是将传入的allBasemapList(备选底图)列表展示,并实现点击切换底图底图。
allBasemapList(备选基础底图数据)的生成是使用这个自定义地图切换widget的关键,以下为传入自定义地图切换widget的基础底图数据生成代码块
// 生成基础底图
Object.entries(basemapLayersDic)
.forEach(([basemapName, basemapInfo]: any) => {
let thumbnailUrl_temp = [];
const baseLayers = basemapInfo.map(({
layer,
thumbnailUrl,
}) => {
thumbnailUrl_temp = [...thumbnailUrl_temp, thumbnailUrl];
return layer;
});
allBasemapList[basemapName] = new Basemap({
baseLayers: baseLayers || [],
title: basemapName,
id: basemapName,
thumbnailUrl: thumbnailUrl_temp[0], // 设置地图截图
});
});
}
thumbnailUrl不是创建Basemap实例对象必须的参数,而是为了在自定义widget中实现通过thumbnailUrl展示不同底图的缩略图,更加直观的展示各种类型的底图。
参考文章:
widget添加
Basemap实例化