首页 > 解决方案 > 从组中选择对象的问题

问题描述

我目前正在创建自己的具有扩展组功能的自定义组类。首先,我创建了一个可以选择组中对象的功能。该功能的概念是:

  1. 在画布上单击鼠标时检测鼠标点。
  2. 基于鼠标点检测分组中的对象。
  3. 如果在组中找到对象,则激活该对象。
  4. 如果在组中未找到对象,则激活该组。
  5. 组中的活动对象具有实线边框,组具有虚线边框。

未修改组时,一切正常。但是,当组进行缩放、旋转和倾斜时,就会出现这些问题:

  1. 组内对象的选择区域不遵循实际大小。
  2. 实线边框仍然显示创建对象的初始属性,而不是跟随组的旋转和缩放。

有关更多详细信息,您可以查看下图:

问题和预期结果

这是组自定义类:

/**
 * GroupExtended class
 * @extends fabric.Group
 * @todo preserve object stacking
 * @todo fix bug object coords on group scaling
 */
var GroupExtended = fabric.util.createClass(fabric.Group, {
  /**
   * Type of an object
   * @type String
   * @default
   */
  type: "group-extended",

  /**
   * When set to `false`, object's controlling borders are not rendered
   * @type Boolean
   * @default
   */
  hasBorders: true,

  /**
   * Array specifying dash pattern of an object's borders (hasBorder must be true)
   * @type Array
   * @default
   */
  borderDashArray: [5, 5],

  /**
   * Selected object
   * @type fabric.Object
   */
  _selectedObject: null,

  /**
   * Remove solid border from selected object
   */
  _removeSelectedBorder: function () {
    this.canvas.clearContext(this.canvas.contextTop);
  },

  /**
   * Show solid border from selected object
   */
  _showSelectedBorder: function () {
    this._removeSelectedBorder();
    this._selectedObject &&
      this._selectedObject._renderControls(this.canvas.contextTop, {
        hasControls: false,
      });
  },

  /**
   * Constructor
   * @param {Object} objects Group objects
   * @param {Object} [options] Options object
   * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already.
   * @return {Object} thisArg
   */
  initialize: function (objects, options, isAlreadyGrouped) {
    this.callSuper("initialize", objects, options, isAlreadyGrouped);

    this.on({
      moving: this._showSelectedBorder,
      deselected: this._removeSelectedBorder,
    });
  },

  /**
   * Get selected object based on mouse point.
   * Return detected object or
   * most top of objects if more than one object detected in mouse point or
   * null if mouse point refer to empty area in group.
   * @param {Object} point object with "x" and "y" number values
   * @return {fabric.Object} selected object
   */
  getSelectedObjectInGroup: function (point) {
    // reset last known selected object
    this._selectedObject = null;
    this._removeSelectedBorder();

    this.forEachObject(
      function (obj) {
        var matrixPoint = obj.calcTransformMatrix();

        var center = {
          x: matrixPoint[4],
          y: matrixPoint[5],
        };

        var thisPos = {
          xStart: center.x - obj.width / 2,
          xEnd: center.x + obj.width / 2,
          yStart: center.y - obj.height / 2,
          yEnd: center.y + obj.height / 2,
        };

        if (point.x >= thisPos.xStart && point.x <= thisPos.xEnd) {
          if (point.y >= thisPos.yStart && point.y <= thisPos.yEnd) {
            this._selectedObject = obj;
            this._showSelectedBorder();
          }
        }
      }.bind(this)
    );

    return this._selectedObject;
  },
});

链接到 jsfiddle:https ://jsfiddle.net/clngkusnd/pa5dzLm2/

问题是为什么在创建对象时,选定对象的选择区域保持不变

标签: javascripthtml5-canvasfabricjs

解决方案


fabricJS 中的选择区代码没有考虑分组转换,即使现在 fabricJS 没有理由支持分组选择,这个问题也可以修复。请注意,您可以在不编写自定义代码来查找内部对象的情况下完成您所取得的成就:

https://jsfiddle.net/asturur/wg0mkjv2/3/

fabricJS 支持在组内找到开箱即用的目标,使subTargetCheck布尔属性能够true


推荐阅读