cesiusm实现 多图例展示+点聚合(base64图标)

  • 需求背景
  • 解决思路
  • 解决效果
  • index.vue

需求背景

1.需要展示多个站点图例的图表及闪烁效果
2.需要考虑层级高时,多图例的点聚合效果,且点聚合显示需要采用设计的圆形图标

解决思路

闪烁效果:采用 css3的 animation动画属性
圆形图标:采用canvas的toDataURL方法,生产base64图片

解决效果

index.vue

/**
* @author: liuk
* @date: 2024-11-13 16:40:51
* @describe:图例展示+点聚合(base64图标)
*/
<template><div class="legendShow-wrap"><div class="legendBox"><div class="lengendBtn" @click='isFlat = !isFlat' :class="{select: isFlat === true}"><span>图例</span><el-icon v-show="isFlat"><ArrowDown/></el-icon><el-icon v-show="!isFlat"><ArrowUp/></el-icon></div><ul v-if="isFlat"><li v-for="item of legendImgList" :key='item.id' @click="updateProject(item)":class="item.typeArr[0] === curId ? 'select':''"><div class="imgBox"><img :src="item.img" alt=""></div><p>{{ item.typeArr[0] }}</p></li></ul></div><ul class="animation-list" ref="animationListRef"></ul><!-- 默认加载天地图--><Tdt_img_d/></div>
</template><script lang="ts" setup>
// Component
import Tdt_img_d from "@/views/cesium/component/controlPanel/layerManagement/basicMap/tdt_img_d.vue"
import {onMounted, onUnmounted, reactive, toRefs, ref} from "vue";
import jsonData from "./data.json"
import {usemapStore} from "@/store/modules/cesiumMap";
// Refs
const animationListRef = ref(null)const mapStore = usemapStore()
const model = reactive({isFlat: false,// 是否展开curId: '',//当前选中图例
})
const {isFlat, curId} = toRefs(model)onMounted(() => {mapResetCamera()viewer.dataSources.add(lengendShowDatasource);viewer.scene.postRender.addEventListener(showPopupBox);lengendShowDatasource.clustering.clusterEvent.addEventListener(clusteredFn)addEntity()
})onUnmounted(() => {lengendShowDatasource.clustering.clusterEvent.removeEventListener(clusteredFn)lengendShowDatasource?.entities?.removeAll()viewer.dataSources.remove(lengendShowDatasource);viewer.scene.postRender.removeEventListener(showPopupBox);
})const updateProject = (row) => {if (model.curId === row.typeArr[0]) {lengendShowDatasource.entities.values.forEach(entity => entity.show = true)model.curId = ""return}lengendShowDatasource.entities.values.forEach(entity => {entity.show = row.typeArr.includes(entity.data.state)})model.curId = row.typeArr[0]
}// 地图逻辑
const viewer = mapStore.getCesiumViewer()
const lengendShowDatasource = new Cesium.CustomDataSource("lengendShow");
lengendShowDatasource.clustering.pixelRange = 2; //多少像素矩形范围内聚合
lengendShowDatasource.clustering.minimumClusterSize = 3;
lengendShowDatasource.clustering.enabled = true;const addEntity = () => {jsonData.forEach(item => {const {longitude, latitude, state, level} = itemconst legendData = legendImgList.find(x => x.typeArr.includes(state))lengendShowDatasource.entities.add({customType: "lengendShow",position: Cesium.Cartesian3.fromDegrees(longitude, latitude),data: item,billboard: {image: legendData.img,scale: 0.5,horizontalOrigin: Cesium.HorizontalOrigin.CENTER,verticalOrigin: Cesium.VerticalOrigin.BOTTOM,scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 8.0e6, 0.2),disableDepthTestDistance: Number.POSITIVE_INFINITY, //解决遮挡问题heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5 * 1e5),},})const li = document.createElement('li') // 后面加载dom,不在组件的scope里面li.longitude = longitudeli.latitude = latitudeli.typeArr = legendData.typeArrli.className = 'animation-point'li.style.color = getColor(level)animationListRef.value.appendChild(li)})
}const showPopupBox = () => {const cameraPosition = viewer.camera.positionWC; // 相机世界坐标;[...animationListRef.value.children].forEach(dom => {const {longitude, latitude, typeArr} = domconst curPosition = Cesium.Cartesian3.fromDegrees(longitude, latitude, 0);const {x, y} = viewer.scene.cartesianToCanvasCoordinates(curPosition)dom.style.left = x + "px"dom.style.top = y + "px"const distance = Cesium.Cartesian3.distance(cameraPosition, curPosition);if ((model.curId && !typeArr.includes(model.curId)) || distance < 0 || distance > 1e6) {dom.style.display = "none"} else {dom.style.display = "block"}})
}const clusteredFn = (clusteredEntities, cluster) => {cluster.label.show = false;cluster.billboard.show = true;cluster.billboard.scale = 0.5; // 解决数字文本锯齿cluster.billboard.image = getCircleImage(clusteredEntities.length);cluster.billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY //解决遮挡问题
}import png1 from "@/assets/images/legendShow/lx.png"
import png2 from "@/assets/images/legendShow/sg.png"
import png3 from "@/assets/images/legendShow/fh.png"
import png4 from "@/assets/images/legendShow/zj.png"
import png5 from "@/assets/images/legendShow/cy.png"
import png6 from "@/assets/images/legendShow/zy.png"
import png7 from "@/assets/images/legendShow/rk.png"
import png8 from "@/assets/images/legendShow/gh.png"const legendImgList = [// 图例数据{img: png1, typeArr: ["立项"]},{img: png2, typeArr: ["施工"]},{img: png3, typeArr: ["复核"]},{img: png4, typeArr: ["自验", "未自验", "已自验", "初验驳回", "自验"],},{img: png5, typeArr: ["初验", "待初验", "初验通过", "终验驳回", "市级同意终验驳回"]},{img: png6, typeArr: ["终验", "申请终验中", "申请发起核验", "申请开展验收", "申请终验驳回", "市级同意核验", "市级同意终验", "核验中", "核验完成", "终验通过",],},{img: png7, typeArr: ["入库", "申请入库中", "县级核定完成"]},{img: png8, typeArr: ["管护", "市级同意入库", "管护"]},
]const getColor = (level) => {switch (level) {case 1:return "#eaff56";case 2:return "#ff461f";case 3:return "#f20c00";}
}
// 生产圆形图标 base64格式
const getCircleImage = (count, option = {}) => {let {clr, clr2, font, fontColor} = optionconst options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};const circleImageRadius = 28;const circleImageRadius2 = 28 - 5if (!options.color) {if (count < 10) {clr = "rgba(181, 226, 140, 0.6)";clr2 = "rgba(110, 204, 57, 0.5)";} else if (count < 100) {clr = "rgba(241, 211, 87, 0.6)";clr2 = "rgba(240, 194, 12, 0.5)";} else {clr = "rgba(253, 156, 115, 0.6)";clr2 = "rgba(241, 128, 23, 0.5)";}}const thisSize = circleImageRadius * 2;const circleCanvas = document.createElement("canvas");circleCanvas.width = thisSize;circleCanvas.height = thisSize;const circleCtx = circleCanvas.getContext("2d");circleCtx.fillStyle = "#ffffff00";circleCtx.globalAlpha = 0.0;circleCtx.fillRect(0, 0, thisSize, thisSize);//圆形底色 (外圈)if (clr) {circleCtx.globalAlpha = 1.0;circleCtx.beginPath();circleCtx.arc(circleImageRadius, circleImageRadius, circleImageRadius, 0, Math.PI * 2, true);circleCtx.closePath();circleCtx.fillStyle = clr;circleCtx.fill();}//圆形底色(内圈)if (clr2) {circleCtx.globalAlpha = 1.0;circleCtx.beginPath();circleCtx.arc(circleImageRadius, circleImageRadius, circleImageRadius2, 0, Math.PI * 2, true);circleCtx.closePath();circleCtx.fillStyle = clr2;circleCtx.fill();}//数字文字circleCtx.font = font || circleImageRadius2 * 0.9 + "px bold normal";circleCtx.fillStyle = fontColor || "#ffffff";circleCtx.textAlign = "center";circleCtx.textBaseline = "middle";circleCtx.fillText(count, circleImageRadius, circleImageRadius);return circleCanvas.toDataURL();
};const mapResetCamera = () => {viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(106.487115, 21.464166, 290064.99),orientation: {heading: Cesium.Math.toRadians(360.0),pitch: Cesium.Math.toRadians(-48.9),roll: 0.0}});
}
</script><style lang="scss" scoped>
.legendShow-wrap {.legendBox {position: fixed;left: 70px;bottom: 35px;width: 115px;border-radius: 4px;background: rgba(29, 40, 57, 0.6);backdrop-filter: blur(4px);pointer-events: auto;.lengendBtn {width: calc(100% - 10px);height: 35px;margin: 5px auto 5px;line-height: 35px;text-align: center;border: 1px solid #7588aab0;border-radius: 4px;color: rgba(255, 255, 255, 0.8);background: rgba(23, 40, 53, 0.4);backdrop-filter: blur(4px);box-shadow: rgb(7 98 255 / 30%) 0px 0px 2px 1px;cursor: pointer;&:hover {border-color: #4086ffb0;color: rgb(255, 255, 255);text-shadow: rgb(7 98 255 / 50%) 0px 0px 8px;}&.select {border: 1px solid #4086ffb0;color: rgb(255, 255, 255);background: rgba(25, 56, 111, 0.6);text-shadow: rgb(7 98 255 / 50%) 0px 0px 8px;}i {margin-left: 5px;}}ul {display: flex;flex-wrap: wrap;align-items: center;justify-content: center;width: 100%;height: 100%;color: rgba(255, 255, 255, 0.856);transition: all 3s linear 1s; //过渡为什么没用li {display: flex;justify-content: center;width: 100%;margin: 3px 10px;opacity: 0.8;cursor: pointer;&:hover {opacity: 1;}&.select {opacity: 1;color: #4086ffb0;font-weight: 600;}.imgBox {width: 20px;margin-right: 15px;img {width: 100%;height: 100%;}}}}}
}
</style>
<style lang="scss">
.animation-point {position: fixed;width: 10px;height: 10px;border-radius: 50%;border: 1px solid hsla(0, 0%, 100%, .5);cursor: pointer;color: #0ff;background: currentColor;transform: translate(-50%, 50%);box-shadow: 0 0 2em currentColor, 0 0 .5em currentColor;&::after, &::before {content: "";position: absolute;width: 0;height: 0;left: 50%;top: 50%;border: 1px solid;border-radius: 50%;transform: translate(-50%, -50%);animation: mapAni 1s ease infinite}
}@keyframes mapAni {0% {width: 0;height: 0;opacity: 1;filter: alpha(opacity=1)}25% {width: 12px;height: 12px;opacity: .7;filter: alpha(opacity=70)}50% {width: 20px;height: 20px;opacity: .5;filter: alpha(opacity=50)}75% {width: 30px;height: 30px;opacity: .2;filter: alpha(opacity=20)}to {width: 40px;height: 40px;opacity: 0;filter: alpha(opacity=0)}
}</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/14051.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

【银河麒麟】时间同步工具chrony与ntp对比

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn Chrony介绍 Chrony 是一个用于时间同步的软件。…

fork函数详解

前言 之前我们提到&#xff0c;创建子进程的时候&#xff0c;需要使用fork()函数&#xff0c;其中分别有id 0和id >0的if函数&#xff0c;但是实验表明&#xff0c;两个if函数中的内容都得到了实现。按照我们之前所学&#xff0c;一个变量同一时间只能有一个值&#xff0c;…

二叉排序树

在说二叉排序树之前先考虑这样一个例子&#xff0c;假设我们的数据集开始只有一个数{62}&#xff0c;然后现在需要将88插入数据集&#xff0c;于是数据集成了{62,88}&#xff0c;还保持着从小到大有序&#xff0c;再查找有没有58&#xff0c;没有则插入&#xff0c;可此时要想在…

GitLab 中文版如何禁止从 UI 上下载代码?

本文分享如何通过配置来禁止用户从 GitLab 中文版 UI 界面上下载源代码。 GitLab 中文版也就是极狐GitLab&#xff0c;使用界面和 GitLab 一样。常规下载代码的方式也一样&#xff0c;要么使用 SSH 或者 HTTP 克隆&#xff0c;要么直接从 UI 上下载源代码&#xff1a; 但是有些…

Conmi的正确答案——ESP32导出烧录进芯片的固件

版本&#xff1a;ESP-IDF 4.4.7 系统&#xff1a;Windows 11 相关链接&#xff1a; 官网&#xff1a;Read Flash Contents: read_flash GITHUB独立工具&#xff1a;esptool 命令&#xff1a; # 我这里用的是C3和windows版的EXE工具 esptool.exe --chip ESP32-C3 -p COM17 -b …

vue2+ element ui 集成pdfjs-dist

目录 1. 下载Pdf.js1.1 下载1.2 修改配置1.2.1 将pdfjs-3.8.162-dist复制到项目中1.2.2 解决跨域问题1.2.3 将pdf.worker.js文件复制到public目录下1.2.4 安装 pdfjs-dist1.2.5 前端vue代码(示例) 3. 参考资料 1. 下载Pdf.js 1.1 下载 下载链接&#xff08;官方&#xff09;需…

为什么越来越多的跨境卖家放弃电商平台,转向独立站?

对于做跨境电商的卖家来说&#xff0c;采用多平台、多站点的经营策略非常重要。这样做不仅可以分散风险&#xff0c;避免把所有的钱都押在一个市场上&#xff0c;减少“把所有鸡蛋放在一个篮子里”的风险&#xff0c;还能拓宽销售渠道&#xff0c;帮助卖家赚更多的钱&#xff0…

PCB+SMT线上报价系统+PCB生产ERP系统自动化拼板模块升级

PCB生产ERP系统的智能拼版技术&#xff0c;是基于PCB前端报价系统获取到的用户或市场人员已录入系统的板子尺寸及set参数等&#xff0c;按照最优原则或利用率最大化原则自动进行计算并输出拼版样式图和板材利用率&#xff0c;提高工程人员效率&#xff0c;减少板材的浪费。覆铜…

2024年第四届数字化社会与智能系统国际学术会议(DSInS 2024)

会议地点 悉尼会场&#xff1a;澳大利亚悉尼-悉尼科技大学空中科技大学功能中心&#xff0c;沃特尔&#xff08;Aerial UTS Function Centre, Wattle Room&#xff09; 具体地址&#xff1a;Building 10, Level 7, 235 Jones Street, Ultimo, New South Wales, 2007, AU 郑州…

从零开始快速构建Vue3项目

一、技术选型 组件大类 具体插件 vue3插件 相关插件开发文档 基础架构搭建 初始项目搭建、打包构件工具&#xff1a;vite开始 | Vite路由管理及菜单权限封装vue-router介绍 | Vue Router状态管理Pinia介绍 | Pinia 中文文档API请求及异常封装axiosUI框架 element-uihttps…

spring cloud 入门笔记1(RestTemplate,Consul)

最大感受&#xff1a; spring cloud无非是将spring boot中的各个工作模块拆分成独立的小spring boot&#xff0c;各个模块之间&#xff0c;不再是通过导包什么的&#xff0c;调用而是通过网路进行各个模块之间的调用 工具一&#xff1a;RestTemplate 在Java代码中发送HTTP请…

从虚构到现实!FAME助力模型编辑走向实际应用

论文&#xff1a;FAME: Towards Factual Multi-Task Model Editing 链接&#xff1a;https://arxiv.org/abs/2410.10859项目&#xff1a;https://github.com/BITHLP/FAME 前言 大语言模型中丰富的知识使得其在如智能助理&#xff0c;法律顾问&#xff0c;医疗咨询等多个领域中…

无需Photoshop即可在线裁剪和调整图像大小的工具

Bitmind是一个灵活且易于使用的批量图像本地化处理器&#xff0c;经过抓包看&#xff0c;这个工具在浏览器本地运行&#xff0c;不会上传图片到服务器&#xff0c;所以安全性完全有保证。 它可以将图像调整到任何特定尺寸&#xff0c;并在必要时按比例裁剪。 这是一个在线工具…

计算两个结构的乘法

在行列可自由变换的平面上&#xff0c;2点结构有3个 3点结构有6个 计算2*2 2a1*2a14a6 2a1*2a24a8 2a1*2a34a12 显然2a1*2a14a6因为这3个结构都分布在同一列上&#xff0c;就是整数乘法。2a1*2a2的结果有2种写法&#xff0c;一种外形像2a1细节为2a2&#xff0c;一种外形为2…

短剧项目全流程花费项目详解:从软件采购到OSS流量

一、引言 随着网络视频的兴起&#xff0c;短剧项目作为一种新兴的内容形式&#xff0c;受到了广泛关注。然而&#xff0c;短剧项目运营过程中涉及诸多费用&#xff0c;本文将对短剧项目的各项花费进行明细分析&#xff0c;以帮助相关从业者更好地规划预算和控制成本。 二、软…

Vector Optimization – Vector Mask Register

文章目录 Vector优化 – Vector掩码寄存器 Vector优化 – Vector掩码寄存器 One of the reasons for low levels of vectorization is the presence of conditionals (IF statements) inside loops. IF statements introduce control dependencies into a loop. 矢量化水平低的…

冗余连接2 hard题 代随C#写法

此题在卡码网109与力扣685题亦有记载 有一说一C#写法我没咋搞懂 就看明白了思路 这里贴一个答案待后续我醒悟了再来看罢 难就难在对整体数据结构classUnion&#xff08;并查集&#xff09;的理解不熟并且 对于输入输出这个迭代过程理解上也比较吃力 109. 冗余连接II 题…

MySQL:CRUD

MySQL表的增删改查&#xff08;操作的是表中的记录&#xff09; CRUD(增删改查) C-Create新增R-Retrieve检查&#xff0c;查询U-Update更新D-Delete删除 新增&#xff08;Create&#xff09; 语法&#xff1a; 单行数据全列插入 insert into 表名[字段一&#xff0c;字段…

【stable diffusion部署】手把手教你从0基础入门Stable Diffusion

前言 在开始学之前&#xff0c;我想提前说一下&#xff0c;我所理解的AI绘画的本质&#xff0c;就是手替&#xff0c;人提出方案&#xff0c;AI帮你完成具体的作画过程。 写这篇文章的初衷&#xff0c;网上的Stable Diffusion教程太多了&#xff0c;但是我真正去学的时候发现…

前端单元测试框架 引入说明

1. 背景&#xff1a; 2. 如何选择&#xff1a; 2.1. 流行框架 Jest&#xff1a;由Facebook开源的JavaScript测试框架&#xff0c;应用于脸书系以及 ReactJs 系Mocha&#xff1a;适用于 NodeJs 和 浏览器、简易、灵活、有趣的JavaScript 测试框架Jasmine&#xff1a;BDD&#…