All files / lib/item Group.ts

97.56% Statements 80/82
95.65% Branches 22/23
100% Functions 8/8
97.56% Lines 80/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222                              1x 1x 1x 1x                     1x 1x 1x 1x 1x 1x 1x 1x                                                                                                                                 1x   834x 834x 834x 834x   1x 3868x 3868x   3796x 3796x 3868x   1x   1064x     1064x 457x 457x 457x 920x 7x 7x 7x 920x 457x 457x 1064x 1064x                                                                     1x 8x 8x   1x 6x 6x 6x   1x 440x 440x 9x 431x 440x   1x 255x 255x 255x 254x 254x 254x 254x 254x   254x 254x   255x   1x 361x 361x 361x 361x         361x 2x 2x 361x 361x 716x 716x 716x 361x 1x 1x   1x  
/*
 * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
 * http://paperjs.org/
 *
 * Copyright (c) 2011 - 2020, Jürg Lehni & Jonathan Puckey
 * http://juerglehni.com/ & https://puckey.studio/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * All rights reserved.
 */
 
// TODO: remove eslint-disable comment and deal with errors over time
/* eslint-disable */
 
import { ref } from '~/globals';
import { Base } from '~/straps';
import { ChangeFlag } from './ChangeFlag';
import { Item } from './Item';
 
/**
 * @name Group
 *
 * @class A Group is a collection of items. When you transform a Group, its
 * children are treated as a single unit without changing their relative
 * positions.
 *
 * @extends Item
 */
export const Group = Item.extend(
  /** @lends Group# */ {
    _class: 'Group',
    _selectBounds: false,
    _selectChildren: true,
    _serializeFields: {
      children: [],
    },
 
    // DOCS: document new Group(item, item...);
    /**
     * Creates a new Group item and places it at the top of the active layer.
     *
     * @name Group#initialize
     * @param {Item[]} [children] An array of children that will be added to the
     * newly created group
     *
     * @example {@paperscript}
     * // Create a group containing two paths:
     * var path = new Path([100, 100], [100, 200]);
     * var path2 = new Path([50, 150], [150, 150]);
     *
     * // Create a group from the two paths:
     * var group = new Group([path, path2]);
     *
     * // Set the stroke color of all items in the group:
     * group.strokeColor = 'black';
     *
     * // Move the group to the center of the view:
     * group.position = view.center;
     *
     * @example {@paperscript height=320}
     * // Click in the view to add a path to the group, which in turn is rotated
     * // every frame:
     * var group = new Group();
     *
     * function onMouseDown(event) {
     *     // Create a new circle shaped path at the position
     *     // of the mouse:
     *     var path = new Path.Circle(event.point, 5);
     *     path.fillColor = 'black';
     *
     *     // Add the path to the group's children list:
     *     group.addChild(path);
     * }
     *
     * function onFrame(event) {
     *     // Rotate the group by 1 degree from
     *     // the centerpoint of the view:
     *     group.rotate(1, view.center);
     * }
     */
    /**
     * Creates a new Group item and places it at the top of the active layer.
     *
     * @name Group#initialize
     * @param {Object} object an object containing the properties to be set on
     *     the group
     *
     * @example {@paperscript}
     * var path = new Path([100, 100], [100, 200]);
     * var path2 = new Path([50, 150], [150, 150]);
     *
     * // Create a group from the two paths:
     * var group = new Group({
     *     children: [path, path2],
     *     // Set the stroke color of all items in the group:
     *     strokeColor: 'black',
     *     // Move the group to the center of the view:
     *     position: view.center
     * });
     */
    initialize: function Group(arg) {
      // Allow Group to have children and named children
      this._children = [];
      this._namedChildren = {};
      if (!this._initialize(arg)) this.addChildren(Array.isArray(arg) ? arg : arguments);
    },
 
    _changed: function _changed(flags) {
      (_changed as any).base.call(this, flags);
      if (flags & /*#=*/ (ChangeFlag.CHILDREN | ChangeFlag.CLIPPING)) {
        // Clear cached clip item whenever hierarchy changes
        this._clipItem = undefined;
      }
    },
 
    _getClipItem: function () {
      // NOTE: _clipItem is the child that has _clipMask set to true.
      var clipItem = this._clipItem;
      // Distinguish null (no clipItem set) and undefined (clipItem was not
      // looked for yet).
      if (clipItem === undefined) {
        clipItem = null;
        var children = this._children;
        for (var i = 0, l = children.length; i < l; i++) {
          if (children[i]._clipMask) {
            clipItem = children[i];
            break;
          }
        }
        this._clipItem = clipItem;
      }
      return clipItem;
    },
 
    /**
     * Specifies whether the group item is to be clipped. When setting to
     * `true`, the first child in the group is automatically defined as the
     * clipping mask.
     *
     * @bean
     * @type Boolean
     *
     * @example {@paperscript}
     * var star = new Path.Star({
     *     center: view.center,
     *     points: 6,
     *     radius1: 20,
     *     radius2: 40,
     *     fillColor: 'red'
     * });
     *
     * var circle = new Path.Circle({
     *     center: view.center,
     *     radius: 25,
     *     strokeColor: 'black'
     * });
     *
     * // Create a group of the two items and clip it:
     * var group = new Group(circle, star);
     * group.clipped = true;
     *
     * // Lets animate the circle:
     * function onFrame(event) {
     *     var offset = Math.sin(event.count / 30) * 30;
     *     circle.position.x = view.center.x + offset;
     * }
     */
    isClipped: function () {
      return !!this._getClipItem();
    },
 
    setClipped: function (clipped) {
      var child = this.getFirstChild();
      if (child) child.setClipMask(clipped);
    },
 
    _getBounds: function _getBounds(matrix, options) {
      var clipItem = this._getClipItem();
      return clipItem
        ? clipItem._getCachedBounds(clipItem._matrix.prepended(matrix), Base.set({}, options, { stroke: false }))
        : (_getBounds as any).base.call(this, matrix, options);
    },
 
    _hitTestChildren: function _hitTestChildren(point, options, viewMatrix) {
      var clipItem = this._getClipItem();
      return (
        (!clipItem || clipItem.contains(point)) &&
        (_hitTestChildren as any).base.call(
          this,
          point,
          options,
          viewMatrix,
          // Pass clipItem for hidden _exclude parameter
          clipItem
        )
      );
    },
 
    _draw: function (ctx, param) {
      var clip = param.clip,
        clipItem = !clip && this._getClipItem();
      param = param.extend({ clipItem: clipItem, clip: false });
      if (clip) {
        // If told to clip with a group, we start our own path and draw each
        // child just like in a compound-path.
        ctx.beginPath();
        param.dontStart = param.dontFinish = true;
      } else if (clipItem) {
        clipItem.draw(ctx, param.extend({ clip: true }));
      }
      var children = this._children;
      for (var i = 0, l = children.length; i < l; i++) {
        var item = children[i];
        if (item !== clipItem) item.draw(ctx, param);
      }
    },
  }
);
 
ref.Group = Group;