I have few elements (triangles) and I want to be able to highlight(setShadow) them as I hover above each one (mouse:over/mouse:move), and reset highlight when mouse not over.
I tried this, but it doesn't do anything. Below is my code:
var canvas = new fabric.Canvas('canvas');
var petal1 = new fabric.Triangle({
width: 200,
height: 300,
fill: '#DBDBDB',
left: 500,
top: 350,
angle: 200,
strokeLineJoin: 'round',
strokeWidth: 20,
stroke: '#DBDBDB'
});
var petal2 = new fabric.Triangle({
// same options as above
});
var petal3 = new fabric.Triangle({
// same options as above
});
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();
});
canvas.add(petal1, petal2, petal3);
I added console.log(e.target);, but it printed nothing.
Your snippet works and check target before setting property to it.
DEMO
var canvas = new fabric.Canvas('canvas');
var options = {
width: 100,
height: 200,
fill: '#DBDBDB',
strokeLineJoin: 'round',
strokeWidth: 20,
stroke: '#DBDBDB'
};
var petal1 = new fabric.Triangle(options);
var petal2 = new fabric.Triangle(options);
var petal3 = new fabric.Triangle(options);
canvas.on('mouse:over', function(e) {
if(e.target){
e.target.set('fill', 'red');
canvas.requestRenderAll();
}
});
canvas.on('mouse:out', function(e) {
if(e.target){
e.target.set('fill', 'green');
canvas.requestRenderAll();
}
});
canvas.add(petal1, petal2, petal3);
canvas{
border:1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.js"></script>
<canvas id="canvas" width="300" height="300"></canvas>
Related
I want to display an path in Fabric.JS, in svg file:
<g>
<path style="fill:none;stroke:#000000;stroke-miterlimit:10;"
d="M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72"/>
</g>
And code in my Fabricjs
var Path_0_1 = new fabric.Path('M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
fill: 'none',
stroke: '#000000',
strokeMiterLimit: 10,
opacity: 1,
});
But result is not same:
Expected:
Path in FabricJS display same as in SVG file.
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()
});
var Path_0_1 = new fabric.Path('M221.58-0.55 c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
// fill : 'none',
stroke: '#000000',
strokeMiterLimit: 10,
opacity: 1,
});
canvas.add(Path_0_1);
canvas.moveTo(Path_0_1, 1);
setObjectCoords();
canvas.renderAll();
function setObjectCoords() {
canvas.forEachObject(function(object) {
object.setCoords();
});
}
#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>
And here is my svg file:
https://svgur.com/s/Bw6
Set fill value '' || null || 'transparent', so on ctx.fill() it wont fill anything to the object.
DEMO
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', {
selectionLineWidth: 2,
width: $("#canvasContainer").width(),
height: $("#canvasContainer").height()
});
var Path_0_1 = new fabric.Path('M221.58-0.55c17.5,31.22,4.77,57.16-8.14,88.46c-13.75,33.35,0.71,57.72,0.71,57.72', {
fill : null,
stroke: '#000000',
});
canvas.add(Path_0_1);
#canvasContainer {
width: 100%;
height: 100vh;
}
<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>
Is there a way of adding e.g. circles or boxes to the html5 canvas by using konva.js? i tried it but somehow it doesn't work! What i want it e.g. one click is adding a circle with drag and drop, a doubleclick removes the circle.
This is how it works, maybe someone can use it!
$( document ).ready(function() {
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var colors = ["red", "orange", "yellow", "green", "blue", "purple"];
var rect1 = new Konva.Rect({
x: 25,
y: 25,
width: width-50,
height: height-50,
opacity: 1,
fill: 'green',
stroke: 'black',
strokeWidth: 2
});
var circle = new Konva.Circle({
x: 230,
y: 100,
radius: 30,
fill: 'grey',
stroke: 'black',
strokeWidth: 1,
draggable: true,
id: 'Origin'
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
circle.on("dragstart", function () {
this.moveToTop();
layer.draw();
});
circle.on("dragmove", function () {
document.body.style.cursor = "pointer";
});
circle.on("dblclick dbltap", function (evt) {
evt.cancelBubble = true;
console.log("item dblclick");
this.destroy();
layer.draw();
});
circle.on("click tap", function (evt) {
evt.cancelBubble = true;
var node = evt.target;
if (node) {
// update tooltip
var mousePos = node.getStage().getPointerPosition();
console.log("item normal click " + node.getId() + " > node-x" + node.x() +" - fill " + node.getFill());
}
});
rect1.on('dblclick', function() {
var clone;
clone = circle.clone({
x:stage.getPointerPosition().x,
y:stage.getPointerPosition().y,
id: 'myCircle'
});
layer.add(clone);
layer.draw();
console.log('content click on rect1 ' + JSON.stringify(stage.getPointerPosition()));
});
circle.on("mouseover", function () {
document.body.style.cursor = "pointer";
});
circle.on("mouseout", function () {
document.body.style.cursor = "default";
});
layer.add(rect1);
layer.add(circle);
stage.add(layer);
});
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<script src="https://cdn.rawgit.com/konvajs/konva/1.7.6/konva.min.js"></script>
<script
src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<meta charset="utf-8">
<title>Add/Remove</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
</style>
</head>
<body>
<div id="container"></div>
</body>
</html>
Why this clipTo method doesn't work on the latest fabricjs version, which you could resize the object container and the image inside it. Also you able to move the container object and image object.
var imgInstance = new fabric.Image(img, {
width: instanceWidth,
height: instanceHeight,
top: (canvas.getHeight() / 2 - instanceHeight / 2),
left: (canvas.getWidth() / 2 - instanceWidth / 2),
originX: 'left',
originY: 'top'
});
canvas.add(imgInstance);
imgInstance.clipTo = function(ctx) {
/* image clipping method doesn't work on latest fabricjs version*/
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clippingRect.render(ctx);
ctx.restore();
};
http://jsfiddle.net/efmbrm4v/2/
Or is their another approach shape object inside is the image object.
There is some caching issue with the latest version of FabricJS. To get around that, you need to set objectCaching property to false for the rectangle object.
$(document).ready(function() {
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
});
var canvas = new fabric.Canvas('myCanvas');
var clippingRect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: 'transparent',
opacity: 1,
objectCaching: false //<-- set this
});
canvas.add(clippingRect);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function(event) {
var img = new Image();
img.onload = function() {
var instanceWidth, instanceHeight;
instanceWidth = img.width;
instanceHeight = img.height;
var imgInstance = new fabric.Image(img, {
width: instanceWidth,
height: instanceHeight,
top: (canvas.getHeight() / 2 - instanceHeight / 2),
left: (canvas.getWidth() / 2 - instanceWidth / 2),
originX: 'left',
originY: 'top'
});
canvas.add(imgInstance);
imgInstance.clipTo = function(ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clippingRect.render(ctx);
ctx.restore();
};
canvas.renderAll();
};
img.src = event.target.result;
};
reader.readAsDataURL(e.target.files[0]);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<canvas id="myCanvas" width="400" height="300" style="border: 1px solid black"></canvas>
<br />
<label>Choose a File:</label>
<br/>
<br />
<input type="file" id="imageLoader" name="imageLoader" />
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
In my code I created method to clip images using fabric shapes. I have used stackoverflow answer for achieving this. Somehow after using this method I cannot render the canvas using default fabric canvas render method.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
canvas.renderAll();
this.href = canvas.toDataURL({
format: 'png',
multiplier: 2
});
this.download = "test.png";
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
angle: 5,
stroke: 'red'
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
ctx.setTransform(1, 0, 0, 1, 0, 0);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
pugImg.setAttribute('crossOrigin', 'anonymous');
#c {
border:0px solid #ccc;
}
<script src="//cdn.bootcss.com/fabric.js/1.5.0/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
Your problem is the multiplier.
When using that kind of clipTo functions, you are setting the transform of canvas to plain. When rendering with canvas with multiplier, the base canvas transformation is scaled by the multiplier.
Your rect will be drawn without this transform ( because of setTransform(1,0,0,1,0,0) and will clip out the image.
Instead of setting the transform to [1,0,0,1,0,0] you should set to the invers of the current transformation of the object you are clipping.
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
document.getElementById('download').addEventListener('click', function() {
var data = canvas.toDataURL({
format: 'png',
multiplier: 2
});
console.log(data);
//var img = document.getElementById('export');
//img.src = data;
}, false);
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
angle: 90,
left: 195,
top: 0,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
stroke: 'red',
angle: 5
});
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 245,
top: 35,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
ctx.save();
var myMatrix = this.calcTransformMatrix();
myMatrix = fabric.util.invertTransform(myMatrix);
ctx.transform.apply(ctx, myMatrix);
clipRect1.render(ctx);
ctx.restore();
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
#c {
border:0px solid #ccc;
}
<script src="//www.deltalink.it/andreab/fabric/fabric.js"></script>
<canvas id="c" width="500" height="400"></canvas>
<a id="download">Download as image</a>
<img id="export" >
Im still learning but it seems everything I do does not work in getting the images to also be rotated along with being scaled and dragged. Can someone please help me out with this. Here is the code I am working with...
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body onmousedown="return false;">
<div style="height:1024px; width: 1280px; background-image: url(http://www.designmyprofile.com/images/graphics/backgrounds/background0172.jpg)" id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.2.min.js"></script>
<script>
function update(activeAnchor) {
var group = activeAnchor.getParent();
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var image = group.get('.image')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case 'topLeft':
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
image.setPosition(topLeft.getPosition());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
image.setSize(width, height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
function loadImages(sources, callback) {
var images = {};
var loadedImages = 0;
var numImages = 0;
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
function initStage(images) {
var stage = new Kinetic.Stage({
container: 'container',
width: 1280,
height: 1024
});
var darthVaderGroup = new Kinetic.Group({
x: 270,
y: 100,
draggable: true
});
var yodaGroup = new Kinetic.Group({
x: 100,
y: 110,
draggable: true
});
var layer = new Kinetic.Layer();
/*
* go ahead and add the groups
* to the layer and the layer to the
* stage so that the groups have knowledge
* of its layer and stage
*/
layer.add(darthVaderGroup);
layer.add(yodaGroup);
stage.add(layer);
// darth vader
var darthVaderImg = new Kinetic.Image({
x: 0,
y: 0,
image: images.darthVader,
width: 200,
height: 138,
name: 'image'
});
darthVaderGroup.add(darthVaderImg);
addAnchor(darthVaderGroup, 0, 0, 'topLeft');
addAnchor(darthVaderGroup, 200, 0, 'topRight');
addAnchor(darthVaderGroup, 200, 138, 'bottomRight');
addAnchor(darthVaderGroup, 0, 138, 'bottomLeft');
darthVaderGroup.on('dragstart', function() {
this.moveToTop();
});
// yoda
var yodaImg = new Kinetic.Image({
x: 0,
y: 0,
image: images.yoda,
width: 93,
height: 104,
name: 'image'
});
yodaGroup.add(yodaImg);
addAnchor(yodaGroup, 0, 0, 'topLeft');
addAnchor(yodaGroup, 93, 0, 'topRight');
addAnchor(yodaGroup, 93, 104, 'bottomRight');
addAnchor(yodaGroup, 0, 104, 'bottomLeft');
yodaGroup.on('dragstart', function() {
this.moveToTop();
});
stage.draw();
}
var sources = {
darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
};
loadImages(sources, initStage);
</script>
</body>
</html>