熱力圖之heatmap


2021-12-24

Heatmap.js 是目前應用最廣的web動態熱圖javaScript庫。heatmap使用 canvas 進行繪制。

一、傳送門

Heatmap官網:https://www.patrick-wied.at/static/heatmapjs/

github下載: https://github.com/pa7/heatmap.js

 

二、代碼結構

1、整個js庫包裹在一個立即執行的匿名函數里,以避免污染全局命名空間。這也是很多js庫的常見寫法。
2、核心對象有三個:Store(數據)、Canvas2dRenderer(繪制工具)、HeatMap(構建器)。
3、通過global['h337']暴露創建工廠。


三、熱力圖渲染原理

以 heatmap.js v2.0.5 為例子; heatmap使用 canvas 進行繪制。

Heatmap.js 最重要的4個點: _getPointTemplate, _getColorPalette , _drawAlpha , _colorize

3.1、點模板 _getPointTemplate,設置單點渲染模板

    點模板對應熱力圖數據點。它是一個圓點,根據可配置的模糊因子(blurFactor,默認.85),可使圓點帶有模糊效果(借助createRadialGradient)。

    主要是調用 canvas 的 createRadialGradient 方法。核心方法是canvas的createRadialGradient方法,每個點設置渲染半徑,由漸變因子 blur 確定內圓比例,內圓與外圓的圓周間進行無色的放射漸變,達到中間透明度高,邊緣透明度低的效果。這個無色的透明度漸變的圓形即為點的模板。

var _getPointTemplate = function(radius, blurFactor) {
    var tplCanvas = document.createElement('canvas');
    var tplCtx = tplCanvas.getContext('2d');
    var x = radius;
    var y = radius;
    tplCanvas.width = tplCanvas.height = radius*2;

    if (blurFactor == 1) {
      tplCtx.beginPath();
      tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
      tplCtx.fillStyle = 'rgba(0,0,0,1)';
      tplCtx.fill();
    } else {
      var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
      gradient.addColorStop(0, 'rgba(0,0,0,1)');
      gradient.addColorStop(1, 'rgba(0,0,0,0)');
      tplCtx.fillStyle = gradient;
      tplCtx.fillRect(0, 0, 2*radius, 2*radius);
    }

    return tplCanvas;
  };

用 html canvas代碼測試效果,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>_getPointTemplate</title>
  <style>
      /*canvas {border:1px solid black;}*/
  </style>
</head>
<body>
<div class="heatmap">
</div>
<script>
  window.onload = function () {
    var container = document.querySelector('.heatmap');

    var p1 = _getPointTemplate(40, 0.85);
    //document.body.appendChild(p1);
    container.appendChild(p1);
  }

  var _getPointTemplate = function(radius, blurFactor) {
    var tplCanvas = document.createElement('canvas');
    var tplCtx = tplCanvas.getContext('2d');
    var x = radius;
    var y = radius;
    tplCanvas.width = tplCanvas.height = radius*2;

    if (blurFactor == 1) {
      tplCtx.beginPath();
      tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
      tplCtx.fillStyle = 'rgba(0,0,0,1)';
      tplCtx.fill();
    } else {
      var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
      gradient.addColorStop(0, 'rgba(0,0,0,1)');
      gradient.addColorStop(1, 'rgba(0,0,0,0)');
      tplCtx.fillStyle = gradient;
      tplCtx.fillRect(0, 0, 2*radius, 2*radius);
    }
    return tplCanvas;
  };
</script>
</body>
</html>
View Code

當 radius=50, blurFactor = 0.85 ,測試效果如下:

 

 當 radius=50, blurFactor = 0.5 ,測試效果如下:

3.2、線性色譜 _getColorPalette , 構建0到256的調色板

    通過createLinearGradient你可以自主定制自己的熱力圖色譜(config.gradient)。

 主要是調用 canvas 的 createLinearGradient 方法。核心方法是canvas的createLinearGradient方法

var _getColorPalette = function(config) {
    var gradientConfig = config.gradient || config.defaultGradient;
    var paletteCanvas = document.createElement('canvas');
    var paletteCtx = paletteCanvas.getContext('2d');

    paletteCanvas.width = 256;
    paletteCanvas.height = 1;

    var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
    for (var key in gradientConfig) {
      gradient.addColorStop(key, gradientConfig[key]);
    }

    paletteCtx.fillStyle = gradient;
    paletteCtx.fillRect(0, 0, 256, 1);

    return paletteCtx.getImageData(0, 0, 256, 1).data;
  };

