leaflet学习笔记-带过滤的图例(九)

这篇具有很好参考价值的文章主要介绍了leaflet学习笔记-带过滤的图例(九)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

图例不只能够帮助我们在查看地图的时候更加方便容易地分辨不同颜色代表的要素,本文要介绍的图例组件还可以按需求过滤掉不用显示的要素,使地图的更能清晰的显示我们需要显示的内容

技术核心

说到过滤要素,第一时间想到的就是滑块组件,这里我们选择了Element-plus的Slider 滑块组件,主要功能就是根据滑块背景的不同颜色,滑动滑块过滤掉滑块范围以外背景颜色的要素。这里遇到一个大麻烦,本来以为很容易解决的,后面发现没有这么容易完成,就是滑块的背景颜色添加,这里想了好几种方式,最后还是只能使用原生js通过操作dom实现背景颜色的添加和上下两个滑块遮罩的添加(将要过滤的颜色范围遮盖掉)。核心代码如下:

watchEffect(() => {
  let [min, max] = sliderValue.value

  //为了添加滑块的遮罩,达到想要的效果(重点)
  nextTick(() => {
    let runway = document.getElementsByClassName('sliderLegend')?.[0]?.querySelectorAll('.el-slider__runway')[0]
    if (!runway.querySelector('.maxBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', 'maxBar maskBar')
      runway.appendChild(div)
    }

    if (!runway.querySelector('.minBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', 'minBar maskBar')
      runway.appendChild(div)
    }

    let maxMaskBar = document.querySelector('.maxBar')
    let minMaskBar = document.querySelector('.minBar')

    if (maxMaskBar) {
      maxMaskBar.style.height = new BigNumber(100).minus(max).toNumber() + '%'
    }

    if (minMaskBar) {
      minMaskBar.style.height = min + '%'
    }
  })
})

完整代码

/**
* sliderLegend.vue 可以拖动滑块过滤的图例
* @Author ZhangJun
* @Date  2024/1/19 9:36
**/
<template>
  <el-card class='slider-block absolute right-10 bottom-10'
           v-if='grades.values&&grades.values.length>0'
           style='z-index: 1000;'>
    <el-space direction='vertical' :size='20'>
      <el-text size='large' type='info'>{{ grades.desc }}{{ grades.unit }}</el-text>

      <div style='width: 60px;text-align: left;'>
        <el-slider ref='legendRef'
                   class='sliderLegend'
                   v-model='sliderValue'
                   @change='onChange'
                   :range='true'
                   vertical
                   :marks='marks'
                   v-bind='options' />
      </div>
    </el-space>
  </el-card>
</template>

<script setup>
import { ref, defineProps, computed, reactive, watchEffect, nextTick } from 'vue'
import BigNumber from 'bignumber.js'

const props = defineProps({
  gradesValues: { type: Array, default: () => ([]) },//分级的value数值
  gradesColors: { type: Array, default: () => ([]) },//分级的color数值(需要与gradesValues一一对应)
})

const emits = defineEmits(['update:modeValue'])

let legendRef = ref()

//当前滑块的值
let sliderValue = ref([0, 100])

//间隔数值
let interval = ref()

//为了获取真实数据和百分比之间的映射关系
let percentage2ValueDic = {}
let valueDic2Percentage = {}

/**
 * @Description 生成滑块的背景颜色
 * @Param colors 备选颜色集合
 * @Author ZhangJun
 * @Date  2024-01-19 01:43:56
 * @return void
 **/
let generationLinearGradient = computed(() => {
  let { colors } = grades
  let interval = new BigNumber(1).div(colors?.length)
  let temp = colors.map((color, index) => {
    let percentage = interval.times(index).times(100).toFixed(0) + '%'
    let rgba = `rgba(${color[0]},${color[1]},${color[2]},${color.length > 3 ? color[3] / 255 : 1})`
    if (index === 0) {
      return [rgba]
    } else {
      return [percentage, rgba]
    }
  })

  return `linear-gradient(to top,${temp.flat()})`
})

