123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289 |
- /**
- * @module echarts/core/BoundingRect
- */
- import * as matrix from './matrix';
- import Point, { PointLike } from './Point';
- const mathMin = Math.min;
- const mathMax = Math.max;
- const lt = new Point();
- const rb = new Point();
- const lb = new Point();
- const rt = new Point();
- const minTv = new Point();
- const maxTv = new Point();
- class BoundingRect {
- x: number
- y: number
- width: number
- height: number
- constructor(x: number, y: number, width: number, height: number) {
- if (width < 0) {
- x = x + width;
- width = -width;
- }
- if (height < 0) {
- y = y + height;
- height = -height;
- }
- this.x = x;
- this.y = y;
- this.width = width;
- this.height = height;
- }
- union(other: BoundingRect) {
- const x = mathMin(other.x, this.x);
- const y = mathMin(other.y, this.y);
- // If x is -Infinity and width is Infinity (like in the case of
- // IncrementalDisplayble), x + width would be NaN
- 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;
- }
- applyTransform(m: matrix.MatrixArray) {
- BoundingRect.applyTransform(this, this, m);
- }
- calculateTransform(b: RectLike): matrix.MatrixArray {
- const a = this;
- const sx = b.width / a.width;
- const sy = b.height / a.height;
- const 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;
- }
- intersect(b: RectLike, mtv?: PointLike): boolean {
- if (!b) {
- return false;
- }
- if (!(b instanceof BoundingRect)) {
- // Normalize negative width/height.
- b = BoundingRect.create(b);
- }
- const a = this;
- const ax0 = a.x;
- const ax1 = a.x + a.width;
- const ay0 = a.y;
- const ay1 = a.y + a.height;
- const bx0 = b.x;
- const bx1 = b.x + b.width;
- const by0 = b.y;
- const by1 = b.y + b.height;
- let overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
- if (mtv) {
- let dMin = Infinity;
- let dMax = 0;
- const d0 = Math.abs(ax1 - bx0);
- const d1 = Math.abs(bx1 - ax0);
- const d2 = Math.abs(ay1 - by0);
- const d3 = Math.abs(by1 - ay0);
- const dx = Math.min(d0, d1);
- const dy = Math.min(d2, d3);
- // On x axis
- if (ax1 < bx0 || bx1 < ax0) {
- if (dx > dMax) {
- dMax = dx;
- if (d0 < d1) {
- Point.set(maxTv, -d0, 0); // b is on the right
- }
- else {
- Point.set(maxTv, d1, 0); // b is on the left
- }
- }
- }
- else {
- if (dx < dMin) {
- dMin = dx;
- if (d0 < d1) {
- Point.set(minTv, d0, 0); // b is on the right
- }
- else {
- Point.set(minTv, -d1, 0); // b is on the left
- }
- }
- }
- // On y axis
- if (ay1 < by0 || by1 < ay0) {
- if (dy > dMax) {
- dMax = dy;
- if (d2 < d3) {
- Point.set(maxTv, 0, -d2); // b is on the bottom(larger y)
- }
- else {
- Point.set(maxTv, 0, d3); // b is on the top(smaller y)
- }
- }
- }
- else {
- if (dx < dMin) {
- dMin = dx;
- if (d2 < d3) {
- Point.set(minTv, 0, d2); // b is on the bottom
- }
- else {
- Point.set(minTv, 0, -d3); // b is on the top
- }
- }
- }
- }
- if (mtv) {
- Point.copy(mtv, overlap ? minTv : maxTv);
- }
- return overlap;
- }
- contain(x: number, y: number): boolean {
- const rect = this;
- return x >= rect.x
- && x <= (rect.x + rect.width)
- && y >= rect.y
- && y <= (rect.y + rect.height);
- }
- clone() {
- return new BoundingRect(this.x, this.y, this.width, this.height);
- }
- /**
- * Copy from another rect
- */
- copy(other: RectLike) {
- BoundingRect.copy(this, other);
- }
- plain(): RectLike {
- return {
- x: this.x,
- y: this.y,
- width: this.width,
- height: this.height
- };
- }
- /**
- * If not having NaN or Infinity with attributes
- */
- isFinite(): boolean {
- return isFinite(this.x)
- && isFinite(this.y)
- && isFinite(this.width)
- && isFinite(this.height);
- }
- isZero(): boolean {
- return this.width === 0 || this.height === 0;
- }
- static create(rect: RectLike): BoundingRect {
- return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
- }
- static copy(target: RectLike, source: RectLike) {
- target.x = source.x;
- target.y = source.y;
- target.width = source.width;
- target.height = source.height;
- }
- static applyTransform(target: RectLike, source: RectLike, m: matrix.MatrixArray) {
- // In case usage like this
- // el.getBoundingRect().applyTransform(el.transform)
- // And element has no transform
- if (!m) {
- if (target !== source) {
- BoundingRect.copy(target, source);
- }
- return;
- }
- // Fast path when there is no rotation in matrix.
- if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) {
- const sx = m[0];
- const sy = m[3];
- const tx = m[4];
- const 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;
- }
- // source and target can be same instance.
- 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);
- const maxX = mathMax(lt.x, rb.x, lb.x, rt.x);
- const maxY = mathMax(lt.y, rb.y, lb.y, rt.y);
- target.width = maxX - target.x;
- target.height = maxY - target.y;
- }
- }
- export type RectLike = {
- x: number
- y: number
- width: number
- height: number
- }
- export default BoundingRect;
|