用 html canvas代碼測試效果,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>_getColorPalette</title>
  <style>
      /*canvas {border:1px solid black;}*/
  </style>
</head>
<body>
<div class="heatmap">
</div>
<script>
  window.onload = function () {
    var container = document.querySelector('.heatmap');

    /*var HeatmapConfig = {
    defaultRadius: 40,
    defaultRenderer: 'canvas2d',
    defaultGradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"},
    defaultMaxOpacity: 1,
    defaultMinOpacity: 0,
    defaultBlur: .85,
    defaultXField: 'x',
    defaultYField: 'y',
    defaultValueField: 'value',
    plugins: {}
    };*/
    var config = { defaultGradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"} }

    var imgData = _getColorPalette(config);
    var c=document.createElement("canvas");
    container.appendChild(c);
    var ctx=c.getContext("2d");
    var img = ctx.getImageData(0, 0, 256, 1)
    //img.data = imgData;
    for (let i = 0; i < img.data.length; i++) {
      img.data[i] = imgData[i];
    }
    ctx.putImageData(img, 0, 0);
  }

  var _getColorPalette = function(config) {
    var gradientConfig = config.gradient || config.defaultGradient;
    var paletteCanvas = document.createElement('canvas');
    var paletteCtx = paletteCanvas.getContext('2d');

    paletteCanvas.width = 256;
    paletteCanvas.height = 1;

    var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
    for (var key in gradientConfig) {
      gradient.addColorStop(key, gradientConfig[key]);
    }

    paletteCtx.fillStyle = gradient;
    paletteCtx.fillRect(0, 0, 256, 1);

    return paletteCtx.getImageData(0, 0, 256, 1).data;
  };
</script>
</body>
</html>
View Code

當 var gradientConfig = { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"};,測試效果如下:

3.3、灰度(透明度)疊加 _drawAlpha, 根據模板繪制全部點

     這個熱力圖的"靈魂"。rgb通道是無法線性疊加呈現效果的,但是透明度是近似線性的。var templateAlpha = (value-min)/(max-min);,根據數據點的比率,對應於透明度的值alpha,我們在canvas上(shadowCtx)繪制一個數據點。它們的透明度是可以疊加的,值越大,越"不透明"。

    主要是調用 canvas 的 drawImage方法。核心方法是canvas的drawImage方法,在每個點的位置按照模板進行繪制,達到重疊部分透明度疊加的效果。

_drawAlpha: function(data) {
      var min = this._min = data.min;
      var max = this._max = data.max;
      var data = data.data || [];
      var dataLen = data.length;
      // on a point basis?
      var blur = 1 - this._blur;

      while(dataLen--) {

        var point = data[dataLen];

        var x = point.x;
        var y = point.y;
        var radius = point.radius;
        // if value is bigger than max
        // use max as value
        var value = Math.min(point.value, max);
        var rectX = x - radius;
        var rectY = y - radius;
        var shadowCtx = this.shadowCtx;




        var tpl;
        if (!this._templates[radius]) {
          this._templates[radius] = tpl = _getPointTemplate(radius, blur);
        } else {
          tpl = this._templates[radius];
        }
        // value from minimum / value range
        // => [0, 1]
        var templateAlpha = (value-min)/(max-min);
        // this fixes #176: small values are not visible because globalAlpha < .01 cannot be read from imageData
        shadowCtx.globalAlpha = templateAlpha < .01 ? .01 : templateAlpha;

        shadowCtx.drawImage(tpl, rectX, rectY);

        // update renderBoundaries
        if (rectX < this._renderBoundaries[0]) {
            this._renderBoundaries[0] = rectX;
          }
          if (rectY < this._renderBoundaries[1]) {
            this._renderBoundaries[1] = rectY;
          }
          if (rectX + 2*radius > this._renderBoundaries[2]) {
            this._renderBoundaries[2] = rectX + 2*radius;
          }
          if (rectY + 2*radius > this._renderBoundaries[3]) {
            this._renderBoundaries[3] = rectY + 2*radius;
          }

      }
    },

 用 html canvas代碼測試效果,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>_drawAlpha</title>
  <style>
      /*canvas {border:1px solid black;}*/
  </style>
</head>
<body>
<div class="heatmap">
</div>
<script>
  window.onload = function () {
    var container = document.querySelector('.heatmap');

    var shadowCanvas = this.shadowCanvas = document.createElement('canvas');
    this._width = shadowCanvas.width = 900;
    this._height = shadowCanvas.height = 900;

    this.shadowCtx = shadowCanvas.getContext('2d');

    shadowCanvas.style.cssText = 'position:absolute;left:0;top:0;';

    container.style.position = 'relative';
    container.appendChild(shadowCanvas);

    var renderBoundaries = this._renderBoundaries = [10000, 10000, 0, 0];
    // this._min
    // this._max
    this._blur = 0.85;
    this._templates = {};

    var data = {
      min: 0,
      max: 10,
      // x坐標, y坐標, value值, radius圓半徑
      data: [{x: 10, y: 15, value: 5, radius: 40}, {x: 130, y: 170, value: 8, radius: 40}, {x: 200, y: 250, value: 10, radius: 40},
        {x: 300, y: 450, value: 5, radius: 40}, {x: 300, y: 450, value: 5, radius: 40}]
    };
    _drawAlpha(data);
  }

  var _getPointTemplate = function(radius, blurFactor) {
    var tplCanvas = document.createElement('canvas');
    var tplCtx = tplCanvas.getContext('2d');
    var x = radius;
    var y = radius;
    tplCanvas.width = tplCanvas.height = radius*2;

    if (blurFactor == 1) {
      tplCtx.beginPath();
      tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
      tplCtx.fillStyle = 'rgba(0,0,0,1)';
      tplCtx.fill();
    } else {
      var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
      gradient.addColorStop(0, 'rgba(0,0,0,1)');
      gradient.addColorStop(1, 'rgba(0,0,0,0)');
      tplCtx.fillStyle = gradient;
      tplCtx.fillRect(0, 0, 2*radius, 2*radius);
    }
    return tplCanvas;
  };

  var _drawAlpha = function(data) {
    var min = this._min = data.min;
    var max = this._max = data.max;
    var data = data.data || [];
    var dataLen = data.length;
    // on a point basis?
    var blur = 1 - this._blur;

    while(dataLen--) {
      var point = data[dataLen];

      var x = point.x;
      var y = point.y;
      var radius = point.radius;
      // if value is bigger than max
      // use max as value
      var value = Math.min(point.value, max);
      var rectX = x - radius;
      var rectY = y - radius;
      var shadowCtx = this.shadowCtx;

      var tpl;
      if (!this._templates[radius]) {
        this._templates[radius] = tpl = _getPointTemplate(radius, blur);
      } else {
        tpl = this._templates[radius];
      }
      // value from minimum / value range
      // => [0, 1]
      var templateAlpha = (value-min)/(max-min);
      // this fixes #176: small values are not visible because globalAlpha < .01 cannot be read from imageData
      shadowCtx.globalAlpha = templateAlpha < .01 ? .01 : templateAlpha;

      shadowCtx.drawImage(tpl, rectX, rectY);

      // update renderBoundaries
      if (rectX < this._renderBoundaries[0]) {
        this._renderBoundaries[0] = rectX;
      }
      if (rectY < this._renderBoundaries[1]) {
        this._renderBoundaries[1] = rectY;
      }
      if (rectX + 2*radius > this._renderBoundaries[2]) {
        this._renderBoundaries[2] = rectX + 2*radius;
      }
      if (rectY + 2*radius > this._renderBoundaries[3]) {
        this._renderBoundaries[3] = rectY + 2*radius;
      }

    }
  }
</script>
</body>
</html>
View Code

測試效果如下:

3.4、着色 _colorize

     最后,透明度的疊加值(this.shadowCtx.getImageData)映射到線性色譜(palette),取線性色譜中的顏色為canvas上色(putImageData)就得到最終的熱力圖了。

    主要是調用 canvas 的 putImageData方法。核心方法是canvas的putImageData方法, 對繪制的每個點進行着色,獲取繪制的區域中每個像素,根據像素的透明度去調色板中取對應的顏色進行渲染,最后達到熱力圖的效果。

_colorize: function() {
      var x = this._renderBoundaries[0];
      var y = this._renderBoundaries[1];
      var width = this._renderBoundaries[2] - x;
      var height = this._renderBoundaries[3] - y;
      var maxWidth = this._width;
      var maxHeight = this._height;
      var opacity = this._opacity;
      var maxOpacity = this._maxOpacity;
      var minOpacity = this._minOpacity;
      var useGradientOpacity = this._useGradientOpacity;

      if (x < 0) {
        x = 0;
      }
      if (y < 0) {
        y = 0;
      }
      if (x + width > maxWidth) {
        width = maxWidth - x;
      }
      if (y + height > maxHeight) {
        height = maxHeight - y;
      }

      var img = this.shadowCtx.getImageData(x, y, width, height);
      var imgData = img.data;
      var len = imgData.length;
      var palette = this._palette;


      for (var i = 3; i < len; i+= 4) {
        var alpha = imgData[i];
        var offset = alpha * 4;


        if (!offset) {
          continue;
        }

        var finalAlpha;
        if (opacity > 0) {
          finalAlpha = opacity;
        } else {
          if (alpha < maxOpacity) {
            if (alpha < minOpacity) {
              finalAlpha = minOpacity;
            } else {
              finalAlpha = alpha;
            }
          } else {
            finalAlpha = maxOpacity;
          }
        }

        imgData[i-3] = palette[offset];
        imgData[i-2] = palette[offset + 1];
        imgData[i-1] = palette[offset + 2];
        imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha;

      }

      img.data = imgData;
      this.ctx.putImageData(img, x, y);

      this._renderBoundaries = [1000, 1000, 0, 0];

    },

用 html canvas代碼測試效果,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>_colorize</title>
  <style>
      /*canvas {border:1px solid black;}*/
  </style>
</head>
<body>
<div class="heatmap">
</div>
<script>
  window.onload = function () {
    var container = document.querySelector('.heatmap');

    var shadowCanvas = this.shadowCanvas = document.createElement('canvas');
    var canvas = this.canvas = document.createElement('canvas');
    var renderBoundaries = this._renderBoundaries = [10000, 10000, 0, 0];

    canvas.className = 'heatmap-canvas';

    this._width = canvas.width = shadowCanvas.width = 900;
    this._height = canvas.height = shadowCanvas.height = 900;

    this.shadowCtx = shadowCanvas.getContext('2d');
    this.ctx = canvas.getContext('2d');

    canvas.style.cssText = shadowCanvas.style.cssText = 'position:absolute;left:0;top:0;';

    container.style.position = 'relative';
    container.appendChild(canvas);

    var config = { defaultGradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"} }
    this._palette = _getColorPalette(config);
    this._templates = {};
    var opacity = this._opacity = 0.8;
    var maxOpacity = this._maxOpacity = 1;
    var minOpacity = this._minOpacity = 0;
    var useGradientOpacity = this._useGradientOpacity = true;
    // this._min
    // this._max
    this._blur = 0.85;

    var data = {
      min: 0,
      max: 10,
      // x坐標, y坐標, value值, radius圓半徑
      data: [{x: 10, y: 15, value: 5, radius: 40}, {x: 130, y: 170, value: 8, radius: 40}, {x: 200, y: 250, value: 10, radius: 40},
        {x: 300, y: 450, value: 5, radius: 40}, {x: 300, y: 450, value: 5, radius: 40}]
    };
    _drawAlpha(data);
    _colorize();
  };

  var _getColorPalette = function(config) {
    var gradientConfig = config.gradient || config.defaultGradient;
    var paletteCanvas = document.createElement('canvas');
    var paletteCtx = paletteCanvas.getContext('2d');

    paletteCanvas.width = 256;
    paletteCanvas.height = 1;

    var gradient = paletteCtx.createLinearGradient(0, 0, 256, 1);
    for (var key in gradientConfig) {
      gradient.addColorStop(key, gradientConfig[key]);
    }

    paletteCtx.fillStyle = gradient;
    paletteCtx.fillRect(0, 0, 256, 1);

    return paletteCtx.getImageData(0, 0, 256, 1).data;
  };

  var _getPointTemplate = function(radius, blurFactor) {
    var tplCanvas = document.createElement('canvas');
    var tplCtx = tplCanvas.getContext('2d');
    var x = radius;
    var y = radius;
    tplCanvas.width = tplCanvas.height = radius*2;

    if (blurFactor == 1) {
      tplCtx.beginPath();
      tplCtx.arc(x, y, radius, 0, 2 * Math.PI, false);
      tplCtx.fillStyle = 'rgba(0,0,0,1)';
      tplCtx.fill();
    } else {
      var gradient = tplCtx.createRadialGradient(x, y, radius*blurFactor, x, y, radius);
      gradient.addColorStop(0, 'rgba(0,0,0,1)');
      gradient.addColorStop(1, 'rgba(0,0,0,0)');
      tplCtx.fillStyle = gradient;
      tplCtx.fillRect(0, 0, 2*radius, 2*radius);
    }
    return tplCanvas;
  };

  var _drawAlpha = function(data) {
    var min = this._min = data.min;
    var max = this._max = data.max;
    var data = data.data || [];
    var dataLen = data.length;
    // on a point basis?
    var blur = 1 - this._blur;

    while(dataLen--) {
      var point = data[dataLen];

      var x = point.x;
      var y = point.y;
      var radius = point.radius;
      // if value is bigger than max
      // use max as value
      var value = Math.min(point.value, max);
      var rectX = x - radius;
      var rectY = y - radius;
      var shadowCtx = this.shadowCtx;

      var tpl;
      if (!this._templates[radius]) {
        this._templates[radius] = tpl = _getPointTemplate(radius, blur);
      } else {
        tpl = this._templates[radius];
      }
      // value from minimum / value range
      // => [0, 1]
      var templateAlpha = (value-min)/(max-min);
      // this fixes #176: small values are not visible because globalAlpha < .01 cannot be read from imageData
      shadowCtx.globalAlpha = templateAlpha < .01 ? .01 : templateAlpha;

      shadowCtx.drawImage(tpl, rectX, rectY);

      // update renderBoundaries
      if (rectX < this._renderBoundaries[0]) {
        this._renderBoundaries[0] = rectX;
      }
      if (rectY < this._renderBoundaries[1]) {
        this._renderBoundaries[1] = rectY;
      }
      if (rectX + 2*radius > this._renderBoundaries[2]) {
        this._renderBoundaries[2] = rectX + 2*radius;
      }
      if (rectY + 2*radius > this._renderBoundaries[3]) {
        this._renderBoundaries[3] = rectY + 2*radius;
      }

    }
  };

  var _colorize = function() {
    var x = this._renderBoundaries[0];
    var y = this._renderBoundaries[1];
    var width = this._renderBoundaries[2] - x;
    var height = this._renderBoundaries[3] - y;
    var maxWidth = this._width;
    var maxHeight = this._height;
    var opacity = this._opacity;
    var maxOpacity = this._maxOpacity;
    var minOpacity = this._minOpacity;
    var useGradientOpacity = this._useGradientOpacity;

    if (x < 0) {
      x = 0;
    }
    if (y < 0) {
      y = 0;
    }
    if (x + width > maxWidth) {
      width = maxWidth - x;
    }
    if (y + height > maxHeight) {
      height = maxHeight - y;
    }

    var img = this.shadowCtx.getImageData(x, y, width, height);
    var imgData = img.data;
    var len = imgData.length;
    var palette = this._palette;


    for (var i = 3; i < len; i+= 4) {
      var alpha = imgData[i];
      var offset = alpha * 4;


      if (!offset) {
        continue;
      }

      var finalAlpha;
      if (opacity > 0) {
        finalAlpha = opacity;
      } else {
        if (alpha < maxOpacity) {
          if (alpha < minOpacity) {
            finalAlpha = minOpacity;
          } else {
            finalAlpha = alpha;
          }
        } else {
          finalAlpha = maxOpacity;
        }
      }

      imgData[i-3] = palette[offset];
      imgData[i-2] = palette[offset + 1];
      imgData[i-1] = palette[offset + 2];
      imgData[i] = useGradientOpacity ? palette[offset + 3] : finalAlpha;

    }

    img.data = imgData;
    this.ctx.putImageData(img, x, y);

    this._renderBoundaries = [1000, 1000, 0, 0];

  };
</script>
</body>
</html>
View Code

測試效果如下:

 

 

 

當然還有很多其他的方法,這里不一一介紹了。

四、調用 heatmap.js 生成熱力圖

首先引入 heatmap.js 文件:

官網:https://www.patrick-wied.at/static/heatmapjs/

github:https://github.com/pa7/heatmap.js

代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <!-- https://www.patrick-wied.at/static/heatmapjs/docs.html -->
  <!--  <link rel="stylesheet" type="text/css" href="style.css">-->
  <!--<script src="../../lib/heatmap.js-master/build/heatmap.min.js"></script>-->
  <script src="https://cdn.bootcdn.net/ajax/libs/heatmap.js/2.0.0/heatmap.min.js"></script>
  <style>
      div {
          width: 100%;
          height: 900px;
          /*border-style:solid;*/
          /*border-color:red;*/
          border:2px solid Orange;
      }
  </style>
</head>
<body>
  <div id="heatmap"></div>
  <script type="text/javascript">
    /*
      h337”是heatmap.js注冊的全局對象的名字。您可以使用它來創建熱圖實例
      h337.create(configObject) 返回一個heatmapInstance。
      使用 h337.create 創建熱圖實例。可以使用 configObject 自定義熱圖。
      configObject 參數是必需的。
     */
    var heatmap = h337.create({
      // 可能的配置屬性:

      // container (DOMNode) *必需*
      // A DOM node where the heatmap canvas should be appended (heatmap will adapt to the node's size)
      // 應附加熱圖畫布的 DOM 節點(熱圖將適應節點的大小)
      container: document.getElementById("heatmap"),

      // 背景色
      // backgroundColor (string) *optional*
      // A background color string in form of hexcode, color name, or rgb(a)
      // 十六進制代碼、顏色名稱或 rgb(a) 形式的背景顏色字符串
      //backgroundColor: "#f3f3f3",
      //backgroundColor: "rgb(240, 240, 240)",
      backgroundColor: "rgba(240, 240, 240, 0.2)",

      // gradient (object) *可選*
      // An object that represents the gradient (syntax: number string [0,1] : color string), check out the example
      // 表示漸變的對象(語法:數字字符串[0,1]:顏色字符串),查看示例
      gradient: { 0.25: "rgb(0,0,255)", 0.55: "rgb(0,255,0)", 0.85: "yellow", 1.0: "rgb(255,0,0)"},

      // radius (number) *可選*
      // The radius each datapoint will have (if not specified on the datapoint itself)
      // 每個數據點將具有的半徑(如果未在數據點本身上指定)
      radius: 20,

      // opacity (number) [0,1] *可選* default = .6
      // A global opacity for the whole heatmap. This overrides maxOpacity and minOpacity if set!
      // 整個熱圖的全局不透明度。如果設置,這將覆蓋 maxOpacity 和 minOpacity!
      // opacity: .6,

      // maxOpacity (number) [0,1] *可選*
      // The maximal opacity the highest value in the heatmap will have. (will be overridden if opacity set)
      // 熱圖中最高值的最大不透明度。(如果設置不透明度將被覆蓋)
      maxOpacity: 1,
      // minOpacity(number) [0,1] *可選*
      // The minimum opacity the lowest value in the heatmap will have (will be overridden if opacity set)
      // 熱圖中最低值的最小不透明度(如果設置了不透明度,將被覆蓋)
      minOpacity: 0,

      // onExtremaChange function callback  函數回調
      // Pass a callback to receive extrema change updates. Useful for DOM legends.
      // 傳遞回調以接收極值更改更新。對 DOM 圖例很有用。
      // onExtremaChange

      // blur (number) [0,1] *可選* default = 0.85
      //
      // 將應用於所有數據點的模糊因子。模糊系數越高,漸變就越平滑


      // xField (string) *可選* default = "x"
      //
      // 數據點中 x 坐標的屬性名稱
      xField: "x",

      // yField (string) *optional* default = "y"
      //
      // 數據點中 y 坐標的屬性名稱
      yField: "y",

      // valueField (string) *optional* default = "value"
      //
      // 數據點中 y 坐標的屬性名稱
      valueField: "value"
    });

    heatmap.setData({
      min: 0,
      max: 10,
      data: [{x: 10, y: 15, value: 5, radius: 40}, {x: 130, y: 170, value: 8, radius: 40}, {x: 200, y: 250, value: 10, radius: 40},
        {x: 300, y: 450, value: 5, radius: 40}, {x: 300, y: 450, value: 5, radius: 40}]
      //data: [{ x: 50, y: 75, value: 5, radius: 40}, {x: 200, y: 350, value: 3, radius: 10}]
    });
  </script>
</body>
</html>

結果如下:

 

 

參考: 

heatmap.js(熱力圖)源碼解讀

熱點圖heatMap.js V2.0 研究筆記


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM