三十六、openlayers官网示例Earthquake Clusters解析——在聚合图层鼠标触摸显示五角星

官网demo地址:

Earthquake Clusters

这篇展示了鼠标触摸聚合图层点位显示五角星的效果。

首先是初始化地图,加载了一个KML格式的矢量数据源,extractStyles为false表示不从kml数据源中提取样式。使用Select添加了鼠标选中的交互事件

vector = new VectorLayer({source: new Cluster({distance: 40,source: new VectorSource({url: "https://openlayers.org/en/latest/examples/data/kml/2012_Earthquakes_Mag5.kml",format: new KML({extractStyles: false,}),}),}),style: styleFunction,});const raster = new TileLayer({source: new StadiaMaps({layer: "stamen_toner",}),}); 
const map = new Map({layers: [raster, vector],interactions: defaultInteractions().extend([new Select({condition: function (evt) {return evt.type == "pointermove" || evt.type == "singleclick";},style: selectStyleFunction,}),]),target: "map",view: new View({center: [0, 0],zoom: 2,}),});

其中有两个样式函数,先来看第一个styleFunction。

如果有子feature就显示为黄色圆圈,如果没有子feature则绘制成五角星。

 let currentResolution;function styleFunction(feature, resolution) {if (resolution != currentResolution) {calculateClusterInfo(resolution);currentResolution = resolution;}let style;const size = feature.get("features").length;if (size > 1) {style = new Style({image: new CircleStyle({radius: feature.get("radius"),fill: new Fill({color: [255, 153, 0, Math.min(0.8, 0.4 + size / maxFeatureCount)],}),}),text: new Text({text: size.toString(),fill: textFill,stroke: textStroke,}),});} else {const originalFeature = feature.get("features")[0];style = createEarthquakeStyle(originalFeature);}return style;}

使用calculateClusterInfo 函数计算圆圈的半径,将子feature的extent合并到了一起,结合分辨率算出半径。

