I am working on fabric js app & i trying to apply shadow to imported SVG without stroke shadow
when i apply shadow to SVG then shadow is also applied to stroke of svg but i don't want this
Thanks in advance for help
My tried code is
canvas = new fabric.Canvas('canvas');
var shadow = {
color: 'rgba(0,0,0,0.6)',
blur: 20,
offsetX: 10,
offsetY: 10,
opacity: 0.6,
fillShadow: true,
strokeShadow: false
}
var s = '<svg width="100" height="100"><polygon points="30 0, 70 0, 99 33, 99 66, 70 99, 30 99, 0 66, 0 33" fill="#bbb"/></svg>'
fabric.loadSVGFromString(s, function(objects, options) {
var shape = fabric.util.groupSVGElements(objects, options);
//shape.setShadow("10px 10px 5px rgba(94, 128, 191, 0.5)");
if (shape.isSameColor && shape.isSameColor() || !shape.paths) {
console.log('shape');
shape.set({
strokeWidth: 3,
stroke: '#000'
});
}
if (shape.paths) {
console.log('shape path');
/*for (i in shape.paths) {
shape.paths[i].set({
strokeWidth: strokewidth,
stroke: strokecolor
});
}*/
allObjects = shape.paths;
$.each(allObjects, function(key, value) {
value.set({
strokeWidth: 3,
stroke: '#000'
});
});
}
//shape.setShadow("10px 10px 5px rgba(94, 128, 191, 0.5)");
shape.setShadow(shadow);
canvas.add(shape).renderAll();
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>
canvas = new fabric.Canvas('canvas');
var shadow = {
color: 'rgba(0,0,0,0.6)',
blur: 20,
offsetX: 10,
offsetY: 10,
opacity: 0.6,
affectStroke: false
}
var s = '<svg width="100" height="100"><polygon points="30 0, 70 0, 99 33, 99 66, 70 99, 30 99, 0 66, 0 33" fill="#bbb"/></svg>'
fabric.loadSVGFromString(s, function(objects, options) {
var shape = fabric.util.groupSVGElements(objects, options);
if (shape.paths) {
allObjects = shape.paths;
$.each(allObjects, function(key, value) {
value.set({
shadow: shadow,
strokeWidth: 3,
stroke: '#000',
});
value.shadow.affectStroke = false;
});
}
canvas.add(shape).renderAll();
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.5.0/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='canvas' width="500" height="400" style="border:#000 1px solid;"></canvas>
I refined your code to apply the shadow just on paths instead of pathGroup. For what concerns shadow.affectStroke = false not working on pathGroups, this may be a bug, or simply fabric.PathGroup shadow feature is poorly implemented.
Related
I would like to configure fabricJS to add extra rotation controls. I know there is a control API, I am not sure how to use it. control-api
var canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({ width: 100, height: 100, fill: 'red', transparentCorners: false, top: 50, left: 50 });
canvas.add(rect);
canvas.setActiveObject(rect);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<canvas id="c" width="400" height="400" ></canvas>
The new control api allows you to add controls to the
fabric.Object.prototype.controls
This object has a key for each control, and the one that actually hold the rotation is the controls.mtr by default.
we can add mtr1, mtr2 and mtr3 contols in this way.
const originalControl = fabric.Object.prototype.controls.mtr;
fabric.Object.prototype.controls.mtr1 = new fabric.Control({
x: -0.5,
y: 0,
offsetX: -40,
actionHandler: originalControl.actionHandler,
});
Look in the snippet for more details
var canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({ width: 100, height: 100, fill: 'red', transparentCorners: false, top: 50, left: 50 });
canvas.add(rect);
const originalControl = fabric.Object.prototype.controls.mtr;
fabric.Object.prototype.controls.mtr1 = new fabric.Control({
x: -0.5,
y: 0,
offsetX: -40,
actionHandler: originalControl.actionHandler,
withConnection: true,
actionName: 'rotate',
});
fabric.Object.prototype.controls.mtr2 = new fabric.Control({
x: 0.5,
y: 0,
offsetX: 40,
actionHandler: originalControl.actionHandler,
withConnection: true,
actionName: 'rotate',
});
fabric.Object.prototype.controls.mtr3 = new fabric.Control({
x: 0,
y: 0.5,
offsetY: 40,
actionHandler: originalControl.actionHandler,
withConnection: true,
actionName: 'rotate',
});
canvas.setActiveObject(rect);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.3.1/fabric.min.js"></script>
<canvas id="c" width="400" height="400" ></canvas>
Ugly but work.
A note, not specifying actionName: 'rotate' does not keep the rotation point in the center. This is obviously wrong and should be addressed in the library probably.
I need a canvas with a specific shape. I was able to do so thanks to this post using clipPath. The problem is I can't style it at all.
Here an example with a circle shaped canvas. I try to apply the same style to the object inside the container and to the container itself, but as you can see only the object inside the container is styled. How can I apply a stroke or a shadow to this circle container (clipPath)?
const canvas = new fabric.Canvas("canvas", {backgroundColor: "#d3d3d3"})
const container = new fabric.Circle({
radius: 150,
left: 50,
top: 50,
stroke: "rgba(0, 0, 0, 0.5)",
strokeWidth: 1,
})
const obj = new fabric.Rect({
width: 100,
height: 100,
left: 150,
top: 150,
fill: "blue",
stroke: "rgba(0, 0, 0, 0.5)",
strokeWidth: 1,
})
const shadow = new fabric.Shadow({
color: "rgba(0, 0, 0, 0.5)",
blur: 10,
})
container.set("shadow", shadow)
obj.set("shadow", shadow)
canvas.clipPath = container
canvas.add(obj)
canvas.requestRenderAll()
#canvas {
background: #e8e8e8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.0.0-beta.5/fabric.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
[EDIT] I found a company who does that: https://www.plaqueomatic.fr/plaqueomatic/plastique. They use fabric v3.6.0. How can I achieve the same?
When clipping the canvas itself, styles like dropshadows are best applied using CSS. I've also enabled the controlsAboveOverlay property to make the resizing controls visible outside the clippath (feel free to disable if you don't need that).
const canvas = new fabric.Canvas("canvas", {
backgroundColor: "#d3d3d3",
controlsAboveOverlay: true
})
const container = new fabric.Circle({
radius: 150,
left: 50,
top: 50,
stroke: "rgba(0, 0, 0, 0.5)",
strokeWidth: 1,
})
const obj = new fabric.Rect({
width: 100,
height: 100,
left: 150,
top: 150,
fill: "blue",
stroke: "rgba(0, 0, 0, 0.5)",
strokeWidth: 1,
})
const shadow = new fabric.Shadow({
color: "rgba(0, 0, 0, 0.5)",
blur: 10,
})
obj.set("shadow", shadow)
canvas.clipPath = container
canvas.add(obj)
canvas.requestRenderAll()
#canvas {
-webkit-filter: drop-shadow(0px 3px 3px rgba(0, 0, 0, 0.5));
filter: drop-shadow(0px 3px 3px rgba(0, 0, 0, 0.5));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.0.0-beta.5/fabric.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
I'm trying to stroke my Kinetic Spline object with a gradient instead of a solid color. However, my spline is turning out black. Any ideas?
Here's my code:
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var blueSpline = new Kinetic.Spline({
points: [{
x: 73,
y: 160
}, {
x: 340,
y: 23
}, {
x: 500,
y: 109
}, {
x: 300,
y: 109
}],
strokeWidth: 10,
lineCap: 'round',
tension: 1,
fillLinearGradientStartPoint: [73, 160],
fillLinearGradientEndPoint: [300, 109],
fillLinearGradientColorStops: ['#ff0000', '#00ff00'],
fillPriority: 'linear-gradient'
});
layer.add(blueSpline);
stage.add(layer);
You can try this:
var ctx = layer.getContext();
var grad = ctx.createLinearGradient(73, 160, 300, 109);
grad.addColorStop(0, '#ff0000');
grad.addColorStop(1, '#00ff00');
var blueSpline = new Kinetic.Spline({
...
stroke: grad,
...
});
Here is an example:
http://jsfiddle.net/qK6nq/
KineticJS does not support gradient strokes--only gradient fills.
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>
I want to use Angularjs with Kineticjs. The problem is that, it seems angular is overriding mouse events on my stage object.
The following html works fine as stand alone file, you can test it. But if you put this as an Angularjs template, the mouse events stop working.
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#container {
background-color: black;
background-image: url("http://www.html5canvastutorials.com/demos/assets/line-building.png");
background-position: 1px 0px;
background-repeat: no-repeat;
width: 580px;
height: 327px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.1.min.js"></script>
<script defer="defer">
function getData() {
return {
'1st Floor': {
color: 'blue',
points: [366, 298, 500, 284, 499, 204, 352, 183, 72, 228, 74, 274]
},
'2nd Floor': {
color: 'red',
points: [72, 228, 73, 193, 340, 96, 498, 154, 498, 191, 341, 171]
},
'3rd Floor': {
color: 'yellow',
points: [73, 192, 73, 160, 340, 23, 500, 109, 499, 139, 342, 93]
},
'Gym': {
color: 'green',
points: [498, 283, 503, 146, 560, 136, 576, 144, 576, 278, 500, 283]
}
}
}
function updateTooltip(tooltip, x, y, text) {
tooltip.getText().setText(text);
tooltip.setPosition(x, y);
tooltip.show();
}
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 325
});
var shapesLayer = new Kinetic.Layer();
var tooltipLayer = new Kinetic.Layer();
var tooltip = new Kinetic.Label({
opacity: 0.75,
visible: false,
listening: false,
text: {
text: '',
fontFamily: 'Calibri',
fontSize: 18,
padding: 5,
fill: 'white'
},
rect: {
fill: 'black',
pointerDirection: 'down',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: 10,
shadowOpacity: 0.5
}
});
tooltipLayer.add(tooltip);
// get areas data
var areas = getData();
// draw areas
for(var key in areas) {
var area = areas[key];
var points = area.points;
var shape = new Kinetic.Polygon({
points: points,
fill: area.color,
opacity: 0,
// custom attr
key: key
});
shapesLayer.add(shape);
}
stage.add(shapesLayer);
stage.add(tooltipLayer);
stage.on('mouseover', function(evt) {
var shape = evt.targetNode;
shape.setOpacity(0.5);
shapesLayer.draw();
});
stage.on('mouseout', function(evt) {
var shape = evt.targetNode;
shape.setOpacity(0);
shapesLayer.draw();
tooltip.hide();
tooltipLayer.draw();
});
stage.on('mousemove', function(evt) {
var shape = evt.targetNode;
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y - 5;
updateTooltip(tooltip, x, y, shape.attrs.key);
tooltipLayer.batchDraw();
});
</script>
How does event handling work on angular? And how could I prevent from overriding events like:
stage.on('mouseover', function(evt) {
var shape = evt.targetNode;
shape.setOpacity(0.5);
shapesLayer.draw();
});
Thanks!
Ok, it seems Angular was capturing all DOM events.
The solution is to put Kineticjs tag before angular.js(and probably before jQuery too), and be sure you don't declare the tag again elsewhere in any view.