//刻度值
const marks = computed(() => {
  //清空
  percentage2ValueDic = {}
  valueDic2Percentage = {}
  let { values, unit } = grades
  interval.value = new BigNumber(1).div(values?.length - 1)
  let marks = {}
  values.forEach((value, index) => {
    let percentageVal = interval.value.times(index).times(100).toFixed(0)
    marks = { ...marks, [percentageVal]: `${value}` }
    //做映射使用
    percentage2ValueDic = { ...percentage2ValueDic, [percentageVal]: value }
    valueDic2Percentage = { ...valueDic2Percentage, [value]: percentageVal }
  })
  return marks
})

//分级数据
let grades = reactive({
  values: props.gradesValues,
  colors: props.gradesColors,
  unit: undefined,
  desc: '',
})

//默认的配置参数
let options = computed(() => {
  let { values } = grades
  let height = (values?.length - 1) * 40
  height = height > 300 ? 300 : height
  return {
    min: 0,
    max: 100,
    height: `${height}px`,
    step: interval.value.times(100).toFixed(0),
    showTooltip: false,
  }
})

/**
 * @Description 初始化当前control
 * @Param gradesData 分级参数
 * @Author ZhangJun
 * @Date  2024-01-22 09:38:17
 * @return void
 **/
function initControl(gradesData) {
  sliderValue.value = [0, 100]
  grades = Object.assign(grades, gradesData)
}

/**
 * @Description 获取数组里面最接近这个值的数
 * @Param arr 数组
 * @Param target 目标值
 * @Author ZhangJun
 * @Date  2024-01-19 07:19:21
 * @return void
 **/
function getClosestNumber(arr = [], target) {
  let minDistance = Math.abs(target - arr[0])
  let [closestNumber] = arr

  for (let i = 1; i < arr.length; i++) {
    let distance = Math.abs(target - arr[i])
    if (distance < minDistance) {
      minDistance = distance
      closestNumber = arr[i]
    }
  }

  return closestNumber
}

/**
 * @Description 滑块数值改变
 * @Param e 事件回调参数
 * @Author ZhangJun
 * @Date  2024-01-22 09:38:59
 * @return void
 **/
function onChange(e) {
  let [min, max] = e
  let arr = Object.keys(percentage2ValueDic)
  min = getClosestNumber(arr, min)
  max = getClosestNumber(arr, max)
  emits('update:modeValue', [percentage2ValueDic[min], percentage2ValueDic[max]])
}

watchEffect(() => {
  let [min, max] = sliderValue.value

  //为了添加滑块的遮罩,达到想要的效果(重点)
  nextTick(() => {
    let runway = document.getElementsByClassName('sliderLegend')?.[0]?.querySelectorAll('.el-slider__runway')[0]
    if (!runway.querySelector('.maxBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', 'maxBar maskBar')
      runway.appendChild(div)
    }

    if (!runway.querySelector('.minBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', 'minBar maskBar')
      runway.appendChild(div)
    }

    let maxMaskBar = document.querySelector('.maxBar')
    let minMaskBar = document.querySelector('.minBar')

    if (maxMaskBar) {
      maxMaskBar.style.height = new BigNumber(100).minus(max).toNumber() + '%'
    }

    if (minMaskBar) {
      minMaskBar.style.height = min + '%'
    }
  })
})

defineExpose({ initControl })

</script>

<style scoped lang='scss'>
::v-deep .el-slider__runway {
  background: v-bind(generationLinearGradient);

  .maskBar {
    width: 100%;
    height: auto;
    background: lightgrey;
    position: absolute;
    border-radius: 6px;
  }

  .maxBar {
    top: -3px;
  }

  .minBar {
    bottom: -3px;
  }
}

::v-deep .el-slider__bar {
  background: transparent;
}
</style>

效果

leaflet学习笔记-带过滤的图例(九),leaflet学习笔记,学习,笔记,javascript,图例,leaflet

过滤后的效果

leaflet学习笔记-带过滤的图例(九),leaflet学习笔记,学习,笔记,javascript,图例,leaflet

本来原理很简单,主要时间还是花费到了slider的背景颜色上,还要添加一个上下滑动的遮罩,才能将要过滤掉的颜色范围遮掉

进阶版

加入可横向/竖向选择