const calculateClusterInfo = function (resolution) {maxFeatureCount = 0;const features = vector.getSource().getFeatures();let feature, radius;for (let i = features.length - 1; i >= 0; --i) {feature = features[i];const originalFeatures = feature.get("features");const extent = createEmpty(); //创建一个空的范围对象,用来存储聚类的总范围。let j, jj;for (j = 0, jj = originalFeatures.length; j < jj; ++j) {//获取当前原始特征的几何范围。将这个几何范围合并到总范围 extent 中extend(extent, originalFeatures[j].getGeometry().getExtent());}maxFeatureCount = Math.max(maxFeatureCount, jj);radius = (0.25 * (getWidth(extent) + getHeight(extent))) / resolution;feature.set('radius',radius)}};

extend方法示例

假设你有一个聚类包含三个特征,其范围分别为:

  • 特征1: [0, 0, 1, 1]
  • 特征2: [2, 2, 3, 3]
  • 特征3: [1, 1, 4, 4]

通过逐步扩展 extent:

  • 初始 extent 是空的。
  • 扩展第一个特征后,extent 变为 [0, 0, 1, 1]
  • 扩展第二个特征后,extent 变为 [0, 0, 3, 3]
  • 扩展第三个特征后,extent 变为 [0, 0, 4, 4]

最终的 extent 包含了所有特征的范围,即 [0, 0, 4, 4]

 createEarthquakeStyle是绘制星星的方法,主要用了RegularShape这个类。

function createEarthquakeStyle(feature) {const name = feature.get("name");const magnitude = parseFloat(name.substr(2));const radius = 5 + 20 * (magnitude - 5);return new Style({geometry: feature.getGeometry(),image: new RegularShape({radius: radius,radius2: 3,points: 5,angle: Math.PI,fill: earthquakeFill,stroke: earthquakeStroke,}),});}

写一个小demo来理解RegularShape

//小demolet piontArr = [-213399.46385070545, -7204129.9025042085];let pointFeature = new Feature({geometry: new MultiPoint([piontArr]),});let newLayer = new VectorLayer({source: new VectorSource({features: [pointFeature],}),style: [new Style({image: new RegularShape({radius: 50,radius2:20,points: 5,angle: Math.PI,fill: earthquakeFill,stroke: earthquakeStroke,}),}),],});map.addLayer(newLayer)

 RegularShape参数解释:

  • radius:

    • 含义: 图形的外半径,即从图形中心到外顶点的距离。
  • radius2:

    • 含义: 图形的内半径,仅在绘制星形时有效。表示从图形中心到内顶点的距离。
  • points:

    • 含义: 图形的顶点数。如果 radius2 被定义,则 points 表示星形的顶点数(外顶点和内顶点的总数),否则表示多边形的边数。
    • 示例值: 6 表示绘制一个六边形或六角星形。
  • angle:

    • 含义: 图形的旋转角度,以弧度为单位。Math.PI 表示旋转 180 度。
    • 示例值: Math.PI 表示图形旋转 180 度。

 然后是第二个样式函数selectStyleFunction

鼠标触摸的时候获取到feature自定义属性features取出来,把每一个子feature绘制成星星形状展示。

function selectStyleFunction(feature) {const styles = [new Style({image: new CircleStyle({radius: feature.get("radius"),fill: invisibleFill,}),}),];const originalFeatures = feature.get("features");let originalFeature;for (let i = originalFeatures.length - 1; i >= 0; --i) {originalFeature = originalFeatures[i];styles.push(createEarthquakeStyle(originalFeature));}return styles;}

完整代码:

<template><div class="box"><h1>Earthquake Clusters</h1><div id="map"></div></div>
</template><script>
import KML from "ol/format/KML.js";
import Map from "ol/Map.js";
import View from "ol/View.js";
import {Circle as CircleStyle,Fill,RegularShape,Stroke,Style,Text,Circle,
} from "ol/style.js";
import { MultiPoint, Point } from "ol/geom.js";
import { Cluster, StadiaMaps, Vector as VectorSource } from "ol/source.js";
import { Select, defaults as defaultInteractions } from "ol/interaction.js";
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer.js";
import { createEmpty, extend, getHeight, getWidth } from "ol/extent.js";
import Feature from "ol/Feature.js";
export default {name: "",components: {},data() {return {map: null,};},computed: {},created() {},mounted() {const earthquakeFill = new Fill({color: "rgba(255, 153, 0, 0.8)",});const earthquakeStroke = new Stroke({color: "rgba(255, 204, 0, 0.2)",width: 1,});const textFill = new Fill({color: "#fff",});const textStroke = new Stroke({color: "rgba(0, 0, 0, 0.6)",width: 3,});const invisibleFill = new Fill({color: "rgba(255, 255, 255, 0.01)",});function createEarthquakeStyle(feature) {const name = feature.get("name");const magnitude = parseFloat(name.substr(2));const radius = 5 + 20 * (magnitude - 5);return new Style({geometry: feature.getGeometry(),image: new RegularShape({radius: radius,radius2: 3,points: 5,angle: Math.PI,fill: earthquakeFill,stroke: earthquakeStroke,}),});}let maxFeatureCount;let vector = null;const calculateClusterInfo = function (resolution) {maxFeatureCount = 0;const features = vector.getSource().getFeatures();let feature, radius;for (let i = features.length - 1; i >= 0; --i) {feature = features[i];const originalFeatures = feature.get("features");const extent = createEmpty();let j, jj;for (j = 0, jj = originalFeatures.length; j < jj; ++j) {extend(extent, originalFeatures[j].getGeometry().getExtent());}maxFeatureCount = Math.max(maxFeatureCount, jj);radius = (0.25 * (getWidth(extent) + getHeight(extent))) / resolution;feature.set('radius',radius)}};let currentResolution;function styleFunction(feature, resolution) {if (resolution != currentResolution) {calculateClusterInfo(resolution);currentResolution = resolution;}let style;const size = feature.get("features").length;if (size > 1) {style = new Style({image: new CircleStyle({radius: feature.get("radius"),fill: new Fill({color: [255, 153, 0, Math.min(0.8, 0.4 + size / maxFeatureCount)],}),}),text: new Text({text: size.toString(),fill: textFill,stroke: textStroke,}),});} else {const originalFeature = feature.get("features")[0];style = createEarthquakeStyle(originalFeature);}return style;}function selectStyleFunction(feature) {const styles = [new Style({image: new CircleStyle({radius: feature.get("radius"),fill: invisibleFill,}),}),];const originalFeatures = feature.get("features");let originalFeature;for (let i = originalFeatures.length - 1; i >= 0; --i) {originalFeature = originalFeatures[i];styles.push(createEarthquakeStyle(originalFeature));}return styles;}vector = new VectorLayer({source: new Cluster({distance: 40,source: new VectorSource({url: "https://openlayers.org/en/latest/examples/data/kml/2012_Earthquakes_Mag5.kml",format: new KML({extractStyles: false,}),}),}),style: styleFunction,});const raster = new TileLayer({source: new StadiaMaps({layer: "stamen_toner",}),});const map = new Map({layers: [raster,vector],interactions: defaultInteractions().extend([new Select({condition: function (evt) {return evt.type == "pointermove" || evt.type == "singleclick";},style: selectStyleFunction,}),]),target: "map",view: new View({center: [0, 0],zoom: 2,}),});//小demolet piontArr = [-213399.46385070545, -7204129.9025042085];let pointFeature = new Feature({geometry: new MultiPoint([piontArr]),});let newLayer = new VectorLayer({source: new VectorSource({features: [pointFeature],}),style: [new Style({image: new RegularShape({radius: 50,radius2:20,points: 5,angle: Math.PI,fill: earthquakeFill,stroke: earthquakeStroke,}),}),],});// map.addLayer(newLayer)},methods: {},
};
</script><style lang="scss" scoped>
#map {width: 100%;height: 500px;
}
.box {height: 100%;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Kubernetes】 emptyDir、nfs存储卷 和 PV、PVC

emptyDir存储卷 当pod被分配给节点 容器和容器之间进行共享存储 hostPath nfs共享存储卷 NAS 专业的存储设备&#xff1b;一般是与NFS 搭配&#xff0c;然后共享出去 GFS 自己搭&#xff1b;CEPH(至少要9台) 第三方&#xff1b;NAS 第三方&#xff1b; 云端 oss …

【wiki知识库】05.分类管理模块--后端SpringBoot模块

&#x1f4dd;个人主页&#xff1a;哈__ 期待您的关注 目录 一、&#x1f525;今日目标 二、☀SpringBoot代码修改 1.使用逆向工程生成Category表结构 2. 新增CategoryQueryParam 3.新增CategorySaveParam 4.新增CategotyQueryVo 三、&#x1f916;新增分类管理的相关接口…

v1.2.70-FastJson的AutoType机制研究

v1.2.70-FastJson的AutoType机制研究 最近在对接Alexa亚马逊语音技能&#xff0c;Smart Home Skill Apis时&#xff0c;有一个配置的JSON字符串是这样的&#xff1a; { "capabilityResources": {"friendlyNames": [{"type": "asset",…

python图像识别库-pytesseract

内容目录 一、安装1.安装tesseract OCR1) MAC中安装2) Windows中安装3) 中文报下载 二、pytesseract的简单使用 pytesseract是python的一个用于图像提取的库, 它实际上是对Tesseract OCR引擎的封装。pytesseract使得在Python项目中调用Tesseract变得更加简便&#xff0c;主要用…

