spritejs/spritejs

View on GitHub
src/node/block.js

Summary

Maintainability
C
1 day
Test Coverage
C
70%
import {mat2d} from 'gl-matrix';
import {Figure2D, Mesh2D} from '@mesh.js/core';
import Node from './node';
import Attr from '../attribute/block';
import {setFillColor, setStrokeColor} from '../utils/color';
import {createRadiusBox} from '../utils/border_radius';
import ownerDocument from '../document';
import getBoundingBox from '../utils/bounding_box';

const _mesh = Symbol('mesh');

export default class Block extends Node {
  static Attr = Attr;

  constructor(attrs = {}) {
    super(attrs);
  }

  get borderSize() {
    const {paddingTop, paddingRight, paddingBottom, paddingLeft, borderWidth} = this.attributes;
    const [width, height] = this.contentSize;
    return [paddingLeft + width + paddingRight + borderWidth,
      paddingTop + height + paddingBottom + borderWidth];
  }

  // content + padding
  get clientSize() {
    const {paddingTop, paddingRight, paddingBottom, paddingLeft} = this.attributes;
    const [width, height] = this.contentSize;
    return [paddingLeft + width + paddingRight,
      paddingTop + height + paddingBottom];
  }

  get contentSize() {
    let {width, height, boxSizing, paddingTop, paddingRight, paddingBottom, paddingLeft} = this.attributes;
    width = width || 0;
    height = height || 0;
    if(boxSizing === 'border-box') {
      const bw = 2 * this.attributes.borderWidth;
      width -= bw + paddingRight + paddingLeft;
      height -= bw + paddingTop + paddingBottom;
      width = Math.max(0, width);
      height = Math.max(0, height);
    }
    return [width, height];
  }

  get hasBorder() {
    const borderWidth = this.attributes.borderWidth;
    return borderWidth > 0;
  }

  /* override */
  get isVisible() {
    const [width, height] = this.borderSize;
    return width > 0 && height > 0;
  }

  get mesh() {
    if(this.attributes.display === 'none') return null;
    const box = this.clientBox;
    if(box) {
      let mesh = this[_mesh];
      if(!mesh) {
        mesh = new Mesh2D(box);
        mesh.box = box;
        const fillColor = this.attributes.bgcolor;
        setFillColor(mesh, {color: fillColor});
        if(this.hasBorder) {
          const {borderColor, borderWidth, borderDash, borderDashOffset} = this.attributes;
          setStrokeColor(mesh,
            {color: borderColor, lineWidth: borderWidth, lineDash: borderDash, lineDashOffset: borderDashOffset});
        }
        // mesh.setOpacity(this.attributes.opacity);
        this[_mesh] = mesh;
        const clipPath = this.attributes.clipPath;
        if(clipPath) {
          this[_mesh].setClipPath(clipPath);
        }
      } else if(mesh.box !== box) {
        mesh.contours = box.contours;
        mesh.box = box;
      }
      const opacity = this.opacity;
      if(mesh.getOpacity() !== opacity) {
        mesh.setOpacity(opacity);
      }
      mesh.setTransform(...this.renderMatrix);
      return mesh;
    }
    return null;
  }

  // content + padding + border
  get offsetSize() {
    const {paddingTop, paddingRight, paddingBottom, paddingLeft, borderWidth} = this.attributes;
    const [width, height] = this.contentSize;
    const bw2 = 2 * borderWidth;
    return [paddingLeft + width + paddingRight + bw2,
      paddingTop + height + paddingBottom + bw2];
  }

  get originalClientRect() {
    if(this.mesh) {
      const boundingBox = this.mesh.boundingBox;
      return [boundingBox[0][0], boundingBox[0][1], boundingBox[1][0] - boundingBox[0][0], boundingBox[1][1] - boundingBox[0][1]];
    }
    return [0, 0, 0, 0];
  }

  get originalContentRect() {
    const [left, top, width, height] = this.originalClientRect;
    const padding = this.attributes.padding;
    return [left + padding[0], top + padding[1], width - padding[0] - padding[2], height - padding[1] - padding[3]];
  }

  getBoundingClientRect() {
    let m = this.renderMatrix;
    if(this.layer && this.layer.layerTransformInvert) {
      m = mat2d(this.layer.transformMatrix) * mat2d(m);
    }
    let boundingBox = null;
    if(this.mesh) {
      boundingBox = [...this.mesh.boundingBox];
      const borderWidth = this.attributes.borderWidth;
      if(borderWidth) {
        boundingBox[0] = [boundingBox[0][0] - borderWidth, boundingBox[0][1] - borderWidth];
        boundingBox[1] = [boundingBox[1][0] + borderWidth, boundingBox[1][1] + borderWidth];
      }
    }
    return getBoundingBox(boundingBox, m);
  }

  // transformPoint(x, y) {
  //   const m = mat2d.invert(this.renderMatrix);
  //   const newX = x * m[0] + y * m[2] + m[4];
  //   const newY = x * m[1] + y * m[3] + m[5];
  //   return [newX, newY];
  // }

  /* override */
  onPropertyChange(key, newValue, oldValue) { // eslint-disable-line complexity
    super.onPropertyChange(key, newValue, oldValue);
    if(key === 'anchorX' || key === 'anchorY' || key === 'boxSizing' || key === 'width' || key === 'height' || key === 'borderWidth'
      || key === 'paddingLeft' || key === 'paddingRight' || key === 'paddingTop' || key === 'paddingBottom'
      || /^border(TopLeft|TopRight|BottomRight|BottomLeft)Radius$/.test(key)) {
      this.updateContours();
    }
    // if(key === 'opacity') {
    //   if(this[_mesh]) this[_mesh].setOpacity(this.opacity);
    // }
    // if(key === 'anchorX' || key === 'anchorY' || key === 'boxSizing') {
    //   if(this[_mesh]) {
    //     const bgcolor = this.attributes.bgcolor;
    //     if(bgcolor && bgcolor.vector) {
    //       setFillColor(this[_mesh], {color: bgcolor});
    //     }
    //     const borderColor = this.attributes.borderColor;
    //     if(borderColor && borderColor.vector) {
    //       const {borderWidth, borderDash, borderDashOffset} = this.attributes;
    //       setStrokeColor(this[_mesh],
    //         {color: borderColor, lineWidth: borderWidth, lineDash: borderDash, lineDashOffset: borderDashOffset});
    //     }
    //   }
    // }
    if(this[_mesh] && key === 'clipPath') {
      this[_mesh].setClipPath(newValue);
    }
    if(this[_mesh] && key === 'bgcolor') {
      setFillColor(this[_mesh], {color: newValue});
    }
    if(this[_mesh]
      && (key === 'borderColor'
      || key === 'borderWidth'
      || key === 'borderDash'
      || key === 'borderDashOffset')) {
      const {borderColor, borderWidth, borderDash, borderDashOffset} = this.attributes;
      setStrokeColor(this[_mesh],
        {color: borderColor, lineWidth: borderWidth, lineDash: borderWidth ? borderDash : 0, lineDashOffset: borderDashOffset});
    }
  }

  /* override */
  updateContours() {
    const {anchorX, anchorY, borderWidth, borderRadius} = this.attributes;
    const [width, height] = this.borderSize;
    const offsetSize = this.offsetSize;

    const bw = 0.5 * borderWidth;

    const left = -anchorX * offsetSize[0] + bw;
    const top = -anchorY * offsetSize[1] + bw;

    this.clientBox = new Figure2D();
    createRadiusBox(this.clientBox, [left, top, width, height], borderRadius);
  }
}

ownerDocument.registerNode(Block, 'block');