/**
* sliderLegend.vue 可以拖动滑块过滤的图例
* @Author ZhangJun
* @Date  2024/1/19 9:36
**/
<template>
  <el-card
    class="slider-block absolute right-10 bottom-10 text-center"
    v-if="grades.values && grades.values.length > 0"
    :body-style="getBodyStyle"
    style="z-index: 600"
  >
    <el-space direction="vertical" :size="vertical ? 20 : 0">
      <el-text type="info">{{ grades.desc }}{{ grades.unit }}</el-text>

      <div style="text-align: left">
        <el-slider ref="legendRef" class="sliderLegend" v-model="sliderValue" @change="onChange" :range="true" :marks="marks" v-bind="options" />
      </div>
    </el-space>
  </el-card>
</template>

<script setup>
import { ref, defineProps, computed, reactive, watchEffect, nextTick } from 'vue'
import BigNumber from 'bignumber.js'

const props = defineProps({
  gradesValues: { type: Array, default: () => [] }, //分级的value数值
  gradesColors: { type: Array, default: () => [] }, //分级的color数值(需要与gradesValues一一对应)
  intervalHeight: { type: Number, default: 40 }, //间隔的高的
  maxHeight: { type: Number, default: 195 }, //图例最高高度限制
  width: { type: Number, default: 130 }, //图例宽度
  vertical: { type: Boolean, default: false }, //是否垂直模式
})

const emits = defineEmits(['update:modeValue'])

let legendRef = ref()

//当前滑块的值
let sliderValue = ref([0, 100])

//间隔数值
let interval = ref()

//为了获取真实数据和百分比之间的映射关系
let percentage2ValueDic = {}
let valueDic2Percentage = {}

//得到内容部分的样式
let getBodyStyle = computed(() => {
  if (props?.vertical) {
    return { padding: `10px 0 0`, width: `${props.width}px` }
  } else {
    return { padding: `10px`, height: `${props.width}px` }
  }
})

/**
 * @Description 生成滑块的背景颜色
 * @Param colors 备选颜色集合
 * @Author ZhangJun
 * @Date  2024-01-19 01:43:56
 * @return void
 **/
let generationLinearGradient = computed(() => {
  let { colors } = grades
  let interval = new BigNumber(1).div(colors?.length - 1)
  let temp = colors.map((color, index) => {
    let percentage = interval.times(index).times(100).toFixed(0) + '%'
    let rgba = `rgba(${color[0]},${color[1]},${color[2]},${color.length > 3 ? color[3] / 255 : 1})`
    if (index === 0) {
      return [rgba]
    } else {
      return [percentage, rgba]
    }
  })
  if (props?.vertical) {
    return `linear-gradient(to top,${temp.flat()})`
  } else {
    return `linear-gradient(to right,${temp.flat()})`
  }
})

//刻度值
const marks = computed(() => {
  //清空
  percentage2ValueDic = {}
  valueDic2Percentage = {}
  let { values, unit } = grades
  interval.value = new BigNumber(1).div(values?.length - 1)
  let marks = {}
  values.forEach((value, index) => {
    let percentageVal = interval.value.times(index).times(100).toFixed(0)
    marks = { ...marks, [percentageVal]: `${value}` }
    //做映射使用
    percentage2ValueDic = { ...percentage2ValueDic, [percentageVal]: value }
    valueDic2Percentage = { ...valueDic2Percentage, [value]: percentageVal }
  })
  return marks
})

//分级数据
let grades = reactive({
  values: props.gradesValues,
  colors: props.gradesColors,
  unit: undefined,
  desc: '',
})

//默认的配置参数
let options = computed(() => {
  let { values } = grades
  let height = new BigNumber(props.intervalHeight).times(values?.length - 1).toNumber()
  height = height > props.maxHeight ? props.maxHeight : height

  let options_temp = {
    min: 0,
    max: 100,
    step: interval.value.times(100).toFixed(0),
    showTooltip: false,
    vertical: props?.vertical,
    size: 'small',
  }

  if (props?.vertical) {
    options_temp = {
      ...options_temp,
      height: `${height}px`,
    }
  } else {
    options_temp = {
      ...options_temp,
      style: {
        margin: '0 20px 0',
        width: `${height}px`,
      },
    }
  }

  return options_temp
})