17K star,一款开源免费的手机电脑无缝同屏软件

导读&#xff1a;白茶清欢无别事&#xff0c;我在等风也等你。 作为程序员&#xff0c;在我们的工作中经常需要把手机投票到电脑进行调试工作&#xff0c;选择一款功能强大的投屏软件是一件很必要的事情。今天给大家介绍一款开源且免费的投屏软件&#xff0c;极限投屏&#xff…

Arthas调优工具使用

1&#xff0c;服务器端下载 curl -O https://arthas.aliyun.com/arthas-boot.jar 2&#xff0c;服务器端启动 java -jar arthas-boot.jar 选定要绑定的Java进程ID 3&#xff0c;本地idea安装Arthas idea 4&#xff0c;选定方法右键trace,生成命令 trace com.xxx.xxx.xxx.vouche…

C语言数据结构快速排序的非递归、归并排序、归并排序的非递归等的介绍

文章目录 前言一、快速排序非递归二、归并排序五、归并排序非递归总结 前言 C语言数据结构快速排序的非递归、归并排序、归并排序的非递归等的介绍 一、快速排序非递归 快速排序非递归的定义 快速排序非递归&#xff0c;需要使用栈来实现。将左右下标分别push到栈中。在栈为…

基于Tricore的Tasking链接文件解读

目录 1.链接文件有什么用&#xff1f; 2.文件结构和语法解析 2.1 文件结构 2.2 语法解析 3.小结 玩惯了ld文件&#xff0c;突然让搞lsl&#xff0c;被其中花里胡哨的语法搞晕了&#xff0c;例如&#xff1a; memory cpu0_dlmu{mau 8;size 64k;type ram;map cached …

腾讯中视频计划项目玩法,号称执行就有收入

