delete selected objects in fabric.js - javascript

My aim is to get three buttons in fabric.js:
"Copy",
"Paste",
"Delete".
Button with name "Copy" should copy selected objects.
Button with name "Paste" should paste copied objects.
Button with name "Delete" should delete selected objects from canvas.
"Copy" and "paste" buttons helps to work with selected objectives.
Buttons with copy and paste works well at that time remove button shows error:
How should I solve my problem?
function Copy()
{
canvas.getActiveObject().clone(function(cloned)
{
_clipboard = cloned;
});
}
function Delete()
{
canvas.getActiveObject().remove();
}
function Paste() {
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function(obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
_clipboard.top += 10;
_clipboard.left += 10;
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
}
var canvas = this.__canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 100,
top: 50,
fill: '#D81B60',
width: 100,
height: 100,
strokeWidth: 2,
stroke: "#880E4F",
rx: 10,
ry: 10,
angle: 45,
hasControls: true
});
canvas.add(rect);
<div>
<button type="button" onclick="Copy()">copy</button>
<button type="button" onclick="Paste()">paste</button>
<button type="button" onclick="Delete()">delete</button>
</div>
<div style="display:flex;flex-direction:row;">
<div>
<canvas id="c" width="1300" height="1300"></canvas>
</div>
</div>
<script src="https://unpkg.com/fabric#4.6.0/dist/fabric.js"></script>

The error is clear you are getting:
remove is not a function
You should be using canvas.remove(object) here is a working sample:
function Delete() {
var active = canvas.getActiveObject()
if (active) {
canvas.remove(active)
if (active.type == "activeSelection") {
active.getObjects().forEach(x => canvas.remove(x))
canvas.discardActiveObject().renderAll()
}
}
}
var canvas = this.__canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 100,
top: 50,
fill: '#D81B60',
width: 100,
height: 100,
strokeWidth: 2,
stroke: "#880E4F",
rx: 10,
ry: 10,
angle: 45,
hasControls: true
});
canvas.add(rect);
var rect2 = new fabric.Rect({
left: 160,
top: 10,
fill: '#D81B60',
width: 60,
height: 60,
strokeWidth: 2,
stroke: "#880E4F",
hasControls: true
});
canvas.add(rect2);
<div>
<button type="button" onclick="Delete()">delete</button>
</div>
<div style="display:flex;flex-direction:row;">
<div>
<canvas id="c" width="1300" height="1300"></canvas>
</div>
</div>
<script src="https://unpkg.com/fabric#4.6.0/dist/fabric.js"></script>

Related

StrokeWidth value in px/em fabricjs

