Fabricjs 按颜色隔离对象计数
Fabricjs isolate object count by color
我有一个计数器,用于计算 canvas 上的对象总数,但我想将其隔离以按对象颜色计数。 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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>
使用自定义辅助函数,我能够按颜色进行计数和过滤。您可以扩展功能以处理更复杂的过滤器,例如形状类型和颜色。此外,您可能希望实现缓存机制以防止它每次都重新计数。
function canvasCount(canvas) {
var obj = canvas.getObjects();
var res = {};
for (var i = 0; i < obj.length; i++) {
if (!obj[i].type) continue; // skip main canvas obj
// get the shapes color
var color = obj[i].fill;
// adds color key if not already in obj
if (!res[color]) res[color] = 0;
// increments color each by one
res[color]++;
// Length of all yellow triangles
// res.yellow
}
return res;
}
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 = canvasCount(canvas);
document.getElementById("greentally").value = count.green || 0;
document.getElementById("yellowtally").value = count.yellow || 0 ;
document.getElementById("redtally").value = count.red || 0;
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
});
}
}
function canvasCount(canvas) {
var obj = canvas.getObjects();
var res = {};
for (var i = 0; i < obj.length; i++) {
if (!obj[i].type) continue; // skip main canvas obj
// get the shapes color
var color = obj[i].fill;
// adds color key if not already in obj
if (!res[color]) res[color] = 0;
// increments color each by one
res[color]++;
// Length of all yellow triangles
// res.yellow
}
return res;
}
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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>
注意::我无法修复 Uncaught TypeError: Cannot set property 'top' of null
错误。
计算具有特定颜色(或任何其他 属性)的对象很容易,因为您通过 canvas.getObjects()
获得 canvas 上所有对象的数组 - 然后您只需过滤那些您正在通过 filter()
寻找。为此,我在我的代码片段中引入了一个 getObjectsBy(fn)
辅助函数。
也就是说,您的代码还有其他几个值得解决的问题:
- 制作
icon
对 iconTriangle
的复制引用乍一看可能看起来很整洁,但实际上毫无意义且容易出错,例如您必须编写单独的逻辑来隐藏副本,并且在实际需要时必须注意它是否 null
。这就是您获得这些 Cannot set property 'top' of null
的原因。在我的代码片段中,我通过类似工厂的 addIcon()
创建了一个新图标,它与 clone()
一样易于使用,但也更易于维护。
mouse:up
事件不仅会在您单击 canvas 时触发,还会在您单击对象时触发,因此每次移动时都会创建不必要的图标。在我的代码片段中,我在 mouse:up
侦听器中使用早期的 return 来解决此问题。
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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>
我有一个计数器,用于计算 canvas 上的对象总数,但我想将其隔离以按对象颜色计数。 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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>
使用自定义辅助函数,我能够按颜色进行计数和过滤。您可以扩展功能以处理更复杂的过滤器,例如形状类型和颜色。此外,您可能希望实现缓存机制以防止它每次都重新计数。
function canvasCount(canvas) {
var obj = canvas.getObjects();
var res = {};
for (var i = 0; i < obj.length; i++) {
if (!obj[i].type) continue; // skip main canvas obj
// get the shapes color
var color = obj[i].fill;
// adds color key if not already in obj
if (!res[color]) res[color] = 0;
// increments color each by one
res[color]++;
// Length of all yellow triangles
// res.yellow
}
return res;
}
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 = canvasCount(canvas);
document.getElementById("greentally").value = count.green || 0;
document.getElementById("yellowtally").value = count.yellow || 0 ;
document.getElementById("redtally").value = count.red || 0;
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
});
}
}
function canvasCount(canvas) {
var obj = canvas.getObjects();
var res = {};
for (var i = 0; i < obj.length; i++) {
if (!obj[i].type) continue; // skip main canvas obj
// get the shapes color
var color = obj[i].fill;
// adds color key if not already in obj
if (!res[color]) res[color] = 0;
// increments color each by one
res[color]++;
// Length of all yellow triangles
// res.yellow
}
return res;
}
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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>
注意::我无法修复 Uncaught TypeError: Cannot set property 'top' of null
错误。
计算具有特定颜色(或任何其他 属性)的对象很容易,因为您通过 canvas.getObjects()
获得 canvas 上所有对象的数组 - 然后您只需过滤那些您正在通过 filter()
寻找。为此,我在我的代码片段中引入了一个 getObjectsBy(fn)
辅助函数。
也就是说,您的代码还有其他几个值得解决的问题:
- 制作
icon
对iconTriangle
的复制引用乍一看可能看起来很整洁,但实际上毫无意义且容易出错,例如您必须编写单独的逻辑来隐藏副本,并且在实际需要时必须注意它是否null
。这就是您获得这些Cannot set property 'top' of null
的原因。在我的代码片段中,我通过类似工厂的addIcon()
创建了一个新图标,它与clone()
一样易于使用,但也更易于维护。 mouse:up
事件不仅会在您单击 canvas 时触发,还会在您单击对象时触发,因此每次移动时都会创建不必要的图标。在我的代码片段中,我在mouse:up
侦听器中使用早期的 return 来解决此问题。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  
<input class="tally" disabled id="greentally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="yellow" onclick="iconSet()" /> Yellow  
<input class="tally" disabled id="yellowtally" type="text" value="0">
<br>
<input name="iconType" type="radio" id="red" onclick="iconSet()" /> red  
<input class="tally" disabled id="redtally" type="text" value="0">
<canvas id="c" width="300" height="300"></canvas>