@antv/g2plot
Version:
G2 Plot, a market of plots built with the Grammar of Graphics'
201 lines • 7.96 kB
JavaScript
import { __assign, __extends } from "tslib";
import { registerElement, Element } from '@antv/g2';
import * as _ from '@antv/util';
import * as colorUtil from '../../util/color';
var GAUSS_COEF = 0.3989422804014327;
var ZERO = 1.0 / 255.0 / 16.0;
var ORIGIN_FIELD = '_origin';
var SHADOW_CANVAS = 'shadowCanvas';
var VALUE_RANGE = 'valueRange';
var IMAGE_SHAPE = 'imageShape';
var MAPPED_DATA = 'mappedData';
var GRAY_SCALE_BLURRED_CANVAS = 'grayScaleBlurredCanvas';
var HEATMAP_SIZE = 'heatmapSize';
var LinearHeatmap = /** @class */ (function (_super) {
__extends(LinearHeatmap, _super);
function LinearHeatmap(cfg) {
return _super.call(this, __assign({ type: 'linearHeatmap', shapeType: 'point', paletteCache: {} }, cfg)) || this;
}
LinearHeatmap.prototype._prepareRange = function () {
var data = this.get(MAPPED_DATA);
var colorAttr = this.getAttr('color');
var colorField = colorAttr.scales[0].field;
var min = Infinity;
var max = -Infinity;
data.forEach(function (row) {
var value = row[ORIGIN_FIELD][colorField];
if (value > max) {
max = value;
}
if (value < min) {
min = value;
}
});
if (min === max) {
min = max - 1;
}
var range = [min, max];
this.set(VALUE_RANGE, range);
};
LinearHeatmap.prototype._prepareSize = function () {
var radius;
if (this.get('radius')) {
radius = this.get('radius');
}
else {
radius = this.getDefaultValue('size');
if (!_.isNumber(radius)) {
radius = this.getDefaultSize();
}
}
var styleOptions = this.get('styleOptions');
var blur = styleOptions && _.isObject(styleOptions.cfg) ? styleOptions.cfg.blur : null;
if (!_.isFinite(blur) || blur === null) {
blur = radius / 2;
}
this.set(HEATMAP_SIZE, {
blur: blur,
radius: radius,
});
};
LinearHeatmap.prototype.getDefaultSize = function () {
var position = this.getAttr('position');
var coord = this.get('coord');
var radius = Math.min(coord.width / (position.scales[0].ticks.length * 4), coord.height / (position.scales[1].ticks.length * 4));
return radius;
};
LinearHeatmap.prototype._colorize = function (img) {
var colorAttr = this.getAttr('color');
var pixels = img.data;
var paletteCache = this.get('paletteCache');
for (var i = 3; i < pixels.length; i += 4) {
var alpha = pixels[i]; // get gradient color from opacity value
if (alpha) {
var palette = void 0;
if (paletteCache[alpha]) {
palette = paletteCache[alpha];
}
else {
palette = colorUtil.rgb2arr(colorAttr.gradient(alpha / 256));
paletteCache[alpha] = palette;
}
// const palette = colorUtil.rgb2arr(colorAttr.gradient(alpha / 256));
pixels[i - 3] = palette[0];
pixels[i - 2] = palette[1];
pixels[i - 1] = palette[2];
pixels[i] = alpha;
}
}
};
LinearHeatmap.prototype._prepareGreyScaleBlurredCircle = function (r) {
var circleCanvas = this.get(GRAY_SCALE_BLURRED_CANVAS);
if (!circleCanvas) {
circleCanvas = document.createElement('canvas');
this.set(GRAY_SCALE_BLURRED_CANVAS, circleCanvas);
}
var intensity = this.get('intensity') ? this.get('intensity') : 2;
var circleRadius = (Math.sqrt(-2.0 * Math.log(ZERO / r / intensity / GAUSS_COEF)) / 3.0) * r;
var blur = circleRadius - r;
var r2 = circleRadius + blur;
var ctx = circleCanvas.getContext('2d');
circleCanvas.width = circleCanvas.height = r2 * 2;
ctx.clearRect(0, 0, circleCanvas.width, circleCanvas.height);
ctx.shadowOffsetX = ctx.shadowOffsetY = r2 * 2;
ctx.shadowBlur = blur;
ctx.shadowColor = 'black';
ctx.beginPath();
ctx.arc(-r2, -r2, r, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
};
LinearHeatmap.prototype._drawGrayScaleBlurredCircle = function (x, y, r, alpha, ctx) {
var circleCanvas = this.get(GRAY_SCALE_BLURRED_CANVAS);
ctx.globalAlpha = alpha;
ctx.drawImage(circleCanvas, x - r, y - r);
};
LinearHeatmap.prototype._getShadowCanvasCtx = function () {
var canvas = this.get(SHADOW_CANVAS);
if (!canvas) {
canvas = document.createElement('canvas');
this.set(SHADOW_CANVAS, canvas);
}
var viewRange = this.get('view').get('panelRange');
canvas.width = viewRange.width;
canvas.height = viewRange.height;
var context = canvas.getContext('2d');
context.globalCompositeOperation = 'lighter';
return context;
};
LinearHeatmap.prototype._clearShadowCanvasCtx = function () {
var ctx = this._getShadowCanvasCtx();
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
};
LinearHeatmap.prototype._getImageShape = function () {
var imageShape = this.get(IMAGE_SHAPE);
if (imageShape) {
return imageShape;
}
var container = this.get('container');
imageShape = container.addShape('Image', {});
this.set(IMAGE_SHAPE, imageShape);
return imageShape;
};
LinearHeatmap.prototype.clear = function () {
this._clearShadowCanvasCtx();
_super.prototype.clear.call(this);
};
LinearHeatmap.prototype.drawWithRange = function (range) {
// canvas size
var _a = this.get('coord'), start = _a.start, end = _a.end, width = _a.width, height = _a.height;
// value, range, etc
// const valueField = this.getAttr('color').field;
var valueField = this.getAttr('color').scales[0].field;
var size = this.get(HEATMAP_SIZE);
// prepare shadow canvas context
this._clearShadowCanvasCtx();
var ctx = this._getShadowCanvasCtx();
// filter data
var data = this.get(MAPPED_DATA);
if (range) {
data = data.filter(function (row) {
return row[ORIGIN_FIELD][valueField] <= range[1] && row[ORIGIN_FIELD][valueField] >= range[0];
});
}
// step1. draw points with shadow
var scale = this.get('scales')[valueField];
for (var i = 0; i < data.length; i++) {
var obj = data[i];
var cfg = this.getDrawCfg(obj);
var alpha = scale.scale(obj[ORIGIN_FIELD][valueField]);
// @ts-ignore
this._drawGrayScaleBlurredCircle(cfg.x - start.x, cfg.y - end.y, size.radius + size.blur, alpha, ctx);
}
// step2. convert pixels
var colored = ctx.getImageData(0, 0, width, height);
this._clearShadowCanvasCtx();
this._colorize(colored);
ctx.putImageData(colored, 0, 0);
var image = new Image();
image.src = ctx.canvas.toDataURL('image/png');
var imageShape = this._getImageShape();
imageShape.attr({
x: start.x,
y: end.y,
width: width,
height: height,
img: image,
});
};
LinearHeatmap.prototype.draw = function (data) {
this.set(MAPPED_DATA, data);
this._prepareRange();
this._prepareSize();
var size = this.get(HEATMAP_SIZE);
this._prepareGreyScaleBlurredCircle(size.radius);
var range = this.get(VALUE_RANGE);
this.drawWithRange(range);
};
return LinearHeatmap;
}(Element));
registerElement('linearHeatmap', LinearHeatmap);
//# sourceMappingURL=linear.js.map