I am adding a rectangle/circle to the canvas and changing the strokeWidth with a range type input.
What is the value of strokeWidth in px/em/%, if we have strokeWidth:5 and range of strokeWidth(1-10).
Actually I wanted to know how much the actual width increases in px, whenever we try to increase the strokeWidth.
Check the code for example:
var canvas = new fabric.Canvas('canvas1');
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true,
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
var activeObj = canvas.getActiveObject();
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
activeObj.set({
strokeWidth: cur_value
});
canvas.renderAll();
});
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
If I'm understanding your question correctly, I believe what you're wanting is to calculate the on screen CSS pixel size of your object and stroke. This changes according to the canvas's zoom level so that needs to be accounted for in the calculation.
This will give you the total object dimensions in CSS pixels (including stroke):
var zoom = canvas.getZoom();
var totalWidth = obj.getScaledWidth() * zoom;
var totalHeight = obj.getScaledHeight() * zoom;
This will give you just the stroke size in CSS pixels:
var zoom = canvas.getZoom();
var strokeX = obj.strokeWidth * obj.scaleX * zoom;
var strokeY = obj.strokeWidth * obj.scaleY * zoom;
If you're using the strokeUniform property, the stroke size won't be affected by the object's scale, so you can just do this.
var zoom = canvas.getZoom();
var strokeSize = obj.strokeWidth * zoom;
Also, if your object uses a paintFirst value of stroke then half of the stroke width will be covered by the fill, so you'll need to multiply your result by 0.5 to get the visible stroke width.
Just add two lines:-
1.<div id="strokeValue"></div> in html
2.document.getElementById('strokeValue').innerHTML=cur_value; at /* Control the border */ in Javascript
here is the full code:-
<style>
button {
max-resolution: 10px;
height: 30px;
}
div {
margin: 10px
}
</style>
<div>
<button class="add_shape" data-rel="circle">Add Circle</button>
<button class="add_shape" data-rel="rectangle">Add Rectangle</button>
<label class="control-label">Border</label>
<input id="control_border" type="range" min="0" max="10" step="1" value="0" />
</div>
<div id="strokeValue"></div>
<canvas id="canvas1" width="600" height="300" style="border:1px solid #000000;"></canvas>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>
<script>
var canvas = new fabric.Canvas('canvas1');
$('.add_shape').click(function() {
var cur_value = $(this).attr('data-rel');
if (cur_value != '') {
switch (cur_value) {
case 'rectangle':
var rect = new fabric.Rect({
left: 50,
top: 50,
fill: '#aaa',
width: 50,
height: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true,
});
canvas.add(rect);
canvas.setActiveObject(rect);
break;
case 'circle':
var circle = new fabric.Circle({
left: 50,
top: 50,
fill: '#aaa',
radius: 50,
opacity: 1,
stroke: '#000',
strokeWidth: 1,
noScaleCache: false,
strokeUniform: true
});
canvas.add(circle);
canvas.setActiveObject(circle);
break;
}
}
});
/* Control the border */
$('#control_border').change(function() {
var cur_value = parseInt($(this).val());
var activeObj = canvas.getActiveObject();
document.getElementById('strokeValue').innerHTML=cur_value;
if (activeObj == undefined) {
alert('Please select the Object');
return false;
}
activeObj.set({
strokeWidth: cur_value
});
canvas.renderAll();
});
</script>

Problem with FabricJS TextBox can't select and edit value & Layer Index is not working correctly

I have a problem with Fabric Text Box: user can't select TextBox & edit value. And using function canvas.MoveTo to set image of cloud to index 2 & Text Box to index 7, I expect TextBox is above Image, but actually, the Text box is always display behind the cloud image.
Here is my code
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
canvas.setBackgroundImage('https://futushigame.firebaseapp.com/Background.svg', canvas.renderAll.bind(canvas), {
// Needed to position backgroundImage at 0/0
originX: 'left',
originY: 'top'
});
fabric.Image.fromURL("https://futushigame.firebaseapp.com/group5.svg", function(img) {
img.left = 0.2;
img.top = 54.94981;
canvas.add(img);
canvas.moveTo(img, 2);
canvas.renderAll();
});
var textbox7 = new fabric.Textbox("LITTLE PRINCESS", {
left: 0,
top: -14.620352,
width: 169.598436,
fontSize: 19.3302,
fontFamily: 'Nunito-Bold',
fill: "#000000",
editable: true,
});
textbox7.editable = true;
canvas.add(textbox7);
canvas.moveTo(textbox7, 7);
textbox7.transformMatrix = [1, 0, 0, 1, 64.7895, 169.1073];
textbox7.setCoords();
canvas.renderAll();
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
For moveTo index, better choose a number between 0 and number of object present in canvas.
And as I see you are changing left and top using tansformMatrix, so just set left and top to the object.
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
canvas.setBackgroundImage('https://futushigame.firebaseapp.com/Background.svg', canvas.renderAll.bind(canvas), {
// Needed to position backgroundImage at 0/0
originX: 'left',
originY: 'top'
});
fabric.Image.fromURL("https://futushigame.firebaseapp.com/group5.svg", function(img) {
img.left = 0.2;
img.top = 54.94981;
canvas.add(img);
canvas.moveTo(img, 0);
canvas.renderAll();
});
var textbox7 = new fabric.Textbox("LITTLE PRINCESS", {
left: 64.7895,
top: 154.4856948,
width: 169.598436,
fontSize: 19.3302,
fontFamily: 'Nunito-Bold',
fill: "#000000",
editable: true,
});
canvas.add(textbox7);
canvas.moveTo(textbox7, 1);
//textbox7.transformMatrix = [1, 0, 0, 1, 64.7895, 169.1073];
textbox7.setCoords();
canvas.renderAll();
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

