WebGis - Realize heat map

About the principle of heat map:

1. First obtain the heat map data, the data is composed of xy coordinates and value

2. According to the coordinates of the heat map data, draw a circle with a gray gradient from the center to the outside on the canvas map

3. Using the principle that gray levels can be superimposed, calculate the gray value obtained by cross-overlapping each pixel data;

4. According to the gray value calculated by each pixel, color mapping is performed in a color ribbon, and finally the image is colored to obtain a heat map

The demo is as follows:

First write a heat map fake data

    initdata() {
      var data = [
        { x: 71, y: 77, value: 25 },
        { x: 38, y: 75, value: 97 },
        { x: 73, y: 19, value: 71 },
        { x: 72, y: 42, value: 63 },
        { x: 63, y: 95, value: 97 },
        { x: 90, y: 37, value: 34 },
        { x: 77, y: 42, value: 66 },
        { x: 171, y: 254, value: 20 },
        { x: 6, y: 82, value: 64 },
        { x: 87, y: 77, value: 14 },
        { x: 100, y: 200, value: 80 }
      ]
      this.data = data
    },

Next we create a canvas and draw a radial gradient circle on the canvas.

<template>
  <div class="">
    <canvas id="mycanvas" width="500" height="200" />
  </div>
</template>
    initcanvas() {
      // 找到该canvas节点
      var c = document.getElementById('mycanvas')
      // 创建文本对象
      var context = c.getContext('2d')
      // 遍历热力图数据
      this.data.forEach(point => {
        // 解构赋值
        const { x, y, value } = point
        // 开始画圆
        context.beginPath()
        // 通过art方法画圆,x-起始点x坐标,y-起始点y坐标,30-圆半径,0-初始角度,2*Math.PI最终角度实际上就是360度
        context.arc(x, y, 30, 0, 2 * Math.PI)
        context.closePath()

        // 创建渐变色: r,g,b取值比较自由,我们只关注alpha的数值,这里是径向渐变,xy都代表圆点位置,只不过一个半径是0一个半径是30
        const radialGradient = context.createRadialGradient(x, y, 0, x, y, 30)
        // 渐变
        radialGradient.addColorStop(0.0, 'rgba(0,0,0,1)')
        radialGradient.addColorStop(1.0, 'rgba(0,0,0,0)')
        // 填充渐变色
        context.fillStyle = radialGradient

        // 设置globalAlpha: 需注意取值需规范在0-1之间,我们这里的14是value的最小值,100是value的最大值,可以自行调整
        const globalAlpha = (value - 14) / (100 - 14)
        context.globalAlpha = Math.max(Math.min(globalAlpha, 1), 0)
        // 打印看到每个圆的灰色值是不一样的,然后每个像素叠加的地方也会累积灰度值,这就是核心原理
        console.log(context.globalAlpha)
        // 填充颜色
        context.fill()
        // 像素着色,获取我们整个画布的所有像素点的rgba
        const imageData = context.getImageData(0, 0, 1000, 800)
        const data = imageData.data
        // rgba,a在第四个所以我们只看a
        for (var i = 3; i < data.length; i += 4) {
          const alpha = data[i]
          // 根据a的值,来找我们彩色映射带的值,将彩色映射带的值重新赋予该canvas的imgdata
          const color = this.colorPicker(alpha)
          data[i - 3] = color[0]
          data[i - 2] = color[1]
          data[i - 1] = color[2]
        }
        context.putImageData(imageData, 0, 0)
      })
    },
    // 初始化彩色映射带
    inittool() {
      // 定义彩色映射带的渐变值
      const colorstops = {
        0.2: 'rgb(0,0,255)',
        0.3: 'rgb(43,111,231)',
        0.4: 'rgb(2,192,241)',
        0.6: 'rgb(44,222,148)',
        0.8: 'rgb(254,237,83)',
        0.9: '#f00',
        1.0: '#f00'
      }
      // 这里显示彩色映射带
      const canvas = document.createElement('canvas')
      canvas.width = 240
      canvas.height = 30
      const ctx = canvas.getContext('2d')
      const linearGradient = ctx.createLinearGradient(0, 0, 256, 30)
      for (const key in colorstops) {
        linearGradient.addColorStop(key, colorstops[key])
      }
      ctx.fillStyle = linearGradient
      ctx.fillRect(0, 0, 240, 30)
      // 我们取彩色应色带height设为1,因为多取也用不到,只需要第一行像素点的rgba
      this.imageData = ctx.getImageData(0, 0, 250, 1).data
      console.log(this.imageData)
      document.body.appendChild(canvas)
    },

Replace imgdata method

    colorPicker(position) {
      // 这里根据a的值也就是灰度值来截取对应彩色映射带的值,a值越小,对应的彩色映射带的值越靠前
      return this.imageData.slice(position * 4, position * 4 + 3)
    }

We should initialize the colormap band first

  mounted() {
    this.initdata()
    this.inittool()
    this.initcanvas()
  },

The final display:

 

Guess you like

Origin blog.csdn.net/yinzisang/article/details/123846978