腾讯中视频掘金计划是一个创新的短视频创作与分享平台&#xff0c;类似于西瓜视频&#xff0c;允许用户发布原创视频内容&#xff0c;并将其同步至腾讯旗下的多个平台&#xff0c;用户基数大&#xff0c;相信视频播放量也会比较大。 操作流程&#xff1a; 1. 注册并登录腾讯中…

深入对比:Transformer与RNN的详细解析

在深度学习领域&#xff0c;特别是在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;循环神经网络&#xff08;RNN&#xff09;和Transformer模型都扮演着举足轻重的角色。然而&#xff0c;随着技术的不断发展&#xff0c;Transformer模型逐渐崭露头角&#xff0c;成为…

OrangePi 安装 CANN 套件及体验 AI 应用

CANN 环境安装&#xff08;桌面端跳过&#xff09; CANN 环境存在于下载页面的官方工具中&#xff0c;点击下载即可进入下载页面。 CANN 安装包就在倒数第二项&#xff0c;下载后传到开发板上。 给 CANN 安装包赋予运行权限并运行即可。 chmod x Ascend-cann-toolkit_7.0.0_l…

MQTT协议使用总结

MQTT是基于TCP/IP协议栈构建的异步通信消息协议&#xff0c;是一种轻量级的发布/订阅信息传输协议MQTT在时间和空间上&#xff0c;将消息发送者与接受者分离&#xff0c;可以在不可靠的网络环境中进行扩展。适用于设备硬件存储空间有限或网络带宽有限的场景。 物联网平台支持设…

2.1.4 采用配置类与注解方式使用MyBatis

实战概述&#xff1a;采用配置类与注解方式使用MyBatis 创建MyBatis配置类 在net.huawei.mybatis.config包中创建MyBatisConfig类&#xff0c;用于配置MyBatis核心组件&#xff0c;包括数据源、事务工厂和环境设置。 配置数据源和事务 使用PooledDataSource配置MySQL数据库连接…

kafka-消费者服务搭建配置简单消费(SpringBoot整合Kafka)

文章目录 1、使用efak 创建 主题 my_topic1 并建立6个分区并给每个分区建立3个副本2、创建生产者发送消息3、application.yml配置4、创建消费者监听器5、创建SpringBoot启动类6、屏蔽 kafka debug 日志 logback.xml7、引入spring-kafka依赖 1、使用efak 创建 主题 my_topic1 并…

DP动态规划(上)

文章目录 动态规划基本概念斐波那契数列问题C 实现Python 实现Java 实现 迷你结C、Python和Java在实现动态规划时有哪些性能差异&#xff1f;迷你结哪种语言在动态规划中更适合大规模数据处理?迷你结C有哪些知名的库适用于动态规划和大数据处理?动态规划辅助库大数据处理库 迷…

【网络协议 | HTTP】HTTP总结与全梳理(一) —— HTTP协议超详细教程

&#x1f525;博客简介&#xff1a;开了几个专栏&#xff0c;针对 Linux 和 rtos 系统&#xff0c;嵌入式开发和音视频开发&#xff0c;结合多年工作经验&#xff0c;跟大家分享交流嵌入式软硬件技术、音视频技术的干货。   ✍️系列专栏&#xff1a;C/C、Linux、rtos、嵌入式…

二叉树练习题(2024/6/5)

1翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;root [2,1,3] 输出&#xff1a;[2,3,1]…

dirfuzz-web敏感目录文件扫描工具

dirfuzz介绍 dirfuzz是一款基于Python3的敏感目录文件扫描工具&#xff0c;借鉴了dirsearch的思路&#xff0c;扬长避短。在根据自身实战经验的基础上而编写的一款工具&#xff0c;经过断断续续几个月的测试、修改和完善。 项目地址&#xff1a;https://github.com/ssrc-c/di…

运维开发介绍

目录 1.什么是运维开发 2.作用 3.优点 4.缺点 5.应用场景 5.1.十个应用场景 5.2.网站和Web应用程序 6.案例 7.小结 1.什么是运维开发 运维开发&#xff08;DevOps&#xff09;是一种结合软件开发&#xff08;Development&#xff09;与信息技术运维&#xff08;Opera…

什么是回调函数?callback()

首先要知道一个点就是 在js中&#xff0c;函数是可以作为函数的参数传递的 所以其实回调函数 就是这个传进去的参数 其实回调函数的本质样子和普通函数是一样的 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…