How to prevent content scale while resize canvas element when using Fabricjs

Please help me, how to keep content size while resize canvas size ?
Please see this code:
https://jsfiddle.net/thobn24h/79Ls6fry/7/
when I resize windows, Rectangle and Text are scaled and have aliasing. How to make them have same size with original and don't have aliasing ?
( by the way, why at the first time canvas size not equal with div size ? )
Thank you!
<style>
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
</style>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.0/fabric.js"></script>
<script>
$(function() {
var canvasObject = document.getElementById("editorCanvas");
// set canvas equal size with div
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
console.log("width: " + $(canvasObject).width());
console.log("height: " + $(canvasObject).height());
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionColor: 'blue',
selectionLineWidth: 2
});
// create a rectangle object
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: 'red',
width: 150,
height: 150
});
rect.set({
transparentCorners: false,
rotatingPointOffset: 40,
cornerColor: 'black',
cornerStrokeColor: 'black',
borderColor: 'black',
cornerSize: 12,
padding: 10,
cornerStyle: 'circle',
borderDashArray: [3, 3]
});
// "add" rectangle onto canvas
canvas.add(rect);
var text = new fabric.Text('hello world', { left: 10, top: 10 });
canvas.add(text);
// Tracking resize windows event
window.addEventListener('resize', resizeCanvas, false);
});
function resizeCanvas() {
var canvasObject = document.getElementById("editorCanvas");
$(canvasObject).width($("#canvasContainer").width());
$(canvasObject).height($("#canvasContainer").height());
console.log("width: " + $(canvasObject).width());
console.log("height: " + $(canvasObject).height());
}
You need to use canvas#setDimensions to set widht/height.
DEMO
canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
selectionColor: 'blue',
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height:$("#canvasContainer").height()
});
// create a rectangle object
var rect = new fabric.Rect({
left: 10,
top: 10,
fill: 'red',
width: 150,
height: 150
});
rect.set({
transparentCorners: false,
rotatingPointOffset: 40,
cornerColor: 'black',
cornerStrokeColor: 'black',
borderColor: 'black',
cornerSize: 12,
padding: 10,
cornerStyle: 'circle',
borderDashArray: [3, 3]
});
// "add" rectangle onto canvas
canvas.add(rect);
var text = new fabric.Text('hello world', {
left: 10,
top: 10
});
canvas.add(text);
// Tracking resize windows event
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.setDimensions({
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
})
}
#canvasContainer {
width: 100%;
height: 100vh;
background-color: gray;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.0/fabric.js"></script>
<div id="canvasContainer">
<canvas id="editorCanvas"></canvas>
</div>

clone one canvas to another having trouble

