How can i draw animating path of an object in kineticJS? - javascript

I drew a rectangle with kinetic.js and animating it in a circular path. In each animation frame i reduce it's radius.
Now i want to draw the line of this rectangle's animating path. I am not sure how can i do it by kinetic.js. Please help!
My codes
var R = 150;
$(document).ready(function () {
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 10,
y: 10,
width: 100,
height: 100,
fill: 'black',
stroke: 'red'
});
layer.add(rect);
stage.add(layer);
var centerX = stage.width() / 2;
var anim = new Kinetic.Animation(
function (f) {
var cX = stage.width() / 2;
var cY = stage.height() / 2;
R = R - 1 / 1000;
var X = cX + R * Math.cos(f.time / 1000);
var Y = cY + R * Math.sin(f.time / 1000);
rect.setX(X);
rect.setY(Y);
}, layer);
anim.start();
});
Here is the codes: http://jsfiddle.net/tanvirgeek/n8z8N/
Thanks In advance.

This is how you can draw line segments that follow the path of your rectangle:
Demo: http://jsfiddle.net/m1erickson/Cbq2c/
First Create a Kinetic.Line that will trace the rectangle's path
var line=new Kinetic.Line({
stroke:"blue"
});
layer.add(line);
Second When you generate a new XY in the animation loop, add that XY to the line's points
var points=line.getPoints();
points.push(X,Y);
line.setPoints(points);
Important Warning! This Kinetics animation loop develops an undesirable pausing "stagger". This stagger is small in Chrome, noticeable in IE and horrible in FireFox. This seems to be due to the Kinetic.Line being unable to smoothly add + draw thousands of changing points of data, so I instead recommend using regular html5 canvas and requestAnimationFrame to do your effect.
<!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-v5.0.1.min.js"></script>
<style>
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var line=new Kinetic.Line({
points:[0,0,100,100],
stroke:"blue",
strokeWidth:2
});
layer.add(line);
var rect = new Kinetic.Rect({
x: 100,
y: 100,
width: 15,
height: 15,
fill: 'black',
stroke: 'red'
});
layer.add(rect);
var cx=stage.getWidth() / 2;
var cy=stage.getHeight()/2;
var R=100;
var A=0;
points=[];
var anim = new Kinetic.Animation(
function (f) {
R = R - 1 / 100;
A += Math.PI/180;
var X = cx + R * Math.cos(A);
var Y = cy + R * Math.sin(A);
points.push(X,Y);
line.setPoints(points);
rect.setX(X);
rect.setY(Y);
},
layer);
anim.start();
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>

Related

Using PolyLines to connect drag and drop shapes with FabricJS

I'd like to use a polyline to connect two rectangles and stay connected to the same points on the respective rectangles as the rectangles move (specifically, for two rectangles on a page, I'd like the polyline to connect the bottom middle point of one rectangle to the top middle part of another rectangle. The reason I'm using a PolyLine is because I will eventually be adding in elbows down the road as well). I'm having issues with the polyline coordinates updating in response to the moving rectangles though.
This demonstrates some of the issues I am hitting:
var canvas = new fabric.Canvas('c');
rect = null;
line = null;
function addLine(x1, y1, x2, y2) {
var coords = [{x: x1, y: y1}, {x: x2, y: y2}];
this.line = new fabric.Polyline(coords, {
stroke: 'green',
strokeWidth: 5,
fill: 'rgba(0,0,0,0)',
selectable: true,
evented: false
});
this.canvas.add(this.line);
}
function addRect(left, top, width, height, line1, line2, line3, line4) {
this.rect = new fabric.Rect({
left: left,
top: top,
width: width,
height: height,
fill: '#9f9',
originX: 'left',
originY: 'top',
centeredRotation: true
});
this.rect.line1 = line1;
this.rect.line2 = line2;
this.rect.line3 = line3;
this.rect.line4 = line4;
this.canvas.add(this.rect);
}
var r1_left = 10;
var r1_top = 20;
var r1_width = 125;
var r1_height = 150;
var r2_left = 350;
var r2_top = 300;
var r2_width = 125;
var r2_height = 150;
addLine(r1_left + r1_width/2, r1_top + r1_height, r2_left + r2_width/2, r2_top);
addRect(r1_left, r1_top, r1_width, r1_height, null, null, this.line, null);
addRect(r2_left, r2_top, r2_width, r2_height, this.line, null, null, null);
this.canvas.renderAll();
this.canvas.on('object:moving', function(e) {
var p = e.target;
if (p.line1) {
let x_2_new = p.left + p.width/2;
let y_2_new = p.top;
p.line1.set('points', [p.line1.points[0], {'x': x_2_new, 'y': y_2_new}]);
p.line1.set('height', y_2_new - p.line1.points[0]['y']);
p.line1.set('width', x_2_new - p.line1.points[0]['x']);
p.set('oCoords', p.line1.calcCoords());
} else if (p.line2) {
p.line2.set({'points': [{'x': p.left + p.width, 'y': p.top + p.height/2}, p.line2.points[1]]});
} else if (p.line3) {
p.line3.set({'points': [{'x': p.left + p.width/2, 'y': p.top + p.height}, p.line3.points[1]]});
} else if (p.line4) {
p.line4.set({'points': [p.line4.points[0], {'x': p.left, 'y': p.top + p.height/2}]});
}
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
</head>
<body>
<canvas id="c" width="700" height="700" style="border:1px solid #ccc"></canvas>
<script>
</script>
</body>
</html>
For the upper rectangle, I have tried simply setting the x and y coordinates as the object moves. With this, I encounter the error that x and y seem to be bound by the oCoords and aCoords of the line.
For the lower rectangle, I have tried setting the coordinates directly. With this, the entire line seems to shift around the page.
Any advice about what I could change here would be great. Thanks!
Here is the code, what you need, jsfiddle
(function() {
var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
function makeCircle(left, top, line1, line2) {
var c = new fabric.Rect({
top: top,
left: left,
width: 30,
height: 30,
selection: false,
fill: '#ccc'
});
c.hasControls = c.hasBorders = false;
c.line1 = line1;
c.line2 = line2;
return c;
}
function makeLine(coords) {
return new fabric.Line(coords, {
fill: 'red',
stroke: 'red',
strokeWidth: 5,
selectable: false,
evented: false,
});
}
var line = makeLine([ 250, 125, 250, 375 ]),
line2 = makeLine([ 250, 375, 250, 350 ]);
canvas.add(line);
canvas.add(
makeCircle(line.get('x1'), line.get('y1'), null, line),
makeCircle(line.get('x2'), line.get('y2'), line, line2),
);
canvas.on('object:moving', function(e) {
var p = e.target;
p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top });
p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top });
canvas.renderAll();
});
})();
<div>
<canvas id="c" width="700" height="575" style="border:1px solid #999"></canvas>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.min.js"></script>

