三十六、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

//小demo
    let 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,
      }),
    });

    //小demo
    let 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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大模型Prompt-Tuning技术进阶

LLM的Prompt-Tuning主流方法 面向超大规模模型的Prompt-Tuning 近两年来&#xff0c;随之Prompt-Tuning技术的发展&#xff0c;有诸多工作发现&#xff0c;对于超过10亿参数量的模型来说&#xff0c;Prompt-Tuning所带来的增益远远高于标准的Fine-tuning&#xff0c;小样本甚至…

在cmd菜单中使用自定义命令通过bat和powershell命令调用翻译API

先说一个血淋淋的结果&#xff0c;这个小功能其实在github已经有大佬帮我们封装好了&#xff0c;我也是自己刚倒腾好之后才发现的&#xff0c;所以如果只是需要这个功能的朋友可以直接移步这个项目&#xff1a;https://github.com/kenshinji/yddict&#xff0c;自己电脑安装一个…

【JVM】已验鼎真,鉴定为:妈妈加载的(双亲委派模型)

【JVM】已验鼎真&#xff0c;鉴定为&#xff1a;妈妈加载的&#xff08;双亲委派模型&#xff09; 在Java的世界中&#xff0c;类加载器&#xff08;ClassLoader&#xff09;是Java虚拟机&#xff08;JVM&#xff09;用来动态加载类的基础组件。双亲委派模型&#xff08;Paren…

grpc接口调用

grpc接口调用 准备依赖包clientserver 参考博客&#xff1a; Grpc项目集成到java方式调用实践 gRpc入门和springboot整合 java 中使用grpc java调用grpc服务 准备 因为需要生成代码&#xff0c;所以必备插件 安装后重启 依赖包 <?xml version"1.0" encoding&…

云服务(ECS)Docker安装vulhub安装详解

本文以xshell进行远程控制 1.以ssh连接云服务器 ssh 服务器名公网ip [D:\~]$ ssh root47.99.138.9 在弹框中输入密码 2.安装docker curl -s http://get.docker.com/ | sh rootiZbp1fm14idjlfp53akni8Z:~# curl -s https://get.docker.com/ | sh # Executing docker insta…

fairseq框架使用记录

sh命令 cmd"fairseq-train data-bin/$data_dir--save-dir $save_dir--distributed-world-size $gpu_num -s $src_lang -t $tgt_lang--arch $arch--dropout $dropout--criterion $criterion --label-smoothing 0.1--task mmt_vqa--optimizer adam --adam-betas (0.9, 0.98…

Vue的APP实现下载文件功能,并将文件保存到手机中

Vue的APP实现下载文件功能&#xff0c;并将文件保存到手机中 文字说明后台核心代码前台核心代码运行截图项目链接 文字说明 本文介绍Vue实现的APP&#xff0c;将文件下载并保存到手机中&#xff0c;为系统提供导出功能&#xff1b;同时支持导入&#xff0c;即选择本地的文件后&…

【动手学深度学习】卷积神经网络CNN的研究详情

目录 &#x1f30a;1. 研究目的 &#x1f30a;2. 研究准备 &#x1f30a;3. 研究内容 &#x1f30d;3.1 卷积神经网络 &#x1f30d;3.2 练习 &#x1f30a;4. 研究体会 &#x1f30a;1. 研究目的 特征提取和模式识别&#xff1a;CNN 在计算机视觉领域被广泛用于提取图像…

【AI大模型】Transformers大模型库(四):AutoTokenizer

目录​​​​​​​ 一、引言 二、自动分词器&#xff08;AutoTokenizer&#xff09; 2.1 概述 2.2 主要特点 2.3 代码示例 三、总结 一、引言 这里的Transformers指的是huggingface开发的大模型库&#xff0c;为huggingface上数以万计的预训练大模型提供预测、训练等服…

Java基础27,28(多线程,ThreadMethod ,线程安全问题,线程状态,线程池)

目录 一、多线程 1. 概述 2. 进程与线程 2.1 程序 2.2 进程 2.3 线程 2.4 进程与线程的区别 3. 线程基本概念 4.并发与并行 5. 线程的创建方式 方式一&#xff1a;继承Thread类 方式二&#xff1a;实现Runable接口 方式三&#xff1a;实现Callable接口 方式四&…

