UNPKG

zrender

Version:

A lightweight graphic library providing 2d draw for Apache ECharts

322 lines (321 loc) 11.1 kB
import * as matrix from './matrix.js'; import Point from './Point.js'; var mathMin = Math.min; var mathMax = Math.max; var mathAbs = Math.abs; var XY = ['x', 'y']; var WH = ['width', 'height']; var lt = new Point(); var rb = new Point(); var lb = new Point(); var rt = new Point(); var _intersectCtx = createIntersectContext(); var _minTv = _intersectCtx.minTv; var _maxTv = _intersectCtx.maxTv; var _lenMinMax = [0, 0]; var BoundingRect = (function () { function BoundingRect(x, y, width, height) { BoundingRect.set(this, x, y, width, height); } BoundingRect.set = function (target, x, y, width, height) { if (width < 0) { x = x + width; width = -width; } if (height < 0) { y = y + height; height = -height; } target.x = x; target.y = y; target.width = width; target.height = height; return target; }; BoundingRect.prototype.union = function (other) { var x = mathMin(other.x, this.x); var y = mathMin(other.y, this.y); if (isFinite(this.x) && isFinite(this.width)) { this.width = mathMax(other.x + other.width, this.x + this.width) - x; } else { this.width = other.width; } if (isFinite(this.y) && isFinite(this.height)) { this.height = mathMax(other.y + other.height, this.y + this.height) - y; } else { this.height = other.height; } this.x = x; this.y = y; }; BoundingRect.prototype.applyTransform = function (m) { BoundingRect.applyTransform(this, this, m); }; BoundingRect.prototype.calculateTransform = function (b) { var a = this; var sx = b.width / a.width; var sy = b.height / a.height; var m = matrix.create(); matrix.translate(m, m, [-a.x, -a.y]); matrix.scale(m, m, [sx, sy]); matrix.translate(m, m, [b.x, b.y]); return m; }; BoundingRect.prototype.intersect = function (b, mtv, opt) { return BoundingRect.intersect(this, b, mtv, opt); }; BoundingRect.intersect = function (a, b, mtv, opt) { if (mtv) { Point.set(mtv, 0, 0); } var outIntersectRect = opt && opt.outIntersectRect || null; var clamp = opt && opt.clamp; if (outIntersectRect) { outIntersectRect.x = outIntersectRect.y = outIntersectRect.width = outIntersectRect.height = NaN; } if (!a || !b) { return false; } if (!(a instanceof BoundingRect)) { a = BoundingRect.set(_tmpIntersectA, a.x, a.y, a.width, a.height); } if (!(b instanceof BoundingRect)) { b = BoundingRect.set(_tmpIntersectB, b.x, b.y, b.width, b.height); } var useMTV = !!mtv; _intersectCtx.reset(opt, useMTV); var touchThreshold = _intersectCtx.touchThreshold; var ax0 = a.x + touchThreshold; var ax1 = a.x + a.width - touchThreshold; var ay0 = a.y + touchThreshold; var ay1 = a.y + a.height - touchThreshold; var bx0 = b.x + touchThreshold; var bx1 = b.x + b.width - touchThreshold; var by0 = b.y + touchThreshold; var by1 = b.y + b.height - touchThreshold; if (ax0 > ax1 || ay0 > ay1 || bx0 > bx1 || by0 > by1) { return false; } var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0); if (useMTV || outIntersectRect) { _lenMinMax[0] = Infinity; _lenMinMax[1] = 0; intersectOneDim(ax0, ax1, bx0, bx1, 0, useMTV, outIntersectRect, clamp); intersectOneDim(ay0, ay1, by0, by1, 1, useMTV, outIntersectRect, clamp); if (useMTV) { Point.copy(mtv, overlap ? (_intersectCtx.useDir ? _intersectCtx.dirMinTv : _minTv) : _maxTv); } } return overlap; }; BoundingRect.contain = function (rect, x, y) { return x >= rect.x && x <= (rect.x + rect.width) && y >= rect.y && y <= (rect.y + rect.height); }; BoundingRect.prototype.contain = function (x, y) { return BoundingRect.contain(this, x, y); }; BoundingRect.prototype.clone = function () { return new BoundingRect(this.x, this.y, this.width, this.height); }; BoundingRect.prototype.copy = function (other) { BoundingRect.copy(this, other); }; BoundingRect.prototype.plain = function () { return { x: this.x, y: this.y, width: this.width, height: this.height }; }; BoundingRect.prototype.isFinite = function () { return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height); }; BoundingRect.prototype.isZero = function () { return this.width === 0 || this.height === 0; }; BoundingRect.create = function (rect) { return new BoundingRect(rect.x, rect.y, rect.width, rect.height); }; BoundingRect.copy = function (target, source) { target.x = source.x; target.y = source.y; target.width = source.width; target.height = source.height; return target; }; BoundingRect.applyTransform = function (target, source, m) { if (!m) { if (target !== source) { BoundingRect.copy(target, source); } return; } if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) { var sx = m[0]; var sy = m[3]; var tx = m[4]; var ty = m[5]; target.x = source.x * sx + tx; target.y = source.y * sy + ty; target.width = source.width * sx; target.height = source.height * sy; if (target.width < 0) { target.x += target.width; target.width = -target.width; } if (target.height < 0) { target.y += target.height; target.height = -target.height; } return; } lt.x = lb.x = source.x; lt.y = rt.y = source.y; rb.x = rt.x = source.x + source.width; rb.y = lb.y = source.y + source.height; lt.transform(m); rt.transform(m); rb.transform(m); lb.transform(m); target.x = mathMin(lt.x, rb.x, lb.x, rt.x); target.y = mathMin(lt.y, rb.y, lb.y, rt.y); var maxX = mathMax(lt.x, rb.x, lb.x, rt.x); var maxY = mathMax(lt.y, rb.y, lb.y, rt.y); target.width = maxX - target.x; target.height = maxY - target.y; }; return BoundingRect; }()); var _tmpIntersectA = new BoundingRect(0, 0, 0, 0); var _tmpIntersectB = new BoundingRect(0, 0, 0, 0); function intersectOneDim(a0, a1, b0, b1, updateDimIdx, useMTV, outIntersectRect, clamp) { var d0 = mathAbs(a1 - b0); var d1 = mathAbs(b1 - a0); var d01min = mathMin(d0, d1); var updateDim = XY[updateDimIdx]; var zeroDim = XY[1 - updateDimIdx]; var wh = WH[updateDimIdx]; if (a1 < b0 || b1 < a0) { if (d0 < d1) { if (useMTV) { _maxTv[updateDim] = -d0; } if (clamp) { outIntersectRect[updateDim] = a1; outIntersectRect[wh] = 0; } } else { if (useMTV) { _maxTv[updateDim] = d1; } if (clamp) { outIntersectRect[updateDim] = a0; outIntersectRect[wh] = 0; } } } else { if (outIntersectRect) { outIntersectRect[updateDim] = mathMax(a0, b0); outIntersectRect[wh] = mathMin(a1, b1) - outIntersectRect[updateDim]; } if (useMTV) { if (d01min < _lenMinMax[0] || _intersectCtx.useDir) { _lenMinMax[0] = mathMin(d01min, _lenMinMax[0]); if (d0 < d1 || !_intersectCtx.bidirectional) { _minTv[updateDim] = d0; _minTv[zeroDim] = 0; if (_intersectCtx.useDir) { _intersectCtx.calcDirMTV(); } } if (d0 >= d1 || !_intersectCtx.bidirectional) { _minTv[updateDim] = -d1; _minTv[zeroDim] = 0; if (_intersectCtx.useDir) { _intersectCtx.calcDirMTV(); } } } } } } export function createIntersectContext() { var _direction = 0; var _dirCheckVec = new Point(); var _dirTmp = new Point(); var _ctx = { minTv: new Point(), maxTv: new Point(), useDir: false, dirMinTv: new Point(), touchThreshold: 0, bidirectional: true, negativeSize: false, reset: function (opt, useMTV) { _ctx.touchThreshold = 0; if (opt && opt.touchThreshold != null) { _ctx.touchThreshold = mathMax(0, opt.touchThreshold); } _ctx.negativeSize = false; if (!useMTV) { return; } _ctx.minTv.set(Infinity, Infinity); _ctx.maxTv.set(0, 0); _ctx.useDir = false; if (opt && opt.direction != null) { _ctx.useDir = true; _ctx.dirMinTv.copy(_ctx.minTv); _dirTmp.copy(_ctx.minTv); _direction = opt.direction; _ctx.bidirectional = opt.bidirectional == null || !!opt.bidirectional; if (!_ctx.bidirectional) { _dirCheckVec.set(Math.cos(_direction), Math.sin(_direction)); } } }, calcDirMTV: function () { var minTv = _ctx.minTv; var dirMinTv = _ctx.dirMinTv; var squareMag = minTv.y * minTv.y + minTv.x * minTv.x; var dirSin = Math.sin(_direction); var dirCos = Math.cos(_direction); var dotProd = dirSin * minTv.y + dirCos * minTv.x; if (nearZero(dotProd)) { if (nearZero(minTv.x) && nearZero(minTv.y)) { dirMinTv.set(0, 0); } return; } _dirTmp.x = squareMag * dirCos / dotProd; _dirTmp.y = squareMag * dirSin / dotProd; if (nearZero(_dirTmp.x) && nearZero(_dirTmp.y)) { dirMinTv.set(0, 0); return; } if ((_ctx.bidirectional || _dirCheckVec.dot(_dirTmp) > 0) && _dirTmp.len() < dirMinTv.len()) { dirMinTv.copy(_dirTmp); } } }; function nearZero(val) { return mathAbs(val) < 1e-10; } return _ctx; } export default BoundingRect;