FabricJS on('object:selected') doesn't trigger consistently for lines - javascript
I am currently building a simple line drawing tool using FabricJs and canvas.
DRAW mode: Draw lines using the mouse
DELETE mode: Click anywhere a line to delete it. Using the fabric js on('object:selected')
My issue is that DELETE mode is inconsistent,
Clicking on the top half deletes the line, clicking on the bottom half doesn't do anything.
Am I missing something? I have tried everything.
Thanks for the help.
EDIT: ADDED snippet
var isDrawing = true;
var canvas = new fabric.Canvas('a', {
selection: false
});
var grid = 30;
// create grid
//line
var line, isDown;
function createGrid(board) {
for (var i = 0; i < (600 / grid); i++) {
board.add(new fabric.Line([i * grid, 0, i * grid, 600], {
stroke: '#000',
selectable: false
}));
board.add(new fabric.Line([0, i * grid, 600, i * grid], {
stroke: '#000',
selectable: false
}))
}
}
//create grids
createGrid(canvas);
//Button Toggle
$("#draw").click(function() {
isDrawing = true;
DrawLine(canvas);
});
$("#erase").click(function() {
isDrawing = false;
EraseLine(canvas);
});
function DrawLine(board) {
// add objects
board.on('mouse:down', function(o) {
isDown = true;
var pointer = board.getPointer(o.e);
var points = [Math.round(pointer.x / grid) * grid, Math.round(pointer.y / grid) * grid, pointer.x, pointer.y];
line = new fabric.Line(points, {
strokeWidth: 5,
strokeDashArray: [5, 10],
strokeLineCap: 'round',
fill: '#005E7A',
stroke: '#005E7A',
originX: 'center',
originY: 'center',
hasControls: 'false',
hasRotatingPoint: 'false',
padding: 50,
///perPixelTargetFind: true,
lockMovementX: true,
lockMovementY: true,
});
line.setOptions({
'selectable': false
});
board.add(line);
});
board.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = board.getPointer(o.e);
line.set({
x2: pointer.x,
y2: pointer.y
});
board.renderAll();
});
board.on('mouse:up', function(o) {
var pointer = board.getPointer(o.e);
isDown = false;
line.set({
x2: Math.round(pointer.x / grid) * grid,
y2: Math.round(pointer.y / grid) * grid
});
board.renderAll();
});
}
function EraseLine(board) {
board.off();
line.setOptions({
'selectable': true
});
var eraseHandler = function(o) {
console.log(o);
board.remove(o.target);
};
board.on('object:selected', eraseHandler);
board.renderAll();
}
canvas {
background-color: transparent;
margin: 3px;
width: 120px;
height: 240px;
border: 2px solid #ccc;
padding-left: 0;
}
.boards {
display: inline;
padding-left: 0;
}
.boards canvas {
list-style: none;
display: inline-block;
background-color: transparent;
margin: 3px;
width: 120px;
height: 240px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<h1>Fabric Js On selected mode </h1>
<div class="boards">
<canvas id="a" width="120" height="240"></canvas>
<br>
<button id="draw">
Draw MOde
</button>
<button id="erase">
Erase Mode
</button>
var isDrawing = true;
var canvas = new fabric.Canvas('a', {
selection: false
});
var grid = 30;
// create grid
//line
var line, isDown;
function createGrid(board) {
for (var i = 0; i < (600 / grid); i++) {
board.add(new fabric.Line([i * grid, 0, i * grid, 600], {
stroke: '#000',
selectable: false
}));
board.add(new fabric.Line([0, i * grid, 600, i * grid], {
stroke: '#000',
selectable: false
}))
}
}
//create grids
createGrid(canvas);
//Button Toggle
$("#draw").click(function() {
isDrawing = true;
DrawLine(canvas);
});
$("#erase").click(function() {
isDrawing = false;
EraseLine(canvas);
});
function DrawLine(board) {
canvas.forEachObject(function(obj){
obj.selectable = false;
})
// add objects
board.on('mouse:down', function(o) {
isDown = true;
var pointer = board.getPointer(o.e);
var points = [Math.round(pointer.x / grid) * grid, Math.round(pointer.y / grid) * grid, pointer.x, pointer.y];
line = new fabric.Line(points, {
strokeWidth: 5,
strokeDashArray: [5, 10],
strokeLineCap: 'round',
fill: '#005E7A',
stroke: '#005E7A',
originX: 'center',
originY: 'center',
hasControls: 'false',
hasRotatingPoint: 'false',
padding: 50,
///perPixelTargetFind: true,
lockMovementX: true,
lockMovementY: true,
selectable: false
});
board.add(line);
});
board.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = board.getPointer(o.e);
line.set({
x2: pointer.x,
y2: pointer.y
});
board.renderAll();
});
board.on('mouse:up', function(o) {
var pointer = board.getPointer(o.e);
isDown = false;
line.set({
x2: Math.round(pointer.x / grid) * grid,
y2: Math.round(pointer.y / grid) * grid
});
line.setCoords();
board.renderAll();
});
}
function EraseLine(board) {
board.off();
line.setOptions({
'selectable': true
});
canvas.forEachObject(function(obj){
obj.selectable = true;
})
canvas.renderAll();
var eraseHandler = function(o) {
board.remove(o.target);
};
board.on('object:selected', eraseHandler);
}
canvas {
background-color: transparent;
margin: 3px;
width: 120px;
height: 240px;
border: 2px solid #ccc;
padding-left: 0;
}
.boards {
display: inline;
padding-left: 0;
}
.boards canvas {
list-style: none;
display: inline-block;
background-color: transparent;
margin: 3px;
width: 120px;
height: 240px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script>
<h1>Fabric Js On selected mode </h1>
<div class="boards">
<canvas id="a" width="120" height="240"></canvas>
<br>
<button id="draw">
Draw MOde
</button>
<button id="erase">
Erase Mode
</button>
use line.setCoords(); to set coordinate after setting line points.
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>
How can I put the selected:clear filter into the canvas that I loaded as JSON?
I have a canvas and I am loading this canvas as JSON data. I want it to give me an alert() when it clicks on an empty place except objects on the canvas. How can I do this? canvas.on('selection:cleared') code works when I add an element to the canvas, but I want it to work on the canvas that I loaded as JSON data. var canvas = new fabric.Canvas('c'); var json = '{"version":"3.1.0","objects":[{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":194,"top":157,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1047","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1047"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1047","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]},{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":640,"top":473,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1048","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1048"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1048","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}],"backgroundImage":{"type":"image","version":"3.1.0","originX":"left","originY":"top","left":0,"top":0,"width":780,"height":646,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://i1.wp.com/onideal.com/wp-content/uploads/2020/03/Schlafzimmer-Grundriss-ideale-Position-Bett-Moebel-Kleiderschrank-dreieckchen-4-780x646.jpg?fit=780%2C646&ssl=1","filters":[]}}' canvas.loadFromJSON(json, () => canvas.renderAll(), (o, object) => { object.on('selected', () => { console.log(object.id); }); }); //canvas.setBackgroundImage('https://i.hizliresim.com/iBHC0t.jpg', canvas.renderAll.bind(canvas)); //var uniqid = "0"; var uniqids = 0; $("#door").on("click", function(e) { rect = new fabric.Rect({ id: uniqid, left: 40, top: 40, width: 35, height: 50, fill: 'blue', stroke: 'blue', strokeWidth: 5, strokeUniform: false, hasControls: true, }); var uniqid = uniqids.toString(); var text = new fabric.Text(uniqid, { fontSize: 30, originX: 'center', originY: 'right' }); var group = new fabric.Group([rect, text], { left: 0, top: 100, }); canvas.add(group); uniqids++; canvas.on('selection:cleared', c => { console.log("empty"); }); }); //***************************** canvas.on('mouse:wheel', function(opt) { var delta = opt.e.deltaY; var zoom = canvas.getZoom(); zoom *= 0.999 ** delta; if (zoom > 20) zoom = 20; if (zoom < 0.01) zoom = 0.01; canvas.setZoom(zoom); opt.e.preventDefault(); opt.e.stopPropagation(); }) $('#getid').click(function() { var activeObject = canvas.getActiveObjects(); alert(canvas.getActiveObject().id); }); //*************************************** $("#save").on("click", function(e) { $(".save").html(canvas.toSVG()); }); $('#delete').click(function() { var activeObject = canvas.getActiveObjects(); canvas.discardActiveObject(); canvas.remove(...activeObject); }); /* canvas.on('mouse:over', function(e) { e.target.set('fill', 'red'); canvas.renderAll(); }); canvas.on('mouse:out', function(e) { e.target.set('fill', 'green'); canvas.renderAll(); }); */ #c { background-color: grey; margin-top: 10px; } button { padding: 10px 20px; } <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.1.0/fabric.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <button id="door">Door</button> <button id="delete">Delete Door</button> <button id="save">Save</button> <button id="getid">GET ID</button> <p>Save bastıktan sonra altta SVG dosyası oluşur</p> <br> <canvas id="c" width="800" height="800"></canvas> <br> <p class="save"> </p>
You can listen to mouse:up and check if there is active object (canvas.getActiveObject()). If not, the point is empty. canvas.on('mouse:up', c => { if (!canvas.getActiveObject()) { console.log("empty"); } }); var canvas = new fabric.Canvas('c'); var json = '{"version":"3.1.0","objects":[{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":194,"top":157,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1047","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1047"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1047","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]},{"type":"group","version":"3.1.0","originX":"left","originY":"top","left":640,"top":473,"width":40,"height":80,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"id":"1048","objects":[{"type":"rect","version":"3.1.0","originX":"left","originY":"top","left":-20,"top":-15,"width":35,"height":50,"fill":"blue","stroke":"blue","strokeWidth":5,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"rx":0,"ry":0,"id":"1048"},{"type":"text","version":"3.1.0","originX":"center","originY":"top","left":0,"top":-40,"width":36,"height":20.34,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"white","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"text":"1048","fontSize":18,"fontWeight":"normal","fontFamily":"Quicksand","fontStyle":"normal","lineHeight":1.16,"underline":false,"overline":false,"linethrough":false,"textAlign":"left","textBackgroundColor":"","charSpacing":0,"styles":{}}]}],"backgroundImage":{"type":"image","version":"3.1.0","originX":"left","originY":"top","left":0,"top":0,"width":780,"height":646,"fill":"rgb(0,0,0)","stroke":null,"strokeWidth":0,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"clipTo":null,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","transformMatrix":null,"skewX":0,"skewY":0,"crossOrigin":"","cropX":0,"cropY":0,"src":"https://i1.wp.com/onideal.com/wp-content/uploads/2020/03/Schlafzimmer-Grundriss-ideale-Position-Bett-Moebel-Kleiderschrank-dreieckchen-4-780x646.jpg?fit=780%2C646&ssl=1","filters":[]}}' canvas.loadFromJSON(json, () => canvas.renderAll(), (o, object) => { object.on('selected', () => { console.log(object.id); }); }); //canvas.setBackgroundImage('https://i.hizliresim.com/iBHC0t.jpg', canvas.renderAll.bind(canvas)); //var uniqid = "0"; var uniqids = 0; $("#door").on("click", function(e) { rect = new fabric.Rect({ id: uniqid, left: 40, top: 40, width: 35, height: 50, fill: 'blue', stroke: 'blue', strokeWidth: 5, strokeUniform: false, hasControls: true, }); var uniqid = uniqids.toString(); var text = new fabric.Text(uniqid, { fontSize: 30, originX: 'center', originY: 'right' }); var group = new fabric.Group([rect, text], { left: 0, top: 100, }); canvas.add(group); uniqids++; }); //***************************** canvas.on('mouse:wheel', function(opt) { var delta = opt.e.deltaY; var zoom = canvas.getZoom(); zoom *= 0.999 ** delta; if (zoom > 20) zoom = 20; if (zoom < 0.01) zoom = 0.01; canvas.setZoom(zoom); opt.e.preventDefault(); opt.e.stopPropagation(); }).on('mouse:up', c => { if (!canvas.getActiveObject()) { console.log("empty"); } }); $('#getid').click(function() { var activeObject = canvas.getActiveObjects(); alert(canvas.getActiveObject().id); }); //*************************************** $("#save").on("click", function(e) { $(".save").html(canvas.toSVG()); }); $('#delete').click(function() { var activeObject = canvas.getActiveObjects(); canvas.discardActiveObject(); canvas.remove(...activeObject); }); /* canvas.on('mouse:over', function(e) { e.target.set('fill', 'red'); canvas.renderAll(); }); canvas.on('mouse:out', function(e) { e.target.set('fill', 'green'); canvas.renderAll(); }); */ #c { background-color: grey; margin-top: 10px; } button { padding: 10px 20px; } <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.1.0/fabric.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <button id="door">Door</button> <button id="delete">Delete Door</button> <button id="save">Save</button> <button id="getid">GET ID</button> <p>Save bastıktan sonra altta SVG dosyası oluşur</p> <br> <canvas id="c" width="800" height="800"></canvas> <br> <p class="save"> </p>
Create checkbox mecanism with Fabric JS
How can you create a checkbox like component with Fabric JS? More like to click on the image, and to set the opacity to 0. If you click again, to set the opacity to 1. Here is my code: For the checkbox image: fabric.Image.fromURL('https://image.flaticon.com/icons/svg/33/33281.svg', (image) => { image.scale(0.35); image.set({ left: 152, top: 120, hoverCursor: 'default', selectable: true, opacity: 0.5, hasControls: false, lockMovementX: true, lockMovementY: true }) if(image.onselect === true ) { image.set().opacity = 0; } canvas.add(image); }); The box where the image is put: function addBox(left, top, width, height) { const o = new fabric.Rect({ left: left, top: top, width: 30, height: 30, fill: boxFill, strokeWidth: 2, originX: 'left', originY: 'top', centeredRotation: true, snapAngle: 45, selectable: true, type: 'box', id: generateId() }) if(image.onselect === true ) { image.set().opacity = 0; } canvas.add(o) canvas.getObjects().map(o => { o.hasControls = false o.lockMovementX = true o.lockMovementY = true o.borderColor = '#38A62E' o.borderScaleFactor = 2.5 }) canvas.selection = false canvas.hoverCursor = 'pointer' canvas.discardActiveObject() canvas.renderAll() return o } How can I resolve this issue? Is there a way to make the image appear and dissapear when you click on it ( using opacity or something similarly) ?
Hope this helps you and many who want to add Event on objects. var canvas = new fabric.Canvas("canvas"); function drawCheckbox(left,right, width, height){ var imgClass = new fabric.Image.fromURL('https://image.flaticon.com/icons/svg/33/33281.svg',function(img){ img.width = width; img.height = height; img.left = left; img.top = right; img.hasControls = false img.on('mousedown', function(e) { if(e.target.opacity <= 0.5){ e.target.opacity = 1; }else{ e.target.opacity = 0.4; } canvas.renderAll(); }); canvas.add(img); canvas.renderAll(); }) } drawCheckbox(0,0, 100,100) drawCheckbox(100,100, 100,100) drawCheckbox(200,200, 100,100) body { background-color:silver; } canvas { border:1px solid red; } <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.3/fabric.min.js"> </script> <canvas id="canvas" width=300 height=300></canvas><br>
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 draw multiple lines that snap to a grid using Fabric.js
I am building a simple line drawing tool using FabricJs and canvas. Using the mouse someone can draw a line that follows grid lines. Like this picture: My goal is the restrict the line to be only drawn vertically, horizontally and diagonally following the grid. So far the lines don't stick to the grid, the lines can be draw freely on the canvas. See picture with red lines: I'm not sure how to implement that part, any help would be appreciated. Here is what I have so far. Thank you. var canvasA = new fabric.Canvas('a', { selection: false }); var grid = 30; // create grid //line var line, isDown; function createGrid(board) { for (var i = 0; i < (600 / grid); i++) { board.add(new fabric.Line([ i * grid, 0, i * grid, 600], { stroke: '#000', selectable: false })); board.add(new fabric.Line([ 0, i * grid, 600, i * grid], { stroke: '#000', selectable: false })) } } //create grids createGrid(canvasA); //handle line drawing drawLine(canvasA); function drawLine (board) { // add objects board.on('mouse:down', function(o){ isDown = true; var pointer = board.getPointer(o.e); var points = [ pointer.x, pointer.y, pointer.x, pointer.y ]; line = new fabric.Line(points, { strokeWidth: 2, fill: 'black', stroke: 'red', originX: 'center', originY: 'center', }); board.add(line); }); board.on('mouse:move', function(o){ if (!isDown) return; var pointer = board.getPointer(o.e); line.set({ x2: pointer.x, y2: pointer.y }); board.renderAll(); }); board.on('mouse:up', function(o){ isDown = false; }); } canvas{ background-color: transparent; margin: 3px; width: 120px; height: 240px; border: 2px solid #ccc; padding-left: 0; } .boards { display: inline; padding-left: 0; } .boards canvas { list-style: none; display: inline-block; background-color: transparent; margin: 3px; width: 120px; height: 240px; } <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script> <h1>Fabric Js Snap To grid </h1> <div class="boards"> <canvas id="a" width="120" height="240"></canvas>
You can find vertical lines using this if statement. if(Math.abs(line.x1 - line.x2) > Math.abs(line.y1 - line.y2)) And on mouse up remove board.remove(line); var canvasA = new fabric.Canvas('a', { selection: false }); var grid = 30; // create grid //line var line, isDown; function createGrid(board) { for (var i = 0; i < (600 / grid); i++) { board.add(new fabric.Line([ i * grid, 0, i * grid, 600], { stroke: '#000', selectable: false })); board.add(new fabric.Line([ 0, i * grid, 600, i * grid], { stroke: '#000', selectable: false })) } } //create grids createGrid(canvasA); //handle line drawing drawLine(canvasA); function drawLine (board) { // add objects board.on('mouse:down', function(o){ isDown = true; var pointer = board.getPointer(o.e); var points = [ pointer.x, pointer.y, pointer.x, pointer.y ]; line = new fabric.Line(points, { strokeWidth: 2, fill: 'black', stroke: 'red', originX: 'center', originY: 'center', }); board.add(line); }); board.on('mouse:move', function(o){ if (!isDown) return; var pointer = board.getPointer(o.e); line.set({ x2: pointer.x, y2: pointer.y }); board.renderAll(); }); board.on('mouse:up', function(o){ if(Math.abs(line.x1 - line.x2) > Math.abs(line.y1 - line.y2)) board.remove(line); isDown = false; }); } canvas{ background-color: transparent; margin: 3px; width: 120px; height: 240px; border: 2px solid #ccc; padding-left: 0; } .boards { display: inline; padding-left: 0; } .boards canvas { list-style: none; display: inline-block; background-color: transparent; margin: 3px; width: 120px; height: 240px; } <script type='text/javascript' src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.js"></script> <h1>Fabric Js Snap To grid </h1> <div class="boards"> <canvas id="a" width="120" height="240"></canvas>