【操作系统】(详细理解进程的状态)执行状态、就绪状态、阻塞状态、挂起状态

下面是进程的几种状态的概念&#xff1a; 执行状态&#xff1a;当一个进程已获得必要资源&#xff0c;并占有CPU进行执行。 就绪状体&#xff1a;进程已分配到除CPU外的所有必要资源&#xff0c;只要获取CPU允许就可立即执行。 阻塞状态&#xff1a;正在执行的进程&#xff0c;…

C++之虚函数与多态

1、多态 前面三种称为静态绑定&#xff08;静态多态&#xff09;&#xff0c;最后面的虚函数&#xff0c;则称为动态绑定&#xff08;动态多态&#xff09;。 2、静态绑定与动态绑定 要实现动态绑定&#xff0c;就必须使用虚函数。 3、虚函数 只有当你在&#xff1a;基类的指…

计算机组成原理·考点知识点整理

根据往年考试题&#xff0c;对考点和知识点的一个整理。 校验编码 码距 一种编码的最小码距&#xff0c;其实就是指这种编码的码距。码距有两种定义&#xff1a; 码距所描述的对象含义 2 2 2 个特定的码其二进制表示中不同位的个数一种编码这种编码中任意 2 2 2 个合法编码的…

统一响应,自定义校验器,自定义异常,统一异常处理器

文章目录 1.基本准备&#xff08;构建一个SpringBoot模块&#xff09;1.在A_universal_solution模块下创建新的子模块unified-processing2.pom.xml引入基本依赖3.编写springboot启动类4.启动测试 2.统一响应处理1.首先定义一个响应枚举类 RespBeanEnum.java 每个枚举对象都有co…

JVMの垃圾回收

在上一篇中&#xff0c;介绍了JVM组件中的运行时数据区域&#xff0c;这一篇主要介绍垃圾回收器 JVM架构图&#xff1a; 1、垃圾回收概述 在第一篇中介绍JVM特点时&#xff0c;有提到过内存管理&#xff0c;即Java语言相对于C&#xff0c;C进行的优化&#xff0c;可以在适当的…

技术回眸一笑

回忆一下一年前的出差日记吧&#xff0c;那个时候真的是一点经验没有&#xff0c;干硬件又干软件&#xff0c;只能一步一步慢慢摸索&#xff0c;努力过后慢慢成长起来的吧。那个时候甚至开学了都没有正常报道&#xff0c;但是也收获了不少东西&#xff0c;并且也将作为我后来继…

Vue——组件数据传递与props校验

文章目录 前言组件数据传递的几种类型简单字符串类型数据专递其他类型数据(数字、数组、对象)传递注意事项 数据传递值校验限定数据类型 type给定默认值 default指定必选项 required 前言 组件与组件之间并不是完全独立的&#xff0c;他们之间可以进行一些数据的传递操作。传递…

10个高清视频素材库分享,高清高质量的分享给你

今天&#xff0c;我将为各位介绍几个极具价值的高清视频素材库。无论您是短视频创作者、自媒体运营者还是影视后期制作专家&#xff0c;这些素材库将大大提升您作品的质量。现在&#xff0c;让我们直接深入主题&#xff0c;探索这些优秀的资源平台&#xff01; 蛙学府视频素材…

使用cesiumLab使shp转为3dtlies

过程不做赘述&#xff0c;网上大把&#xff0c;说下注意事项。 1. 存储3DTiles 选项 若是打开则输出的文件为glb格式文件,因为glb文件好储存易传输跨平台。cesium可以使用但无法处理&#xff0c;例如改变颜色&#xff0c;改着色器等。若是不打开则输出的文件为bm3d格式文件,此…

ShowDoc item_id 未授权SQL注入漏洞复现

0x01 产品简介 ShowDoc 是一个开源的在线文档协作平台,它支持Markdown、图片等多种格式,方便团队成员共同编辑和分享文档。企业常见使用场景是使用其进行接口文档、内部知识库管理。 0x02 漏洞概述 2024年6月,ShowDoc官方发布新版本修复了一个SQL注入漏洞。鉴于该漏洞无前…