I have the following situation: I draw the canvas with a background image and this works:
var canvasSection = new fabric.Canvas('buildSection', {
selectionColor: 'rgba(94,213,94,0.2)',
width: widthS,
height: heightS,
hoverCursor: 'pointer',
backgroundColor: ({
source: 'image/bordenconfigurator/background/background1.png',
repeat: 'repeat'
})
});
But then I need to clear canvas and to redraw it. at this point when I try to set background, instead of an image I see a black screen. In console I can see that the background image is set however. This is the code I'm trying:
$('#cForm').on('change', function() {
if ($(this).val() == 'rectLandsc') {
widthS = 600;
heightS = 400;
} else if ($(this).val() == 'rectPortr') {
....
}
canvasSection.clear();
canvasSection.set({
fill: 'rgba(0,0,0,0)',
// backgroundColor: ({source: 'image/bordenconfigurator/background/background1.png', repeat: 'repeat'})
});
//canvasSection.backgroundColor({source: 'image/bordenconfigurator/background/background.png', repeat:'repeat'});
canvasSection.setBackgroundColor({
source: 'image/bordenconfigurator/background/background.png'
}),
canvasSection.renderAll.bind(canvas);
drawBaseForm();
canvasSection.renderAll();
console.log(canvasSection);
});
Is it a kind of a bug? Or am I doing something wrong? Could anyone help me out here?
canvas.setBackgroundColor({
source: 'image/bordenconfigurator/background/background1.png',
repeat: 'repeat'
}, canvas.renderAll.bind(canvas));
setBackgroundColor first parameter is color/pattern and second parameter is callback function.
DEMO
var canvas = new fabric.Canvas('c');
canvas.setBackgroundColor({
source: 'http://fabricjs.com/assets/pug_small.jpg'
}, canvas.renderAll.bind(canvas));
function clearCanvas(){
var background = canvas.backgroundColor;
canvas.clear();
setTimeout(function(){
canvas.setBackgroundColor(background,canvas.renderAll.bind(canvas));
},2000)
}
canvas{
border: 2px dotted black;
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<button onclick='clearCanvas()'>clear</button>
<canvas id="c" width="500" height="500"></canvas>
Related
I tried to add a spritesheet to my Phaser game the same way I've done it a few times before, however this time it seems to not load the images correctly, causing it to display a black & green square instead and causing it to throw an error when trying to play an animation.
Can anyone tell what is causing this issue?
(Warning: Playing the Code here seems to freeze up your browser for a few seconds, alternatively view on JSFiddle: https://jsfiddle.net/cak3goru/4/ )
// Configs and Constants
const gameState = {
gameWidth: 800,
gameHeight: 800,
textStyle: {
fontFamily: "'Comic Sans MS'",
fill: "#fff",
align: "center",
boundsAlignH: "left",
boundsAlignV: "top"
},
mouseDown: false,
menu: {
options: [
"Feed", "Clean", "Play"
],
barColor: "0x123456",
items: [],
itemText: [],
itemColor: "0x654321",
}
};
function preload() {
// Clean Tools
this.load.atlas('clean', 'https://gaylie.neocities.org/game/assets/clean.png', 'https://gaylie.neocities.org/game/assets/clean.json');
}
function create () {
this.anims.create({
key: "shower_cursor",
framerate: 12,
frames: this.anims.generateFrameNumbers("clean", {
prefix: "showerhead_000",
start: 0,
end: 7}),
repeat: -1
});
gameState.shower_cursor = this.add.sprite(400,400,'shower_cursor');
console.log(gameState.shower_cursor.frame);
//gameState.shower_cursor.playAfterDelay('shower_cursor', 100);
//gameState.shower_cursor.alpha = 0;
}
var config = {
backgroundColor: "0xf0f0f0",
scale: {
width: gameState.gameWidth,
height: gameState.gameHeight,
autoCenter: Phaser.Scale.CENTER_BOTH
},
scene: {
preload, create
}
};
var game = new Phaser.Game(config);
<head>
<title>Pet Simulator</title>
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
</head>
<body style="height: 100%; width: 100%; margin: 0;">
</body>
The problem is, that you are using the wrong function, you should use this.anims.generateFrameNames, and not this.anims.generateFrameNumbers.
And set the correct key clean for the sprite.
the line should be:
gameState.shower_cursor = this.add.sprite(200, 100, 'clean');
because shower_cursor, is only the key of the animation, not the key of the sprite.
P.s.: the posted code doesn't run on jsfiddler or Stackoverflow due to CORS-Error, but if all assets are on the same server, it should not be a problem.
Referring to the code below, I can drag the red line back and forth within the canvas box and have it stop at the left limit. But the line doesn't stop at the right limit - it disappears beyond the box and reappears if I drag left. I have looked at fabricjs demos (Standalone Controls, PerPixel Drag and Drop, Stickman) and notice that it is possible to drag objects "out of sight" in a similar manner. Is this a characteristic of fabricjs, or is there some way I can fix my code so that the red line cannot be dragged beyond the right limit?
var canvas = new fabric.Canvas('cnvs');
var leftLimit = 20;
var rightLimit = 400;
var redLine = new fabric.Line([leftLimit, 0, leftLimit, canvas.height], {
stroke: 'red',
strokeWidth: 2,
borderColor: 'white',
hasControls: false
});
canvas.add(redLine);
canvas.renderAll();
canvas.on('object:moving', function(e) {
redLine = e.target;
redLine.set({
top: 0
});
if (redLine.left < leftLimit) {
redLine.set({
left: leftLimit
});
}
if (redLine > rightLimit) {
redLine.set({
left: rightLimit
});
}
canvas.renderAll();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.js"></script>
<canvas id="cnvs" width="500" height="200" style="border:1px solid #000000"></canvas>
I'm not sure if you made a typo or not, but (redLine > rightLimit) makes no sense. You should compare left:
if (redLine.left > rightLimit) {
redLine.set({ left: rightLimit });
}
Or, since your line has some width to it, you can make it stop without ever overlapping the boundary:
if (redLine.left + redLine.strokeWidth > rightLimit) {
redLine.set({ left: rightLimit - redLine.strokeWidth });
}
I'm developing a diagram tool based on fabricjs. Our tool has our own collection of shape, which is svg based. My problem is when I scale the object, the border (stroke) scale as well. My question is: How can I scale the object but keep the stroke width fixed. Please check the attachments.
Thank you very much!
Here is an easy example where on scale of an object we keep a reference to the original stroke and calculate a new stroke based on the scale.
var canvas = new fabric.Canvas('c', { selection: false, preserveObjectStacking:true });
window.canvas = canvas;
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa',
originX: 'left',
originY: 'top',
stroke: "#000",
strokeWidth: 1,
centeredRotation: true
}));
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<canvas id="c" width="600" height="600"></canvas>
There is a property called: strokeUniform
Use it like this
shape.set({stroke: '#f55b76', strokeWidth:2, strokeUniform: true })
I have found what feels like an even better solution, works really well with SVG paths.
You can override fabricjs' _renderStroke method and add ctx.scale(1 / this.scaleX, 1 / this.scaleY); before ctx.stroke(); as shown below.
fabric.Object.prototype._renderStroke = function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
this._applyPatternGradientTransform(ctx, this.stroke);
ctx.stroke();
ctx.restore();
};
You may also need to override fabric.Object.prototype._getTransformedDimensions to adjust the bounding box to account for the difference in size.
Also a more complete implementation would probably add a fabric object property to conditionally control this change for both overridden methods.
Another way is to draw a new object on scaled and remove the scaled one.
object.on({
scaled: function()
{
// store new widht and height
var new_width = this.getScaledWidth();
var new_height = this.getScaledHeight();
// remove object from canvas
canvas.remove(this);
// add new object with same size and original options like strokeWidth
canvas.add(new ...);
}
});
Works perfect for me.
I have loaded a SVG on the canvas. Everything works, but I have difficulties to address the object.
Here is the code:
fabric.loadSVGFromURL("images/Achse3.svg",function(objects)
{
var achse1 = new fabric.PathGroup(objects, {
left: 127,
top: 70,
opacity: 0.5,
scaleX: 1.25,
scaleY: 1.25
});
canvas.add(achse1);
//canvas.renderAll();
});
I tried to address the SVG via canvas.item, but the results are very strange. Depending on the value in the sample:
canvas.item(11).set('top',this.value);
The items change. How can I address the item I loaded. I tried it with
canvas.achse1.set('top',this.value);
But this is not working.
Since you have a reference to your PathGroup, you have just to set the related properties of it.
Try yourself the runnable snippet below if it meets your needs.
var canvas = new fabric.Canvas('c'), svg_group;
fabric.loadSVGFromURL("https://upload.wikimedia.org/wikipedia/commons/a/a9/Olympic_rings_with_white_rims.svg", function(objects) {
svg_group = new fabric.PathGroup(objects, {
left: 0,
top: 0,
opacity: 1,
scaleX: .1,
scaleY: .1
});
canvas.add(svg_group);
$('#b').on('click', () => {
svg_group.set('top', 100);
canvas.renderAll();
})
});
canvas {
border: 1px dashed #333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='c' width=300 height=150></canvas>
<button id='b'>move it</button>
Found the problem. I used VAR to declare the variable within the loadSVG function. So the variable was just local within the function. The declaration without VAR did the job. Now the variable is global and can be addressed from outside the function.
I had loaded image in canvas using fabric.Image.fromURL and working fine with default image width and height.
Now I want to minimize width and height of an image.
How to do this?
Thanks in advance.
Hope this will help
var src; //Image source here
fabric.Image.fromURL(src, function(oImg) {
oImg.scaleToWidth(50);
oImg.scaleToHeight(50);
});
We can use scalex / scaley to set height / width as below.
fabric.util.loadImage(imgsrc, function (img) {
var legimg = new fabric.Image(img, {
left: 30,
top: marker.top,
scaleX: 20 / img.width,
scaleY: 20 / img.height
});
canvas.add(legimg);
canvas.renderAll();
});
Thanks
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 0, top: 0, angle: 00,width:100, height:100}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
canvas{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="450" height="450"></canvas>
We can set width and height.
Check this JSfiddle: https://jsfiddle.net/varunPes/8gt6d7op/5/
This working code I have tested:
fabric.Image.fromURL(el.src, function(image) {
image.set({
left: left,
top: top,
angle: 0,
padding: 10,
cornersize: 10,
hasRotatingPoint:true
});
image.scaleToHeight(100);
image.scaleToWidth(200);
canvas.add(image);
});
Work with the image scale properties and not the image size. This worked for me. When I had set the image width and height, and not the scale, when I applied a filter it reset back to original width and height because the scale was 1.0. Hope this helps.
Well I am not sure how are you trying to do it but you could while
adding the image use canvas object in the editor and pass it the Image
in a function called centerObject. Here is the code that worked for
me.
My ReactJS code centers a shirt image in the canvas as given below
const { editor, onReady } = useFabricJSEditor()
const add_image = () => {
fabric.Image.fromURL('assets/custom/shirt_green.png',(oImg) => {
oImg.scaleToHeight(240)
oImg.scaleToWidth(240)
editor.canvas.add(oImg)
editor.canvas.centerObject(oImg)
})
}
Over to the frontend UI we render using
<div>
<FabricJSCanvas className={styles.canvas} onReady={onReady} />
</div>