Ok, solved. Place the tween in the click function.
http://jsfiddle.net/2GLF4/2/
star.on('click', function() {
Spin60 = new Kinetic.Tween({
node: star,
rotationDeg: star.rotation()+60,
duration: 1,
easing: Kinetic.Easings.EaseInOut,
onFinish: function() {
console.log(star.rotation());
}
}).play();
});
I am attempting to rotate the star element with Kinetic.Tween using an on click event. The first tween works but consecutive clicks do not. Is this my error, the limitation of the function, or should i be using Kinetic.Animation instead?
http://jsfiddle.net/2GLF4/
var stage = new Kinetic.Stage({
container: 'container',
width: 200,
height: 200
});
var layer = new Kinetic.Layer();
var star = new Kinetic.Star({
x: stage.width() / 2,
y: stage.height() / 2,
numPoints: 17,
innerRadius: 30,
outerRadius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
});
star.on('click', function () {
Spin60.play();
});
layer.add(star);
stage.add(layer);
console.log(star.rotation());
var Spin60 = new Kinetic.Tween({
node: star,
rotation: +60,
duration: 3,
easing: Kinetic.Easings.EaseInOut,
onFinish: function () {
console.log(star.rotation());
}
});
You can use supply a callback function to the tween's .finish event.
The callback is fired when the tween is complete.
myTween.finish(callback)
Related
Have an issue with line rendering when resizing object.
I've locked line endings positions to exact point on circles and when moving, scaling, rotating etc I have to edit lines connected to current circle.
Here is fiddle
Just try to resize circles and at some point you'll see that rendering is crashed a bit which corresponds to lines. Need a help for it, maybe rerender or something.
Or that's an issue of fabric.js
var circlesData = [{
id: 1,
x: 80,
y: 80,
r: 60
}, {
id: 2,
x: 440,
y: 190,
r: 90
}];
var connectionsData = [{
from: {id: 1, angle: 0, rdist: .8},
to: {id: 2, angle: 0, rdist: .4},
}]
var fcircles = [];
var fconnections = [];
var fcanvas;
init();
function init() {
fcanvas = new fabric.Canvas('c', {
imageSmoothingEnabled: false,
allowTouchScrolling: true,
});
fcanvas.preserveObjectStacking = true;
fcanvas.selection = false;
fcanvas.setBackgroundColor('#fff');
fcircles = circlesData.map(function(circleData) {
var circle = new fabric.Circle({
left: circleData.x,
top: circleData.y,
radius: circleData.r,
fill: 'rgba(100,100,255,0.2)',
originX: 'center',
originY: 'center'
});
circle.initialData = circleData;
circle.setControlsVisibility({
mt: false,
mb: false,
ml: false,
mr: false,
mtr: false,
});
return circle;
});
fconnections = connectionsData.map(function(connectionData) {
var line = new fabric.Line([0,0,0,0], {
strokeWidth: 6,
strokeLineCap: 'round',
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center'
});
line.from = copyJson(connectionData.from);
line.to = copyJson(connectionData.to);
line.selectable = false;
return line;
});
fcircles.concat(fconnections).forEach(function(fobj){
fcanvas.add(fobj)
});
updateConnections(fconnections);
fcanvas.renderAll();
console.log(fcanvas.getObjects())
fcanvas.on('object:moving', onObjChange);
fcanvas.on('object:scaling', onObjChange);
fcanvas.on('object:rotating', onObjChange);
}
function onObjChange(e) {
if(['line'].indexOf(e.target.type) > -1) {
return;
}
var circle = e.target;
updateConnections(fconnections.filter(function(fconnection){
return fconnection.from.id === e.target.initialData.id || fconnection.to.id === e.target.initialData.id;
}))
}
function updateConnections(fconnections) {
fconnections.forEach(function(fconnection) {
var from = fcircles.filter(function(c){return c.initialData.id === fconnection.from.id})[0];
var to = fcircles.filter(function(c){return c.initialData.id === fconnection.to.id})[0];
var fromAngle = fconnection.from.angle - from.angle / 180 * Math.PI;
var toAngle = fconnection.to.angle - from.angle / 180 * Math.PI;
debugger;
fconnection.set({
x1: from.left + fconnection.from.rdist * from.radius * Math.cos(fromAngle),
y1: from.top + fconnection.from.rdist * from.radius * Math.sin(fromAngle),
x2: to.left + fconnection.to.rdist * to.radius * Math.cos(toAngle),
y2: to.top + fconnection.to.rdist * to.radius * Math.sin(toAngle)
});
fconnection.setCoords();
});
}
function copyJson(obj) {
return JSON.parse(JSON.stringify(obj));
}
Add to your Line object property:
objectCaching: false
From fabricjs documentation:
objectCaching :Boolean When true, object is cached on an additional
canvas. default to true since 1.7.0
I am using progressBar.Circle, and this is my code that draws a single circle:
function AnimateCircle(container_id, animatePercentage,type) {
var startColor = '#FFFFFF';
var endColor = '#F18F01';
var element = document.getElementById(container_id);
var circle = new ProgressBar.Circle(element, {
color: startColor,
trailColor: '#eee',
trailWidth: 3,
duration: 1400,
easing: 'easeInOut',
strokeWidth: 3,
text: {
value: "<h4>"+type+"</h4>"+ "<h4>"+(animatePercentage )*10+ "</h1>",
className: 'progressbar__label'
},
// Set default step function for all animate calls
step: function (state, circle) {
circle.path.setAttribute('stroke', state.color);
}
});
circle.animate(animatePercentage, {
from: {
color: startColor
},
to: {
color: endColor
}
});
circle.path.style.strokeLinecap = 'round';
}
Is there a way for me to draw another circle within it? That would result in something similar to this:
I'm new with jointjs and I try to constraint a rectangle with ports to a line.
I tried to reproduce tutorial, that works with a basic.Circle, with a basic.Rect but not with devs.Model
Could someone explian me why and how to solve this problem?
Many thanks in advance!
Here is my code :
var width=400, height=1000;
var ConstraintElementView = joint.dia.ElementView.extend({
pointermove: function(evt, x, y) {
joint.dia.ElementView.prototype.pointermove.apply(this, [evt, 100, y]);
}
});
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({ el: $('#myholder'), width: width, height: height, gridSize: 1, model: graph, elementView: ConstraintElementView});
var m1 = new joint.shapes.devs.Model({
position: { x: 20, y: 20 },
size: { width: 90, height: 90 },
inPorts: [''],
outPorts: [''],
attrs: {
'.label': { text: 'Model', 'ref-x': .4, 'ref-y': .2 },
rect: { fill: '#2ECC71' },
'.inPorts circle': { fill: '#16A085' },
'.outPorts circle': { fill: '#E74C3C' }
}
});
var m2=m1.clone();
m2.translate(0,300);
var earth = new joint.shapes.basic.Circle({
position: { x: 100, y: 20 },
size: { width: 20, height: 20 },
attrs: { text: { text: 'earth' }, circle: { fill: '#2ECC71' } },
name: 'earth'
});
graph.addCell([m1, m2, earth]);
Why does it not work?
devs.Model is not rendered via ContraintElementView to the paper.
devs.Model uses devs.ModelView for rendering, basic.Circle and basic.Rect use ContraintElementView.
JointJS dia.Paper searches for a view defined in the same namespace as the model first. If found, it uses it. It uses one from the paper elementView option otherwise. i.e. joint.shapes.devs.ModelView found for devs.Model but no view found for basic.Circle (no joint.shapes.basic.RectView is defined)
How to make it work?
define elementView paper option as a function. In that case paper don't search the namespace and uses the result of the function first.
Note that in order to render ports devs.ModelView is still required.
i.e.
var paper = new joint.dia.Paper({
elementView: function(model) {
if (model instanceof joint.shapes.devs.Model) {
// extend the ModelView with the constraining method.
return joint.shapes.devs.ModelView.extend({
pointermove: function(evt, x, y) {
joint.dia.ElementView.prototype.pointermove.apply(this, [evt, 100, y]);
}
});
}
return ConstraintElementView;
}
});
http://jsfiddle.net/kumilingus/0bjqg4ow/
What is the recommended way to do that?
JointJS v0.9.7+
not to use custom views that restrict elements movement
use restrictTranslate paper option instead.
i.e.
var paper = new joint.dia.Paper({
restrictTranslate: function(elementView) {
// returns an area the elementView can move around.
return { x: 100, y: 0, width: 0, height: 1000 }
};
});
http://jsfiddle.net/kumilingus/atbcujxr/
I think this could help you :
http://jointjs.com/demos/devs
I am trying to get the ID of the image I am clicking on by using the following code:
theImg.on('click', function() {
alert($(this).attr('id')); //Should show 'IDofImg'
});
The Konva code is this:
var theImg = new Konva.Image({
image: imageObj,
x: stage.getWidth() / 2 - 200 / 2,
y: stage.getHeight() / 2 - 137 / 2,
opacity: 0.8,
shadowColor: 'black',
shadowBlur: 5,
id: 'IDofImg',
shadowOffset: {
x: 0,
y: 0
},
startScale: 1,
shadowOpacity: 0.6,
draggable: true
});
As you see, I have id: 'IDofImg', within the making of the image but it seems not to output the needed ID.
It currently outputs this when clicked on:
function() {
// setting
if (arguments.length) {
this[setter](arguments[0]);
return this;
}
// getting
else {
return this[getter]();
}
}
What am I missing?
Fiddle here
You should use this.id() because it is the Konva Image object, and not an html/javascript object.
See also the docs: http://konvajs.github.io/api/Konva.Node.html#id
I want to code an app that simply puts a rectangle on the screen. But I need to combine kinetic.js and backbone.js for this and i am not sure it can be done.
Kinetic code is:
document.getElementById('rect').addEventListener('click', function() {
rect = new Kinetic.Rect({
x: 239,
y: 75,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
offset: [50,25],
draggable: true,
});
And backbone code
$(function() {
var Shape = Backbone.Model.extend({
defaults: { x:50, y:50, width:150, height:150, color:'gray' },
setTopLeft: function(x,y) { this.set({ x:x, y:y }); },
setDim: function(w,h) { this.set({ width:w, height:h }); },
isCircle: function() { return !!this.get('circle'); }
});
*I added .html file these paths
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<script type="text/javascript" src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.3.3.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.2.2/underscore-min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.5.3/backbone-min.js"></script>
All i want to place kinetic part instead of default values in backbone. Is it possible?
With your help, we wrote this example of work which puts a rectangle on the screen using both kinetic.js and backbone.js. I wish it would be useful for who is looking for this kind of integrated code.
Thanks a lot for your help!
var KineticModel = Backbone.Model.extend({
myRect: null,
createRect : function() {
alert("rectangle created.");
var rect=new Kinetic.Rect({
x: 10,
y: 10,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 1,
offset: [0, 0],
draggable: true,
});
return rect;
}
});
var KineticView = Backbone.View.extend({
tagName: 'span',
stage: null,
layer: null,
initialize: function (options) {
model: options.model;
el: options.el;
this.layer = new Kinetic.Layer();
this.stage = new Kinetic.Stage({ container: this.el, width: 400, height: 400 });
this.stage.add(this.layer);
},
events: {
'click': 'spanClicked'
},
render: function () {
var rect = this.model.createRect();
this.layer.add(rect);
this.stage.add(this.layer);
alert("render");
},
spanClicked: function () {
}
});
var kModel = new KineticModel({});
var kView = new KineticView({ el: '#container', model: kModel });
$('#shapetest').click(function() {
kView.render();
});
Yes this is definitely possible. I would just create a model that stores the data that you will be using in your shape, use a view to render a span tag with click me, attach an event listener to the span and then output the rectangle when the user clicks.
var ShapeModel = Backbone.Model.extend({});
var rectangle = new ShapeModel({
x: 10,
y: 10,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
offset: [0, 0],
draggable: true,
});
var RectangleView = Backbone.View.extend({
tagName: 'span',
initialize: function (options) {
model: options.model;
el: options.el;
},
events: {
'click': 'spanClicked'
},
render: function () {
this.$el.text('click me');
},
spanClicked: function () {
var stage = new Kinetic.Stage({
container: this.el,
width: 200,
height: 200
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect(this.model.toJSON());
layer.add(rect);
stage.add(layer);
}
});
var rectangleView = new RectangleView({ el: '#shapetest', model: rectangle });
rectangleView.render();
I would upgrade to the latest version of Backbone and Underscore too.
Also, thanks for pointing out Kinetic. Hopefully it has support for drawing on the canvas on a mobile device.