Get X and Y of a shape after dragging in Konva JS

I'm using Konva JS in my project. I'm adding a shape on a button click which is draggable. On click of the shape i need to get X and Y positions of the shape. getX and getY functions are returning the original X and Y. How can I update the X and Y after dragging.
Example code below.
var stage = new Konva.Stage({
container: 'canvas', // id of container <div>
width: 500,
height:300
});
jQuery("#add-shape").click(function(){
addShape();
});
var addShape = function(){
console.log("add shape");
var layer = new Konva.Layer();
var parentContainer = new Konva.Rect({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
width: 200,
height: 60,
cornerRadius: 10,
fill: '#ccc'
});
var smallCircle = new Konva.Circle({
x: stage.getWidth() / 2 + 200,
y: stage.getHeight() / 2 + 30,
radius: 15,
fill: "#F2784B",
stroke: "white",
strokeWidth: 2
});
smallCircle.on('click', function() {
console.log(this.getX(),this.getY());
addArrow(this.getX(),this.getY());
//get current X and Y here instead of origina X and Y
});
layer.add(parentContainer);
layer.add(smallCircle);
layer.draggable('true');
stage.add(layer);
}
var addArrow = function(arrowX,arrowY){
var connectorLayer = new Konva.Layer();
var connector = new Konva.Arrow({
points: [arrowX,arrowY,arrowX+10,arrowY],
pointerLength: 4,
pointerWidth: 4,
fill: 'black',
stroke: 'black',
strokeWidth: 2
});
connectorLayer.add(connector);
stage.add(connectorLayer);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.0.2/konva.min.js"></script>
<button id="add-shape">
Add shape
</button>
<div id="canvas">
</div>
If you need to get a mouse position you can use:
smallCircle.on('click', function() {
console.log(stage.getPointerPosition());
});
box.on('mouseout', function () {
document.body.style.cursor = 'default';
console.log(box.attrs.x);
console.log(box.attrs.y);
});
I don't know if this is what you're looking for and it's too late but i'll post it anyway for future developers..
Lets say this is my watermark image inside the layer and bluh bluh and i want it's position getX() and getY(): I use the group like this:
First the regular stuff to add the image:
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.position(topLeft.position());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if (width && height) {
image.width(width);
image.height(height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Konva.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);
}
var stage = new Konva.Stage({
container: 'container',
width: 595,
height: 842
});
var layer = new Konva.Layer();
stage.add(layer);
//WaterMark
var WaterMarkImg = new Konva.Image({
width: 595,
height: 842
});
var WaterMarkGroup = new Konva.Group({
x: 0,
y: 0,
draggable: true
});
layer.add(WaterMarkGroup);
WaterMarkGroup.add(WaterMarkImg);
addAnchor(WaterMarkGroup, 0, 0, 'topLeft');
addAnchor(WaterMarkGroup, 595, 0, 'topRight');
addAnchor(WaterMarkGroup, 595, 842, 'bottomRight');
addAnchor(WaterMarkGroup, 0, 842, 'bottomLeft');
var imageObj1 = new Image();
imageObj1.onload = function () {
WaterMarkImg.image(imageObj1);
layer.draw();
};
imageObj1.src = "some image Url";
and this is simply the getX(): very simple
var x = WaterMarkGroup.getX();
alert(x);
I hope this helps anyone looking for it.
This is not the exact answer for the question. point is the draggable shape.
point.on('dragmove', (t) => {
console.log("dragmove", t.target.x(), t.target.y());
});
use shape.getAttr("x") and shape.getAttr("y"), following is my code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!--mobile friendly-->
<meta name="viewport" content="width=device-width, user-scalable=yes">
</head>
<body>
<div id="c"></div>
<script type="module">
import "../../node_modules/konva/konva.js"
var stage = new Konva.Stage({
container: "#c",
width: 500,
height: 500
})
var layer = new Konva.Layer()
stage.add(layer)
var c = (x, y) => {
return new Konva.Circle({
x: x,
y: y,
stroke: "lightblue",
strokeWidth: 2,
radius: 10,
draggable: true
})
}
let c1 = c(50, 50)
layer.add(c1)
var c2 = c(100, 50)
layer.add(c2)
c1.on("dragmove", () => {
c2.setAttr("y", c1.getAttr("y"))
})
layer.draw()
</script>
</body>
</html>

calculate image 3mm bleed dynamically

Please help me calculate the 'bleed' of an image.
First question: How do I get the dimensions of a dynamic image?
Second question: Sombody knows what is the calculation for bleed?
I will combine the image + bleed indicator..
(If the picture is dynamic i need the bleed to be dynamic too...)
eg x-3=x, y-3=x
I have this code that represents what I want to achieve.
Fiddle
HTML:
<canvas id="c"></canvas>
<br>
<div>
<button onclick="blue_square_2();return true;">Inner Square</button>
<button onclick="red_stroke_2();return true;">Outer Square</button>
</div>
JS:
var canvas = new fabric.StaticCanvas('c');
canvas.setBackgroundImage('img/24-18-0.jpg', canvas.renderAll.bind(canvas));
this.__canvases.push(canvas);
var c2 = document.getElementById("c");
var c2_context = c2.getContext("2d");
function blue_square_2() { //Green color square
canvas.add(new fabric.Rect({
left: 250,
top: 300,
fill: "",
stroke: "green",
strokeWidth: 11.34,
width: 468,
height: 568,
opacity: 0.7
}));
}
function red_stroke_2() { //Blue color edges
canvas.add(new fabric.Rect({
left: 250,
top: 300,
fill: "",
stroke: "blue",
strokeWidth: 11.34,
width: 489,
height: 589,
opacity: 0.7
}));
}
//For someone who also have question like mine, this this is my own answer and calculations
<img id="scream" src="back2.jpg" alt="The Scream" width="220px" height="277px">
<canvas id="c" style="border:1px solid black;"></canvas>
<div>
<button onclick="blue_square_2();return true;">Blue Square</button>
<button onclick="green_stroke_2();return true;">Green Square</button>
<button onclick="clear_rect_2();return true;">Erase Everything</button>
</div>
<script type="text/javascript">
// draw image
var canvas = new fabric.StaticCanvas('c');
canvas.setBackgroundImage('back2.jpg', canvas.renderAll.bind(canvas));
function getHeight(){
return document.querySelector('img').naturalHeight;
}
function getWidth(){
return document.querySelector('img').naturalWidth;
}
function setSize(x,y){
width = x;
height = y;
}
function setCanvasSize(x,y){
canvas.setWidth(x);
canvas.setHeight(y);
width = x;
height = y;
}
var sourceWidth = getWidth();
var sourceHeight = getHeight();
var targetWidth = 400;
var targetHeight = 200;
var sourceRatio = sourceWidth / sourceHeight;
var targetRatio = targetWidth / targetHeight;
var scale;
if ( sourceRatio < targetRatio ) {
scale = sourceWidth / targetWidth;
} else {
scale = sourceHeight / targetHeight;
}
var resizeWidth = parseInt((sourceWidth / scale));
var resizeHeight = parseInt((sourceHeight / scale));
// ctx.drawImage(img,0,0,width,height);
setCanvasSize(resizeWidth,resizeHeight);
console.log(height);
console.log(width);
if(width != getWidth()){
linewidth = (11.34 * 9 ) / (getWidth() / width) ;
linewidth2 = linewidth/2;
}
console.log(linewidth);
// fabric.Object.prototype.originX = true; fabric.Object.prototype.originY = true;
var c2 = document.getElementById("c");
var ctx = c2.getContext("2d");
var rect1 = new fabric.Rect({
left: width/2,
top: height/2,
fill:"",
stroke:"green",
strokeWidth:linewidth,
width: width,
height: height,
opacity: 0.5
});
console.log(linewidth);
var rect2 = new fabric.Rect({
left: width/2 ,
top: height/2 ,
fill:"",
stroke:"blue",
strokeWidth:linewidth2,
width: width-(linewidth+linewidth2),
height: height-(linewidth+linewidth2),
opacity: 0.5
});

Kinetic.js Text gets drawn under shape with fill value set sometimes

In this fiddle: http://jsfiddle.net/m1erickson/fu5LP/
A group of wedges are drawn with text in the middle to produce the above image on the canvas.
When you set the fill value of the wedge object however, the output is rather odd:
Some text values are being drawn under the wedge's fill, I have no idea why.
The code for the fiddle is here:
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var cx = 175;
var cy = 175;
var wedgeRadius = 140;
var accumAngle = 0;
var center = new Kinetic.Circle({
x: cx,
y: cy,
radius: 5,
fill: 'red'
});
layer.add(center);
for (var i = 0; i < 12; i++) {
newTextWedge(30, "Element # " + i);
}
function newTextWedge(angle, text) {
var wedge = new Kinetic.Wedge({
fill : 'black',
x: cx,
y: cy,
//If I add this fill the above output of hiding text occurs
//fill: 'black',
radius: wedgeRadius,
angleDeg: angle,
stroke: 'gray',
strokeWidth: 1,
rotationDeg: -accumAngle + angle / 2
});
layer.add(wedge);
if (accumAngle > 90 && accumAngle < 270) {
var offset = {
x: wedgeRadius - 10,
y: 7
};
var textAngle = accumAngle - 180;
} else {
var offset = {
x: -50,
y: 7
};
var textAngle = accumAngle;
}
var text = new Kinetic.Text({
x: cx,
y: cy,
text: text,
fill: 'red',
offset: offset,
rotationDeg: textAngle
});
layer.add(text);
layer.draw();
accumAngle += angle;
}
Anyone able to give any insight as to why this happens?
Debugging and watching the chart created step by step shows what is happening. The wedge layer is rendered and then the text layer is rendered. The next wedge is rendered on top of that last text layer.
Here is a fork of the fiddle:
http://jsfiddle.net/smurphy/UvdWt/
Kinetic Shape has a method moveToBottom() that you can call on the filled wedge that will force it to the bottom of the stack. See documentation
layer.add(wedge);
wedge.moveToBottom();

Isometric cube projection in html canvas

How do you do the isometric cube in canvas 2d? I've followed True Isometric Projection with HTML5 Canvas to get the top of the cube, but how do you do the left and right sides?
Note: I want to use the Kinetic.js Objects with their event handling features intact.
This is what I have right now:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {
border: 1px solid #9C9898;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.0.0.js"></script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
width: 578,
height: 200,
//scale: [1, 0.5],
//scale: [1, 0.86062],
//rotation: -30 * Math.PI /180,
});
var layer = new Kinetic.Layer({
scale: [1,0.5],
});
var foo = false;
layer.beforeDraw(function(){
if (!foo) {
var context = this.getContext();
var sx = 45*Math.PI/180;
// .75 horizontal shear
var sy = 0;
// no vertical shear
// apply custom transform
//context.transform(1, sy, sx, 1, 0, 0);
//context.scale(1, 0.5);
//context.rotate(45 * Math.PI /180);
//var angle = 30;
//context.setTransform(1, Math.tan(30), 0, 1, 0, 0);
}
foo = true;
});
layer.afterDraw(function(){
var context = this.getContext();
//context.scale(1, 2);
//context.rotate(-45 * Math.PI /180);
});
var rect = new Kinetic.Rect({
x: 200,
y: 100,
width: 50,
height: 50,
fill: "blue",
stroke: "black",
strokeWidth: 4,
rotation: -45 * Math.PI /180,
//scale: [1, 0.5],
});
rect.on("mouseover", function() {
//alert(this.getFill());
this.setFill("red");
layer.draw();
});
rect.on("mouseout", function() {
//alert(this.getFill());
this.setFill("blue");
layer.draw();
});
// add the shape to the layer
layer.add(rect);
// add the layer to the stage
stage.add(layer);
};
</script>
​
demo: http://jsfiddle.net/F5SzS/
Maybe use Polygon instead? Here's an example;
http://jsfiddle.net/Ygnbb/
I made 3 parts separate, but you could do it as one ploygon I guess. Positions and sizes need some tweaking though...

Categories