I have checked all the answers to clone existing canvas to another one. But I could not get it done.
Please check my current progress.
http://jsfiddle.net/37n8rtdf/5/
First canvas will be clipped to that square you see initially and content of that canvas will be added in another canvas. But I don't know it always throw TYPE_MISMATCH_ERR: DOM Exception 171 in chrome. I am using fabricjs to clipping content.
Bit of help is appreciated.
Thanks
Here is code of my script:
HTML
<textarea id="line_1"></textarea>
<input type="button" id="render" value="Apply" />
<input type="button" id="preview" value="preview" />
<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
<canvas id="c_new" width="500" height="500" style="border:1px solid red; margin: 30px;"></canvas>
`
Javascript
var canvas = this.__canvas = new fabric.Canvas('c');
var canvas_new = this.__canvas = new fabric.Canvas('c_new');
var product_image = 'http://www.jail.se/hardware/digital_camera/canon/ixus_800is-powershot_sd700/images/sample_photos/sample3.jpg';
//var ctx = canvas.getContext("2d");
var polygon;
$(document).ready(function(){
fabric.Object.prototype.transparentCorners = false;
//canvas.setDimensions({width:w,height:h});
var center = canvas.getCenter();
canvas.setBackgroundImage(product_image,
canvas.renderAll.bind(canvas), {
scaleX:1,
scaleY:1,
top: center.top,
left: center.left,
originX: 'center',
originY: 'center',
backgroundImageOpacity: 0,
backgroundImageStretch: false
});
canvas_new.setBackgroundImage(product_image,
canvas_new.renderAll.bind(canvas_new), {
scaleX:1,
scaleY:1,
top: center.top,
left: center.left,
originX: 'center',
originY: 'center'
});
polygon = new fabric.Polygon([
{x: 0, y: 0},
{x: 220, y: 0},
{x: 220, y: 180},
{x: 0, y: 180} ], {
left: 140,
top: 150,
angle: 0,
fill: 'transparent',
stroke: '#000', strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockScalingX: true,
lockScalingY: true,
lockRotation: true,
hasControls: false,
hasBorders: false,
hoverCursor: 'default',
overflow: 'hidden'
});
canvas.add(polygon);
$('#render').click(function(){ return render(); });
$('#preview').click(function(){ return rasterize(); });
});
function render()
{
var text_val = $('#line_1').val();
var comicSansText = new fabric.Text(text_val, {
fontWeight: 'normal'
});
canvas.add(comicSansText.set({ left: 200, top: 150, angle: 0 }));
}
function rasterize()
{
var shape = canvas.item(0);
polygon.strokeWidth=0;
canvas.renderAll();
//canvas.remove(shape);
canvas.clipTo = function(ctx) {
shape.render(ctx);
};
var ctx2 = canvas_new.getContext('2d');
ctx2.drawImage(canvas, 0, 0);
}
`
#WinterMute is right, you are trying to draw the Fabric object instead of the canvas element.
You fabric object seems to have two canvases embedded (lowerCanvasEl and upperCanvasEl).
So you can modify just a little bit your code to make it look like :
function rasterize() {
var shape = canvas.item(0);
polygon.strokeWidth = 0;
canvas.renderAll();
canvas.clipTo = function(ctx) {
shape.render(ctx);
};
var ctx2 = canvas_new.getContext('2d');
ctx2.drawImage(canvas.lowerCanvasEl, 0, 0);
ctx2.drawImage(canvas.upperCanvasEl, 0, 0);
}
Updated fiddle

Deselecting mouse event 'mouse:down' after initial event has been rendered

I am very new to fabric.js, but I am learning quickly.
I have a few items that, when clicked, will fill with the color red.
My problem lies with clicking the image again to reset only that image back to default (black).
Can someone explain how to achieve this?
canvas.on('mouse:down', function(e) {
e.target.setFill('red');
e.target.lockMovementX = e.target.lockMovementY = true;
e.target.lockScalingX = e.target.lockScalingY = true;
e.target.lockUniScaling = true;
canvas.deactivateAll().renderAll();
});
Please see the JSFIDDLE for the full example code
Look at the if statement below. It detects the current color and switches it:
(function(){
var canvas = new fabric.Canvas('c4');
canvas.hoverCursor = 'default';
canvas.on('mouse:down', function(e) {
var color = e.target.fill;
if(color == '#000')
{
e.target.setFill('red');
} else {
e.target.setFill('#000');
}
e.target.lockMovementX = e.target.lockMovementY = true;
e.target.lockScalingX = e.target.lockScalingY = true;
e.target.lockUniScaling = true;
canvas.deactivateAll().renderAll();
});
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 200 }));
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 150 }));
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 100 }));
})();
Look at this Fiddle : http://jsfiddle.net/hpyrk05w/3/
it is so simple :
you have to check on mouse down if current fill of object is what?
if current fill is red than fill it with black color and if not, than fill it with red color
(function(){
var canvas = new fabric.Canvas('c4');
canvas.hoverCursor = 'default';
canvas.on('mouse:down', function(e) {
if(e.target.getFill()=="red")
e.target.setFill('black');
else
e.target.setFill('red');
e.target.lockMovementX = e.target.lockMovementY = true;
e.target.lockScalingX = e.target.lockScalingY = true;
e.target.lockUniScaling = true;
canvas.deactivateAll().renderAll();
});
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 200 }));
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 150 }));
canvas.add(new fabric.Circle({ radius: 10, fill: '#000', top: 100, left: 100 }));
})();
pre { margin-left: 15px !important }
canvas{border: 1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://fabricjs.com/lib/fabric.js"></script>
<canvas id="c4" width="450" height="500"></canvas>

Categories

Resources