我有一个计数器,可以计算画布上的对象总数,但是我想将其隔离以按对象颜色计数。 canvas.getObjects().length;可以按颜色获取对象吗?



var canvas = new fabric.Canvas('c');
var iconTriangle = new fabric.Triangle({
  width: 62.5,
  height: 50,
  originX: 'center',
  originY: 'center',
  fill: "green"
});
icon = iconTriangle;
canvas.add(icon);
//disable icon & hide when hovering over existing icon
canvas.on('mouse:over', function(obj) {
  iconTriangle.set('opacity', 0);
  icon = null;
  canvas.renderAll()
});
//restor icon & unhide
canvas.on('mouse:out', function(obj) {
  iconTriangle.set('opacity', 1);
  icon = iconTriangle;
  canvas.renderAll()
});

canvas.on('mouse:move', function(obj) {
  icon.top = obj.e.y - 80;
  icon.left = obj.e.x - 10;
  canvas.renderAll()
});
canvas.on('mouse:out', function(obj) {
  icon.top = -100;
  icon.left = -100;
  canvas.renderAll()
});
//place icon and count each by type
canvas.on('mouse:up', function(obj) {
  var count = canvas.getObjects().length;
  document.getElementById("greentally").value = count;
  document.getElementById("yellowtally").value = count;
  document.getElementById("redtally").value = count;
  canvas.add(icon.clone());
  canvas.renderAll();
});
//set icon type
function iconSet() {
  if (document.getElementById("green").checked == true) {
    iconTriangle.setFill("green");
    canvas.renderAll();
    canvas.trigger('object:modified', {
      target: iconTriangle
    });

  } else if (document.getElementById("yellow").checked == true) {
    iconTriangle.setFill("yellow");
    canvas.renderAll();
    canvas.trigger('object:modified', {
      target: iconTriangle
    });
  } else if (document.getElementById("red").checked == true) {
    iconTriangle.setFill("red");
    canvas.renderAll();
    canvas.trigger('object:modified', {
      target: iconTriangle
    });
  }
}

canvas {
  border: 1px solid #ccc;
}

.tally {
  position: fixed;
  width: 50px;
  left: 255px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>

<input name="iconType" type="radio" id="green" onclick="iconSet()" />Green &emsp;
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow &emsp;
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red &emsp;
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>

最佳答案

对具有特定颜色(或任何其他属性)的对象进行计数很容易,因为您可以通过canvas.getObjects()在画布上获得所有对象的数组-然后,您可以通过filter()过滤出要过滤的对象。为此,我在代码段中引入了getObjectsBy(fn)辅助函数。

也就是说,您的代码还有其他几个值得解决的问题:


首先,将icon复制为iconTriangle的引用看起来很整洁,但实际上是毫无意义且容易出错的,例如您必须编写单独的逻辑来隐藏副本,并且必须在实际需要时注意它是否为null。这就是获得这些Cannot set property 'top' of null的原因。在我的代码段中,我正在通过类似于工厂的addIcon()创建一个新图标,该图标与clone()一样易于使用,但也易于维护。
mouse:up事件不仅在单击画布时触发,而且在单击对象时触发,因此最终每次移动一些东西时都会创建不必要的图标。在我的代码段中,我正在使用mouse:up侦听器中的早期返回值来解决此问题。
iconSet()似乎是引入助手功能以使其更简洁的好地方。同样,将颜色存储在单独的变量中有助于将图标创建与iconTriangle分离。




var canvas = new fabric.Canvas('c');
var currentColor;
var defaultIcon = {
  width: 62.5,
  height: 50,
  originX: 'center',
  originY: 'center'
};
var iconTriangle = new fabric.Triangle(defaultIcon);
setColor('green');
canvas.add(iconTriangle);
//disable icon & hide when hovering over existing icon
canvas.on('mouse:over', function(obj) {
  iconTriangle.set('opacity', 0);
  canvas.renderAll();
});
//restor icon & unhide
canvas.on('mouse:out', function(e) {
  // if 'target' is null, means mouse is out of canvas
  if (e.target) {
    iconTriangle.set('opacity', 1);
  } else {
    iconTriangle.left = -100;
    iconTriangle.top = -100;
  }
  canvas.renderAll();
});
//move pointer icon
canvas.on('mouse:move', function(obj) {
  iconTriangle.top = obj.e.y - 80;
  iconTriangle.left = obj.e.x - 10;
  canvas.renderAll();
});

//count each by type and place new icon
canvas.on('mouse:up', function(e) {
  if (e.target) {
    return
  }
  var red = getObjectsBy((obj) => obj.fill === 'red').length;
  var green = getObjectsBy((obj) => obj.fill === 'green').length;
  var yellow = getObjectsBy((obj) => obj.fill === 'yellow').length;
  document.getElementById("greentally").value = green;
  document.getElementById("yellowtally").value = yellow;
  document.getElementById("redtally").value = red;
  addIcon(e.e.x - 10, e.e.y - 80, currentColor);
});
//set icon type
function iconSet() {
  if (document.getElementById("green").checked == true) {
    setColor('green');
  } else if (document.getElementById("yellow").checked == true) {
    setColor('yellow');
  } else if (document.getElementById("red").checked == true) {
    setColor('red');
  }
}
function setColor (color) {
  currentColor = color;
  iconTriangle.setFill(currentColor);
  canvas.renderAll();
}
function getObjectsBy (fn) {
  return canvas.getObjects().filter(fn)
}
function addIcon (x, y, color) {
  var icon = new fabric.Triangle(defaultIcon);
  icon.setFill(color);
  icon.left = x;
  icon.top = y;
  canvas.add(icon);
  canvas.renderAll();
}

canvas {
  border: 1px solid #ccc;
}

.tally {
  position: fixed;
  width: 50px;
  left: 255px;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>

<input checked name="iconType" type="radio" id="green" onclick="iconSet()" />Green &emsp;
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow &emsp;
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red &emsp;
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>

关于javascript - FabricJS按颜色隔离对象计数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57509915/

10-12 12:56
查看更多