/**
 * @Description 初始化当前control
 * @Param gradesData 分级参数
 * @Author ZhangJun
 * @Date  2024-01-22 09:38:17
 * @return void
 **/
function initControl(gradesData) {
  sliderValue.value = [0, 100]
  grades = Object.assign(grades, gradesData)
}

/**
 * @Description 获取数组里面最接近这个值的数
 * @Param arr 数组
 * @Param target 目标值
 * @Author ZhangJun
 * @Date  2024-01-19 07:19:21
 * @return void
 **/
function getClosestNumber(arr = [], target) {
  let minDistance = Math.abs(target - arr[0])
  let [closestNumber] = arr

  arr.forEach((value, index) => {
    if (index > 0) {
      let distance = Math.abs(target - value)
      if (distance < minDistance) {
        minDistance = distance
        closestNumber = value
      }
    }
  })

  return closestNumber
}

/**
 * @Description 滑块数值改变
 * @Param e 事件回调参数
 * @Author ZhangJun
 * @Date  2024-01-22 09:38:59
 * @return void
 **/
function onChange(e) {
  let [min, max] = e
  let arr = Object.keys(percentage2ValueDic)
  min = getClosestNumber(arr, min)
  max = getClosestNumber(arr, max)
  emits('update:modeValue', [percentage2ValueDic[min], percentage2ValueDic[max]])
}

watchEffect(() => {
  let [min, max] = sliderValue.value

  //为了添加滑块的遮罩,达到想要的效果(重点)
  nextTick(() => {
    let runway = document.getElementsByClassName('sliderLegend')?.[0]?.querySelectorAll('.el-slider__runway')[0]
    if (!runway?.querySelector('.maxBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', `maxBar maskBar ${props?.vertical ? 'verticalBar' : ''}`)
      runway.appendChild(div)
    }

    if (!runway?.querySelector('.minBar')) {
      let div = document.createElement('div')
      div.setAttribute('class', `minBar maskBar ${props?.vertical ? 'verticalBar' : ''}`)
      runway.appendChild(div)
    }

    let maxMaskBar = document.querySelector('.maxBar')
    let minMaskBar = document.querySelector('.minBar')

    if (maxMaskBar) {
      if (props?.vertical) {
        maxMaskBar.style.height = new BigNumber(100).minus(max).toNumber() + '%'
      } else {
        debugger
        maxMaskBar.style.width = new BigNumber(100).minus(max).toNumber() + '%'
      }
    }

    if (minMaskBar) {
      if (props?.vertical) {
        minMaskBar.style.height = min + '%'
      } else {
        minMaskBar.style.width = min + '%'
      }
    }
  })
})

defineExpose({ initControl })
</script>

<style scoped lang="scss">
::v-deep .el-slider__runway {
  background: v-bind(generationLinearGradient);

  .maskBar {
    height: 100%;
    width: auto;
    top: 0;

    &.verticalBar {
      width: 100%;
      height: auto;
      top: auto;
    }

    background: lightgrey;
    position: absolute;
    border-radius: 6px;
  }

  .maxBar {
    right: -3px;

    &.verticalBar {
      top: -3px;
      right: auto;
    }
  }

  .minBar {
    left: -3px;

    &.verticalBar {
      bottom: -3px;
      left: auto;
    }
  }
}

::v-deep .el-slider__bar {
  background: transparent;
}
</style>

本文为学习笔记,仅供参考文章来源地址https://www.toymoban.com/news/detail-814842.html

