{"size": 8335, "ext": "js", "max_stars_repo_path": "src/Layer.js", "max_stars_repo_name": "crowdflux/konva", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "src/Layer.js", "max_issues_repo_name": "crowdflux/konva", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "src/Layer.js", "max_forks_repo_name": "crowdflux/konva", "max_forks_repo_forks_event_min_datetime": "2021-12-11T15:30:16.000Z", "max_forks_repo_forks_event_max_datetime": "2021-12-11T15:30:16.000Z"}
{"max_stars_count": null, "max_issues_count": null, "max_forks_count": 1, "avg_line_length": 30.4197080292, "max_line_length": 95, "alphanum_fraction": 0.5551289742}
(function() {
  'use strict';
  // constants
  var HASH = '#',
    BEFORE_DRAW = 'beforeDraw',
    DRAW = 'draw',
    /*
         * 2 - 3 - 4
         * |       |
         * 1 - 0   5
         *         |
         * 8 - 7 - 6
         */
    INTERSECTION_OFFSETS = [
      { x: 0, y: 0 }, // 0
      { x: -1, y: 0 }, // 1
      { x: -1, y: -1 }, // 2
      { x: 0, y: -1 }, // 3
      { x: 1, y: -1 }, // 4
      { x: 1, y: 0 }, // 5
      { x: 1, y: 1 }, // 6
      { x: 0, y: 1 }, // 7
      { x: -1, y: 1 } // 8
    ],
    INTERSECTION_OFFSETS_LEN = INTERSECTION_OFFSETS.length;

  /**
     * Layer constructor.  Layers are tied to their own canvas element and are used
     * to contain groups or shapes.
     * @constructor
     * @memberof Konva
     * @augments Konva.BaseLayer
     * @param {Object} config
     * @param {Boolean} [config.clearBeforeDraw] set this property to false if you don't want
     * to clear the canvas before each layer draw.  The default value is true.
     * @@nodeParams
     * @@containerParams
     * @example
     * var layer = new Konva.Layer();
     */
  Konva.Layer = function(config) {
    this.____init(config);
  };

  Konva.Util.addMethods(Konva.Layer, {
    ____init: function(config) {
      this.nodeType = 'Layer';
      this.canvas = new Konva.SceneCanvas();
      this.hitCanvas = new Konva.HitCanvas({
        pixelRatio: 1
      });
      // call super constructor
      Konva.BaseLayer.call(this, config);
    },
    _setCanvasSize: function(width, height) {
      this.canvas.setSize(width, height);
      this.hitCanvas.setSize(width, height);
    },
    _validateAdd: function(child) {
      var type = child.getType();
      if (type !== 'Group' && type !== 'Shape') {
        Konva.Util.throw('You may only add groups and shapes to a layer.');
      }
    },
    /**
         * get visible intersection shape. This is the preferred
         * method for determining if a point intersects a shape or not
         * also you may pass optional selector parametr to return ancestor of intersected shape
         * @method
         * @memberof Konva.Layer.prototype
         * @param {Object} pos
         * @param {Number} pos.x
         * @param {Number} pos.y
         * @param {String} [selector]
         * @returns {Konva.Node}
         * @example
         * var shape = layer.getIntersection({x: 50, y: 50});
         * // or if you interested in shape parent:
         * var group = layer.getIntersection({x: 50, y: 50}, 'Group');
         */
    getIntersection: function(pos, selector) {
      var obj, i, intersectionOffset, shape;

      if (!this.hitGraphEnabled() || !this.isVisible()) {
        return null;
      }
      // in some cases antialiased area may be bigger than 1px
      // it is possible if we will cache node, then scale it a lot
      // TODO: check { 0; 0 } point before loop, and remove it from INTERSECTION_OFFSETS.
      var spiralSearchDistance = 1;
      var continueSearch = false;
      while (true) {
        for (i = 0; i < INTERSECTION_OFFSETS_LEN; i++) {
          intersectionOffset = INTERSECTION_OFFSETS[i];
          obj = this._getIntersection({
            x: pos.x + intersectionOffset.x * spiralSearchDistance,
            y: pos.y + intersectionOffset.y * spiralSearchDistance
          });
          shape = obj.shape;
          if (shape && selector) {
            return shape.findAncestor(selector, true);
          } else if (shape) {
            return shape;
          }
          // we should continue search if we found antialiased pixel
          // that means our node somewhere very close
          continueSearch = !!obj.antialiased;
          // stop search if found empty pixel
          if (!obj.antialiased) {
            break;
          }
        }
        // if no shape, and no antialiased pixel, we should end searching
        if (continueSearch) {
          spiralSearchDistance += 1;
        } else {
          return null;
        }
      }
    },
    _getImageData: function(x, y) {
      var width = this.hitCanvas.width || 1,
        height = this.hitCanvas.height || 1,
        index = Math.round(y) * width + Math.round(x);

      if (!this._hitImageData) {
        this._hitImageData = this.hitCanvas.context.getImageData(
          0,
          0,
          width,
          height
        );
      }

      return [
        this._hitImageData.data[4 * index + 0], // Red
        this._hitImageData.data[4 * index + 1], // Green
        this._hitImageData.data[4 * index + 2], // Blue
        this._hitImageData.data[4 * index + 3] // Alpha
      ];
    },
    _getIntersection: function(pos) {
      var ratio = this.hitCanvas.pixelRatio;
      var p = this.hitCanvas.context.getImageData(
        Math.round(pos.x * ratio),
        Math.round(pos.y * ratio),
        1,
        1
      ).data,
        p3 = p[3],
        colorKey,
        shape;
      // fully opaque pixel
      if (p3 === 255) {
        colorKey = Konva.Util._rgbToHex(p[0], p[1], p[2]);
        shape = Konva.shapes[HASH + colorKey];
        if (shape) {
          return {
            shape: shape
          };
        }
        return {
          antialiased: true
        };
      } else if (p3 > 0) {
        // antialiased pixel
        return {
          antialiased: true
        };
      }
      // empty pixel
      return {};
    },
    drawScene: function(can, top) {
      var layer = this.getLayer(), canvas = can || (layer && layer.getCanvas());

      this._fire(BEFORE_DRAW, {
        node: this
      });

      if (this.getClearBeforeDraw()) {
        canvas.getContext().clear();
      }

      Konva.Container.prototype.drawScene.call(this, canvas, top);

      this._fire(DRAW, {
        node: this
      });

      return this;
    },
    drawHit: function(can, top) {
      var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas);

      if (layer && layer.getClearBeforeDraw()) {
        layer.getHitCanvas().getContext().clear();
      }

      Konva.Container.prototype.drawHit.call(this, canvas, top);
      this.imageData = null; // Clear imageData cache
      return this;
    },
    clear: function(bounds) {
      Konva.BaseLayer.prototype.clear.call(this, bounds);
      this.getHitCanvas().getContext().clear(bounds);
      this.imageData = null; // Clear getImageData cache
      return this;
    },
    // extend Node.prototype.setVisible
    setVisible: function(visible) {
      Konva.Node.prototype.setVisible.call(this, visible);
      if (visible) {
        this.getCanvas()._canvas.style.display = 'block';
        this.hitCanvas._canvas.style.display = 'block';
      } else {
        this.getCanvas()._canvas.style.display = 'none';
        this.hitCanvas._canvas.style.display = 'none';
      }
      return this;
    },
    /**
         * enable hit graph
         * @name enableHitGraph
         * @method
         * @memberof Konva.Layer.prototype
         * @returns {Layer}
         */
    enableHitGraph: function() {
      this.setHitGraphEnabled(true);
      return this;
    },
    /**
         * disable hit graph
         * @name disableHitGraph
         * @method
         * @memberof Konva.Layer.prototype
         * @returns {Layer}
         */
    disableHitGraph: function() {
      this.setHitGraphEnabled(false);
      return this;
    },
    setSize: function(width, height) {
      Konva.BaseLayer.prototype.setSize.call(this, width, height);
      this.hitCanvas.setSize(width, height);
      return this;
    }
  });
  Konva.Util.extend(Konva.Layer, Konva.BaseLayer);

  Konva.Factory.addGetterSetter(Konva.Layer, 'hitGraphEnabled', true);
  /**
     * get/set hitGraphEnabled flag.  Disabling the hit graph will greatly increase
     *  draw performance because the hit graph will not be redrawn each time the layer is
     *  drawn.  This, however, also disables mouse/touch event detection
     * @name hitGraphEnabled
     * @method
     * @memberof Konva.Layer.prototype
     * @param {Boolean} enabled
     * @returns {Boolean}
     * @example
     * // get hitGraphEnabled flag
     * var hitGraphEnabled = layer.hitGraphEnabled();
     *
     * // disable hit graph
     * layer.hitGraphEnabled(false);
     *
     * // enable hit graph
     * layer.hitGraphEnabled(true);
     */
  Konva.Collection.mapMethods(Konva.Layer);
})();
