Unable to add an image to fabric js group - javascript

Hello i am trying to add an image to a group of circle and text, and finally add the group to the canvas but it is failling to show the image.
Can anyone tell me what is the problem ?
Here is the snippets
const canvas = new fabric.Canvas('canvas', {
selection: false
});
const circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50,
fill: '#eef',
originX: 'center',
originY: 'center'
});
const img = new Image();
img.src = '/Content/assets/img/logo.png';
const newImage = new fabric.Image(img, {
left: circle.left + 15,
top: circle.top,
perPixelTargetFind: true,
padding: 2,
hasBorders: false,
hasControls: false,
width: 20,
height: 30,
originX: 'center',
originY: 'center',
});
const text = new fabric.Text('Hello World', {
left: circle.left,
top: circle.top,
fontFamily: 'Arial',
fontWeight: 'bold',
fontSize: 10,
fill: 'black',
originX: 'center',
originY: 'center',
});
const group = new fabric.Group([circle, text, newImage], {
left: circle.left,
top: circle.top,
originX: 'center',
originY: 'center'
});
canvas.add(group);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
<canvas id="canvas" width="500" height="300" style="border: 2px solid green;"></canvas>

Because you are passing the image object instead of the source. Do this
fabric.Image.fromURL('http://placekitten.com/200/300', function(img) {
canvas.add(img1);
});
const canvas = new fabric.Canvas('canvas', {
selection: false
});
fabric.Image.fromURL('http://placekitten.com/200/300', function(img) {
var img1 = img.set({ left: 0, top: 0 ,width:200, height:350});
canvas.add(img1);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
<canvas id="canvas" width="500" height="300" style="border: 2px solid green;"></canvas>
new fabric.Image(img, here img should be a string. Not an Image instance
To add that image in the group, do
let ImageInstance;
fabric.Image.fromURL('http://placekitten.com/200/300', function(img) {
var img1 = img.set({ left: 0, top: 0 ,width:200, height:350});
ImageInstance = img1;
});
if (ImageInstance){
const group = new fabric.Group([circle, text, ImageInstance], {
left: circle.left,
top: circle.top,
originX: 'center',
originY: 'center'
});
canvas.add(group);
}

Related

fabric.js How to draw a straight line with arrows, and the end of the line can be dragged

I want to draw a polyline:
With arrows
With endpoint control, you can drag and drop, and you will be able to connect with other objects in the future (I don’t know whether to use fabric.js Control or draw a circle by myself)
My current implementation is like this: The line consists of 5 parts:
Two endpoints + two arrows + line body.
When dragging the end point, the arrow position, the arrow angle, and the coordinates of the line body are synchronously modified.
this is demo fabric.PolygonalLine is the key to the problem
var canvas = new fabric.Canvas(document.getElementById("c"))
fabric.PolygonalLine = fabric.util.createClass(fabric.Object, {
// hasControls: false,
// hasBorders: false,
// selectable: true,
points: [],
sControl: null,
eControl: null,
centerControl: null,
// 垂直方向或者水平方向
controlMoveDirection: "",
sArrow: null,
eArrow: null,
initialize: function (points, options = {}) {
this.points = points || []
this.callSuper("initialize", options)
let len = this.points.length
let defaultOpt = {
hasBorders: false,
hasControls: false,
originX: "center",
originY: "center",
}
this.sControl = new fabric.Circle({
fill: null,
radius: 4,
strokeWidth: 1,
stroke: "rgba(57, 87, 239, 0.8)",
left: this.points[0].x,
top: this.points[0].y - 8,
...defaultOpt,
})
this.eControl = new fabric.Circle({
fill: null,
radius: 4,
strokeWidth: 1,
stroke: "rgba(57, 87, 239, 0.8)",
left: this.points[len - 1].x,
top: this.points[len - 1].y + 8,
...defaultOpt,
})
this.sArrow = new fabric.Triangle({
left: this.points[0].x,
top: this.points[0].y,
width: 10,
height: 10,
// selectable: false,
lockMovementX: true,
lockMovementY: true,
...defaultOpt,
})
this.eArrow = new fabric.Triangle({
left: this.points[len - 1].x,
top: this.points[len - 1].y,
width: 10,
height: 10,
angle: 180,
// selectable: false,
lockMovementX: true,
lockMovementY: true,
...defaultOpt,
})
canvas.add(this.sArrow, this.eArrow, this.sControl, this.eControl)
this._bindEvents()
},
_bindEvents() {
this.sControl.on("moving", (e) => {
this.sArrow.set({
left: e.pointer.x,
top: e.pointer.y + 8,
})
this.points[0].x = e.pointer.x
this.points[0].y = e.pointer.y
this.points[1].x = e.pointer.x
canvas.requestRenderAll()
})
this.eControl.on("moving", (e) => {
this.eArrow.set({
left: e.pointer.x,
top: e.pointer.y - 8,
})
this.points[3].x = e.pointer.x
this.points[3].y = e.pointer.y
this.points[2].x = e.pointer.x
canvas.requestRenderAll()
})
this.sControl.on("selected", (e) => {
console.log("---106-11-selected---", this)
})
this.on("selected", (e) => {
console.log("---106---selected--", e)
})
this.on("moving", (e) => {
console.log("---110--moving---", e)
})
},
render(ctx) {
ctx.save()
ctx.beginPath()
ctx.moveTo(this.points[0].x, this.points[0].y)
for (let i = 0; i < this.points.length - 1; i++) {
let point = this.points[i]
ctx.lineTo(point.x, point.y)
}
ctx.lineTo(this.points[3].x, this.points[3].y)
ctx.stroke()
ctx.restore()
},
})
// ---------------------------content---------------------
let rect = new fabric.Rect({
width: 50,
height: 50,
left: 10,
top: 5,
fill: "rgba(255,0,0,0.5)",
})
let circle = new fabric.Circle({
width: 50,
height: 50,
radius: 25,
left: 200,
top: 205,
fill: "#aac",
})
let line = new fabric.PolygonalLine(
[
{
x: 35,
y: 70,
},
{
x: 35,
y: 120,
},
{
x: 225,
y: 120,
},
{
x: 225,
y: 190,
},
],
{
text: "",
stroke: "red",
strokeWidth: 2,
strokeLineCap: "butt",
strokeDashArray: [10, 5],
}
)
canvas.add(rect, circle, line)
canvas.zoomToPoint({ x: 0, y: 0 }, 2)
canvas.renderAll()
canvas {
border: 1px solid #999;
display:inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/460/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
But it feels awkward to do so. Does any friend have a better way? Or provide an idea. Grateful.

FabricJS canvas objects group is being hidden when adding its clone to another canvas

I try to export a group of objects from a canvas to svg. To do so, I clone the group in another canvas (which will have the same height/width of the group).It works very well. But the problem is the group becomes hidden in the original canvas, I don't know why.
here is the code:
this.__canvas = new fabric.Canvas('meCanvas', {
preserveObjectStacking: true,
height: 300,
width: 200,
backgroundColor: '#1F1F1F',
canvasKey:'azpoazpoaz'
});
let newID = (new Date()).getTime().toString().substr(5);
let rect = new fabric.Rect({
fill: 'red',
width: 48,
height: 32,
left: 100,
top: 100,
originX: 'center',
originY: 'center',
fontWeight: 'normal',
myid: newID
});
let newID1 = (new Date()).getTime().toString().substr(5);
let text = new fabric.IText('Text', {
fontFamily: 'Times',
fontSize: 18,
fill: 'white',
left: 100,
top: 100,
originX: 'center',
originY: 'center',
fontWeight: 'normal',
myid: newID1,
objecttype: 'text'
});
this.__canvas.add(rect);
this.__canvas.add(text);
this.__canvas.renderAll();
$('#generate').click((e)=>{
let obj = this.__canvas.getActiveObject();
if(!obj) return;
let obj1 = $.extend(true, {}, obj);
this.tempCanvas = new fabric.Canvas('tempCanvas', {
canvasKey:'efsdfsd',
preserveObjectStacking: true,
height: obj1.getScaledHeight(),
width: obj1.getScaledWidth()
});
obj1.left= 0;
obj1.top=0;
this.tempCanvas.add(obj1);
let mySVG = this.tempCanvas.toSVG();
//console.log(this.tempCanvas.toSVG());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<div style='display: inline-block'>
<div>
<canvas id='meCanvas' ref='meFabric'/>
</div>
<div>
<button id='generate'>Generate the SVG</button>
</div>
<div style='display: inline-block'>
<div id="rect"></div>
<div id="recttext"></div>
</div>
</div>
If you select both the text and the red rectangle at once, and then click on the button "Generate the SVG", and then click on the canvas again, the group will disappear. And I don't know why.
Please how to fix it ?
To copy an object use obj.clone() instead of $.extend
EXAMPLE
this.__canvas = new fabric.Canvas('meCanvas', {
preserveObjectStacking: true,
height: 300,
width: 200,
backgroundColor: '#1F1F1F',
canvasKey: 'azpoazpoaz'
});
let newID = (new Date()).getTime().toString().substr(5);
let rect = new fabric.Rect({
fill: 'red',
width: 48,
height: 32,
left: 100,
top: 100,
originX: 'center',
originY: 'center',
fontWeight: 'normal',
myid: newID
});
let newID1 = (new Date()).getTime().toString().substr(5);
let text = new fabric.IText('Text', {
fontFamily: 'Times',
fontSize: 18,
fill: 'white',
left: 100,
top: 100,
originX: 'center',
originY: 'center',
fontWeight: 'normal',
myid: newID1,
objecttype: 'text'
});
this.__canvas.add(rect);
this.__canvas.add(text);
this.__canvas.renderAll();
$('#generate').click((e) => {
let obj = this.__canvas.getActiveObject();
if (!obj) return;
obj.clone(function(clonedObj) {
let obj1 = clonedObj;
this.tempCanvas = new fabric.Canvas('tempCanvas', {
canvasKey: 'efsdfsd',
preserveObjectStacking: true,
height: obj.getScaledHeight(),
width: obj.getScaledWidth()
});
obj1.left = 0;
obj1.top = 0;
this.tempCanvas.add(obj1);
let mySVG = this.tempCanvas.toSVG();
})
//console.log(this.tempCanvas.toSVG());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>
<div style='display: inline-block'>
<div>
<canvas id='meCanvas' ref='meFabric'/>
</div>
<div>
<button id='generate'>Generate the SVG</button>
</div>
<div style='display: inline-block'>
<div id="rect"></div>
<div id="recttext"></div>
</div>
</div>

Image shrink resizing using fabric js

I am using fabric js. After editing and saving Image it is shrinking in canvas and loosing quality.
This is code using while saving and sending through ajax call.
c.discardActiveGroup().renderAll();
var objs = c.getObjects().map(function(o) {
return o.set({'active': false, hasBorders: false});
});
var group = new fabric.Group(objs, {
originX: 'center',
originY: 'center',
strokeWidth : 0
});
var cloneGroup = new fabric.Group(objs, {
originX: 'center',
originY: 'center',
strokeWidth : 0
});
cloneGroup.scaleToWidth(imgWidth-1);
var dataURL = cloneGroup.toDataURL({
format: 'png',
left: 1,
top: 1,
width: imgWidth,
height: imgHeight
});
saveAjaxCall(dataURL, flagBit);
group._restoreObjectsState();
c.remove(cloneGroup);
c.renderAll();

Fabric JS: Copy/paste object on mouse down

I'm trying to create a block game where you select shapes from a menu and place them on the canvas. There is a shape menu where you can drag the shapes onto the canvas. I would like for it to leave the main shape in the menu as it drags a clone onto the canvas. Is this possible? I have created a jsfiddle to help.
JSFIDDLE
window.canvas = new fabric.Canvas('fabriccanvas');
var edgedetection = 10; //pixels to snap
canvas.selection = false;
window.addEventListener('resize', resizeCanvas, false);
function resizeCanvas() {
canvas.setHeight(window.innerHeight);
canvas.setWidth(window.innerWidth);
canvas.renderAll();
}
// resize on init
resizeCanvas();
//Initialize Everything
init();
function init(top, left, width, height, fill) {
var bg = new fabric.Rect({
left: 0,
top: 0,
fill: "#eee",
width: window.innerWidth,
height: 75,
lockRotation: true,
maxHeight: document.getElementById("fabriccanvas").height,
maxWidth: document.getElementById("fabriccanvas").width,
selectable: false,
});
var squareBtn = new fabric.Rect({
top: 6,
left: 18,
width: 40,
height: 40,
fill: '#af3',
lockRotation: true,
originX: 'left',
originY: 'top',
cornerSize: 15,
hasRotatingPoint: false,
perPixelTargetFind: true,
});
var circleBtn = new fabric.Circle({
radius: 20,
fill: '#f55',
top: 6,
left: 105,
});
var triangleBtn = new fabric.Triangle({
width: 40,
height: 35,
fill: 'blue',
top: 10,
left: 190,
});
var sqrText = new fabric.IText("Add Square", {
fontFamily: 'Indie Flower',
fontSize: 14,
fontWeight: 'bold',
left: 6,
top: 50,
selectable: false,
});
var cirText = new fabric.IText("Add Circle", {
fontFamily: 'Indie Flower',
fontSize: 14,
fontWeight: 'bold',
left: 95,
top: 50,
selectable: false,
});
var triText = new fabric.IText("Add Triangle", {
fontFamily: 'Indie Flower',
fontSize: 14,
fontWeight: 'bold',
left: 175,
top: 50,
selectable: false,
});
var shadow = {
color: 'rgba(0,0,0,0.6)',
blur: 3,
offsetX: 0,
offsetY: 2,
opacity: 0.6,
fillShadow: true,
strokeShadow: true
}
window.canvas.add(bg);
bg.setShadow(shadow);
window.canvas.add(sqrText);
window.canvas.add(cirText);
window.canvas.add(triText);
window.canvas.add(squareBtn);
window.canvas.add(circleBtn);
window.canvas.add(triangleBtn);
canvas.forEachObject(function (e) {
e.hasControls = e.hasBorders = false; //remove borders/controls
});
this.canvas.on('object:moving', function (e) {
var obj = e.target;
obj.setCoords(); //Sets corner position coordinates based on current angle, width and height
canvas.forEachObject(function (targ) {
activeObject = canvas.getActiveObject();
if (targ === activeObject) return;
if (Math.abs(activeObject.oCoords.tr.x - targ.oCoords.tl.x) < edgedetection) {
activeObject.left = targ.left - activeObject.currentWidth;
}
if (Math.abs(activeObject.oCoords.tl.x - targ.oCoords.tr.x) < edgedetection) {
activeObject.left = targ.left + targ.currentWidth;
}
if (Math.abs(activeObject.oCoords.br.y - targ.oCoords.tr.y) < edgedetection) {
activeObject.top = targ.top - activeObject.currentHeight;
}
if (Math.abs(targ.oCoords.br.y - activeObject.oCoords.tr.y) < edgedetection) {
activeObject.top = targ.top + targ.currentHeight;
}
if (activeObject.intersectsWithObject(targ) && targ.intersectsWithObject(activeObject)) {
} else {
targ.strokeWidth = 0;
targ.stroke = false;
}
if (!activeObject.intersectsWithObject(targ)) {
activeObject.strokeWidth = 0;
activeObject.stroke = false;
activeObject === targ
}
});
});
}
See Jsfiddle here, I add the function to do this.
function draggable(object) {
object.on('mousedown', function() {
var temp = this.clone();
temp.set({
hasControls: false,
hasBorders: false,
});
canvas.add(temp);
draggable(temp);
});
object.on('mouseup', function() {
// Remove an event handler
this.off('mousedown');
// Comment this will let the clone object able to be removed by drag it to menu bar
// this.off('mouseup');
// Remove the object if its position is in menu bar
if(this.top<=75) {
canvas.remove(this);
}
});
}
draggable(squareBtn);
draggable(circleBtn);
draggable(triangleBtn);

KineticJS: How to scale the radius of a Group in Tween?

I'm trying to make a tween which makes a ball bigger and disappear from the screen. It's easy if you do it for a circle.
Tween for only circle: http://jsfiddle.net/VrUB6/
Code:(it won't let me paste only the link):
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 500
});
var layer = new Kinetic.Layer();
var circle = new Kinetic.Circle({
x: 100,
y: 100,
radius: 30,
fillRadialGradientStartPoint: 0,
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: 0,
fillRadialGradientEndRadius: 90,
fillRadialGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'black',
strokeWidth: 0.4,
opacity: 1
});
layer.add(circle);
stage.add(layer);
circle.on('mousedown', function(){
var tween = new Kinetic.Tween({
node: circle,
duration: 0.8,
radius: 80,
opacity: 0,
});
tween.play();
});
But what I want to do is, same tween like this, but a text in the circle. For this I have to create a group, add circle and text in it and then tween the group(I guess). But if I do this, I can't change the radius in tween. It won't work.
Here is my work for it: http://jsfiddle.net/N2J2u/
Code:
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 500
});
var layer = new Kinetic.Layer();
var circ = new Kinetic.Circle({
x: 100,
y: 100,
radius: 30,
fillRadialGradientStartPoint: 0,
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: 0,
fillRadialGradientEndRadius: 90,
fillRadialGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'black',
strokeWidth: 0.4,
opacity: 1
});
var group = new Kinetic.Group({
draggable: true,
});
group.add(circ);
var complexText = new Kinetic.Text({
x: 97,
y: 90,
text: '4',
fontSize: 30,
fontFamily: 'Calibri',
fill: '#555',
padding: -5,
align: 'center'
});
group.add(complexText);
layer.add(group);
stage.add(layer);
group.on('mousedown', function(){
var tween = new Kinetic.Tween({
node: group,
duration: 0.8,
radius: 80,
opacity: 0,
});
// start tween after 20 seconds
setTimeout(function() {
tween.play();
});
});
Thanks for the help.
Set up multiple tweens where the circle expands+fades and the number fades:
group.on('mousedown', function(){
var tweenCirc = new Kinetic.Tween({
node: circ,
duration: 0.8,
width: 80,
opacity: 0,
});
var tweenComplexText = new Kinetic.Tween({
node: complexText,
duration: 0.8,
opacity: 0,
});
// start tween after 20 seconds
setTimeout(function() {
tweenCirc.play();
tweenComplexText.play();
});
});
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/dvfr2/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.4.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 500
});
var layer = new Kinetic.Layer();
stage.add(layer);
var group = new Kinetic.Group({ draggable: true });
layer.add(group);
var circ = new Kinetic.Circle({
x: 100,
y: 100,
radius: 30,
fillRadialGradientStartPoint: 0,
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: 0,
fillRadialGradientEndRadius: 90,
fillRadialGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'black',
strokeWidth: 0.4,
opacity: 1
});
group.add(circ);
var complexText = new Kinetic.Text({
x: 97,
y: 90,
text: '4',
fontSize: 30,
fontFamily: 'Calibri',
fill: '#555',
padding: -5,
align: 'center'
});
group.add(complexText);
group.on('mousedown', function(){
var tweenCirc = new Kinetic.Tween({
node: circ,
duration: 0.8,
width: 80,
opacity: 0,
});
var tweenComplexText = new Kinetic.Tween({
node: complexText,
duration: 0.8,
opacity: 0,
});
// start tween after 20 seconds
setTimeout(function() {
tweenCirc.play();
tweenComplexText.play();
});
});
layer.draw();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Categories

Resources