到了这里,关于leaflet学习笔记-带过滤的图例(九)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 读SQL学习指南(第3版)笔记05_过滤

    3.2.4.1. concat(\\\'Learning\\\', \\\' \\\', \\\'SQL\\\') 3.2.6.1. (\\\'Boston\\\', \\\'New York\\\', \\\'Chicago\\\') 3.3.1.1. =、!=、<、>、<>、like、in和between 3.3.2.1. +、−、*和/ 4.3.3.1. 当需要同时限制范围的上限和下限时,可以选择使用between运算符构建单个查询条件,而不用两个单独的条件 4.3.3.2. 首先必须指定范围的下

    2024年02月11日
    浏览(35)
  • OpenCvSharp学习笔记13--使用InRange进行HSV阈值过滤、渐变色生成

    HSV色彩空间介绍 使用InRange操作阈值 基于HSV色彩空间的像素值范围检测对象 生成渐变色 HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)。HSV色系对用户来说是一种直观的颜色模型,对于颜色,人们直观的会问”

    2024年02月04日
    浏览(52)
  • Spring MVC学习笔记,包含mvc架构使用,过滤器、拦截器、执行流程等等

    😀😀😀创作不易,各位看官点赞收藏. Spring MVC:Spring MVC是Spring Framework的一部分,是基于java实现的MVC的轻量级Web框架。 官网文档地址:https://docs.spring.io/spring-framework/docs/4.2.4.RELEASE/spring-framework-reference/html/mvc.html 轻量级,简单易学。 高效,基于请求和响应的MVC框架。 与Spri

    2024年02月15日
    浏览(48)
  • JavaScript学习笔记05

    什么是 BOM BOM(Browser Object Model)是指 浏览器对象模型 ,是用于描述这种对象与对象之间层次关系的模型。 浏览器对象模型(BOM)提供了独立于内容的、可以与浏览器窗口进行互动的对象结构。 浏览器 主流的浏览器分为 IE、Microsoft Edge、Chrome、Firefox、Safari、Opera 等几大类

    2024年02月07日
    浏览(36)
  • 尚硅谷JavaScript高级学习笔记

    JavaScript中函数是对象。我们后续描述构造函数的内存模型时,会将构造函数称为 构造函数对象。 typeof 运算符来查看值的类型,它返回的是类型的字符串值 == 会做数据转换 输出: 每个函数都有一个prototype属性,它默认指向一个0bject空对象(即称为:原型对象) 给原型对象添加

    2024年03月11日
    浏览(49)
  • 学习笔记 JavaScript基础语法(全)

    1.1 浏览器执行 JS 简介 浏览器分成两部分:渲染引擎和 JS 引擎 渲染引擎 :用来解析HTML与CSS,俗称内核,比如 chrome 浏览器的 blink ,老版本的 webkit JS 引擎 :也称为 JS 解释器。 用来读取网页中的JavaScript代码,对其处理后运行,比如 chrome 浏览器的 V8 1.2 JS的组成 1.2.1 ECMAScr

    2024年02月05日
    浏览(40)
  • 【前端学习笔记2】javaScript基础

    是一种运行在客户端(服务器的编程语言) javacript分为行内JavaScript,内部JavaScript,外部JavaScript 内部JavaScript 直接写在html中body里面 alert(“hello,world”) 我们将script放在html文件的地步附近的原因是浏览器会按照代码在文件中的顺序加载html 如果先加载的JavaScript期望修改其

    2024年01月22日
    浏览(37)
  • JavaWEB学习笔记(二)------HTTP、Servlet、会话、过滤器、监听器、Ajax、前端工程化

    目录 HTTP HTTP1.1 请求和响应的报文格式 请求报文 响应报文 常见状态响应码 Servlet  静态资源和动态资源 ​编辑  Servlet简介  Servlet开发流程 导入和响应头问题 url-pattern不同写法 url-pattern工作方式 Servlet注解方式配置 Servlet生命周期  Servlet继承结构 Servlet接口 GenerisServlet类 Ht

    2024年01月21日
    浏览(43)
  • JavaScript 学习笔记(Day5)

    「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。推荐先按顺序阅读往期内容: 1. JavaScript 学习笔记(Day1) 2. JavaScript 学习笔记(Day2) 3. JavaScript 学习笔记(Day3) 4. JavaScript

    2024年01月19日
    浏览(47)
  • 【JavaScript】面向后端快速学习 笔记

    制作动态页面 脚本语言 弱类型 TS 强类型 1.HTML内部包裹 但是只能单页面使用 引入外部JS文件 2.1 数据类型 数值类型统一为 number , 不区分整数和浮点数 字符串类型为 string 和JAVA中的String相似,JS中 不严格区分单双引号 ,都可以用于表示字符串 布尔类型为 boolean 和Java中的boolea

    2024年01月21日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包