I have 2 images that are the upper arm and forearm. The upper arms rotates around a point and the forearm rotates round this same point.
How can i rotate the forearm when i rotate the upper arm?
if i rotate the upperarm 12 degress,then i must move the forearm to the rotation point of the upper arm and then rotate it but i cant seem to get the forearm to move back into postion after the rotation. What am i doing wrong.
code im using for a kinectjs event;
//upper rotate
upperArmImg.on('mousedown',function(evt) {
upperArmImg.rotateDeg(12);
p.x=upperArmImg.x();
p.y=upperArmImg.y();
//move the formarm to center of rotation
foreArmImg.setPosition(p);
foreArmImg.rotateDeg(12);
//move it back some ???
foreArmImg.move(100,100);
stage.draw();
});
The key to joint movements is putting all arm parts in a group and then setting proper offset points.
The importance of an offset point is that they set where any arm part will rotate (==rotation point)
Here's an outline of how to add kinetic motion to an upper and lower arm:
Put the upper and lower arm in a group
Set the group, upper & lower offsets (==rotation points) to { x:0, y:armDiameter/2 }
To rotate the upper arm, change the groups rotation
To rotate the lower arm, change the lower arm rotation
Group Rotation == 0 degrees, Lower rotation == 0 degrees
Group Rotation == 50 degrees, Lower rotation == 0 degrees
Group Rotation == 50 degrees, Lower rotation == 65 degrees
Here's example code and a Demo:
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
var lastWidth = 0;
var baseGroup = new Kinetic.Group({
x: 50,
y: 200,
draggable: true
});
layer.add(baseGroup);
var lastParent = baseGroup;
var appendages = [];
appendages.push({
name: 'shoulder',
width: 50,
diameter: 20,
fill: 'brown'
});
appendages.push({
name: 'elbow',
width: 80,
diameter: 20,
fill: 'peru'
});
appendages.push({
name: 'hand',
width: 30,
diameter: 20,
fill: 'tan'
});
appendages.push({
name: 'finger',
width: 15,
diameter: 20,
fill: 'wheat'
});
for (var i = 0; i < appendages.length; i++) {
lastParent = addAppendage(i);
appendages[i].group = lastParent;
var appendage = appendages[i];
var html = "Rotate " + appendage.name + ":";
html += "<input id=" + appendage.name;
html += " data-apindex='" + i + "'";
html += " class='apRange' type=range min=0 max=90 value=0><br>";
$('body').append(html);
}
$('.apRange').change(function() {
var appendageIndex = parseInt($(this).data('apindex'));
appendages[appendageIndex].group.rotation(-parseInt($(this).val()));
layer.draw();
});
function addAppendage(i) {
var appendage = appendages[i];
var d2 = appendage.diameter / 2;
// new group for this appendage
var newGroup = new Kinetic.Group({
x: lastWidth,
y: 0,
rotation: 0,
offset: {
x: 0,
y: 0
},
});
newGroup.appendageIndex = i;
lastParent.add(newGroup);
// new appendage
var a = new Kinetic.Rect({
x: 0,
y: 0,
width: appendage.width,
height: d2 * 2,
fill: appendage.fill,
stroke: 'black',
offset: {
x: 0,
y: d2
},
});
newGroup.add(a);
// new joint indicator
var j = new Kinetic.Circle({
x: 0,
y: 0,
radius: d2 / 2,
fill: "red",
offset: {
x: 0,
y: 0
},
});
newGroup.add(j);
// display new objects
layer.draw();
// save width for next loop
lastWidth = appendage.width;
// return latest group
return (newGroup);
}
body {
padding: 20px;
}
#container {
border: solid 1px #ccc;
margin-top: 10px;
width: 350px;
height: 350px;
}
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.1.0.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="container"></div>
Related
I have a simple setup where use clicks location and creates a label with text.
What i would like to be able to do is resize on zoom, so that label is relative size always. Currently label is huge when i zoom in covering key areas.
code:
createTag() {
return new Konva.Tag({
// omitted for brevity
})
}
createLabel(x: number, y: number) {
return new Konva.Label({
x: x,
y: y,
opacity: 0.75
});
}
createText() {
return new Konva.Text({
// omitted for brevity
});
}
createMarker(point: any) {
var label = createLabel(point.x, point.y);
var tag = createTag();
var text = createText();
label.add(tag);
label.add(text);
this.layer.add(label);
this.stage.add(this.layer);
}
Mouse click event listener
this.stage.on('click', function (e) {
// omitted for brevity
var pointer = this.getRelativePointerPosition();
createMarker(pointer);
// omitted for brevity
}
this.stage.on('wheel', function (e) {
// zoom code
});
How can i resize the labels to be relative size of the canvas?
There are many possible solutions. If you are changing scale of the whole stage, then you can just apply reversed scale to the label, so its absolute scale will be always 1.
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});
var layer = new Konva.Layer();
stage.add(layer);
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 50,
fill: 'green',
});
layer.add(circle);
// tooltip
var tooltip = new Konva.Label({
x: circle.x(),
y: circle.y(),
opacity: 0.75,
});
layer.add(tooltip);
tooltip.add(
new Konva.Tag({
fill: 'black',
pointerDirection: 'down',
pointerWidth: 10,
pointerHeight: 10,
lineJoin: 'round',
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 10,
shadowOffsetY: 10,
shadowOpacity: 0.5,
})
);
tooltip.add(
new Konva.Text({
text: 'Try to zoom with wheel',
fontFamily: 'Calibri',
fontSize: 18,
padding: 5,
fill: 'white',
})
);
var scaleBy = 1.01;
stage.on('wheel', (e) => {
e.evt.preventDefault();
var oldScale = stage.scaleX();
var pointer = stage.getPointerPosition();
var mousePointTo = {
x: (pointer.x - stage.x()) / oldScale,
y: (pointer.y - stage.y()) / oldScale,
};
var newScale =
e.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;
stage.scale({ x: newScale, y: newScale });
// apply reversed scale to label
// so its absolte scale is still 1
tooltip.scale({ x: 1 / newScale, y: 1 / newScale })
var newPos = {
x: pointer.x - mousePointTo.x * newScale,
y: pointer.y - mousePointTo.y * newScale,
};
stage.position(newPos);
});
<script src="https://unpkg.com/konva#8.3.0/konva.min.js"></script>
<div id="container"></div>
I have been trying to use built-in functions in p5.js but I can't figure out what I am doing wrong, the col variable won't assign to moon.brightness rather the moon is always white when I preview it, I assigned my variables col and dor before the setup function and called them in the setup function before I initialised the Moon variable, at a total loss here, new to using p5.js so any help about where I am going wrong would be appreciated
var groundHeight;
var mountain1;
var mountain2;
var tree;
var moon;
var sun;
var darkness;
var brightness;
var col;
var dor;
function setup() {
cnv = createCanvas(800, 600)
//set the groundHeight proportional to the canvas size
groundHeight = (height / 3) * 2;
//initalise the mountain objects with properties to help draw them to the canvas
mountain1 = {
x: 400,
y: groundHeight,
height: 320,
width: 230
};
mountain2 = {
x: 550,
y: groundHeight,
height: 200,
width: 130
};
//initalise the tree object
tree = {
x: 150,
y: groundHeight + 20,
trunkWidth: 40,
trunkHeight: 150,
canopyWidth: 120,
canopyHeight: 100
};
//initalise the sun
sun = {
x: 150,
y: 70,
diameter: 80
};
col = (150, 200, 255)
dor = (255, 255, 255)
//TASK: intialise a moon object with an extra property for brightness
moon = {
brightness: col,
x: 700,
y: 70,
diameter: 80
};
//set the initial darkness
darkness = {
x: 800,
y: 600,
light: col
};
}
function draw() {
//TASK: update the values for the moons brightness, the sun's position and the darkness.
//You can either map this to the mouse's location (i.e. the futher left the mouse is the more daylight) or you can just change the values gradually over time.
//draw the sky
background(150, 200, 255);
noStroke();
//draw the sun
fill(255, 255, 0);
ellipse(sun.x, sun.y, sun.diameter);
sun.y = map(mouseX, 0, 800, 70, 630)
fill(moon.brightness)
ellipse(moon.x, moon.y, moon.diameter);
moon.brightness = map(mouseX, 0, 800, col, dor);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
There are two issues here:
In JavaScript the expression (1, 2, 3) does not create a an array, or a vector, or a tuple, or anything that could be used to represent a color. The comma operator evaluates the expression on the left, and the regardless of the value of that expression, it evaluates an expression on the right.
The p5.js map() function does not work with colors, it only works with numbers. If you're working with colors you need to use lerpColor()
var groundHeight;
var mountain1;
var mountain2;
var tree;
var moon;
var sun;
var col;
var dor;
function setup() {
cnv = createCanvas(800, 600)
//set the groundHeight proportional to the canvas size
groundHeight = (height / 3) * 2;
//initalise the mountain objects with properties to help draw them to the canvas
mountain1 = {
x: 400,
y: groundHeight,
height: 320,
width: 230
};
mountain2 = {
x: 550,
y: groundHeight,
height: 200,
width: 130
};
//initalise the tree object
tree = {
x: 150,
y: groundHeight + 20,
trunkWidth: 40,
trunkHeight: 150,
canopyWidth: 120,
canopyHeight: 100
};
//initalise the sun
sun = {
x: 150,
y: 70,
diameter: 80
};
// FIXED: Use the color function to create a p5.Color object from R G and B components
col = color(150, 200, 255)
dor = color(255, 255, 255)
//TASK: intialise a moon object with an extra property for brightness
moon = {
brightness: col,
x: 700,
y: 70,
diameter: 80
};
}
function draw() {
//TASK: update the values for the moons brightness, the sun's position and the darkness.
//You can either map this to the mouse's location (i.e. the futher left the mouse is the more daylight) or you can just change the values gradually over time.
scale
//draw the sky
background(150, 200, 255);
noStroke();
//draw the sun
fill(255, 255, 0);
ellipse(sun.x, sun.y, sun.diameter);
sun.y = map(mouseX, 0, 800, 70, 630)
fill(moon.brightness)
ellipse(moon.x, moon.y, moon.diameter);
// FIXED: when interpolating between two colors, use lerpColor instead of map
moon.brightness = lerpColor(col, dor, mouseX / width);
}
html, body {
margin: 0;
padding: 0;
}
canvas {
transform: scale(0.25);
transform-origin: top left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
I am using KonvaJS to drag and drop rectangles into predefined slots. Some of the slots need to be rotated 90 degrees. I have a hit box around the slots that are rotated vertically, so when the user drags the rectangle into the area it will rotate 90 degrees automatically (to match the orientation). When it rotates, it moves out from under the mouse. This can be solved with offset, but then the rectangle doesn't visually line up with the boxes after snapping. This can (probably) be solved with additional code.
I have tried to rotate the rectangle, and then move it under the mouse. Since the user is still dragging it, this doesn't seem to work as I planned.
Is it possible to force the rectangle to rotate under the mouse without using offset?
Here is a fiddle showing the issue - The offset problems can be demonstrated by setting the first variable to true.
https://jsfiddle.net/ChaseRains/1k0aqs2j/78/
var width = window.innerWidth;
var height = window.innerHeight;
var rectangleLayer = new Konva.Layer();
var holdingSlotsLayer = new Konva.Layer();
var controlLayer = new Konva.Layer();
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
draggable: true
});
//vertical holding spot
holdingSlotsLayer.add(new Konva.Rect({
x: 300,
y: 25,
width: 130,
height: 25,
fill: '#fff',
draggable: false,
rotation: 90,
stroke: '#000'
}));
//horizontal holding spot
holdingSlotsLayer.add(new Konva.Rect({
x: 25,
y: 75,
width: 130,
height: 25,
fill: '#fff',
draggable: false,
rotation: 0,
stroke: '#000'
}));
//mask to set boundaries around where we wannt to flip the rectangle
controlLayer.add(new Konva.Rect({
x: 215,
y: 15,
width: 150,
height: 150,
fill: '#fff',
draggable: false,
name: 'A',
opacity: 0.5
}));
stage.add(holdingSlotsLayer, controlLayer);
//function for finding intersections
function haveIntersection(placeHolder, rectangle, zone) {
if (rectangle.rotation == 0 || zone == true) {
return !(
rectangle.x > placeHolder.x + placeHolder.width ||
rectangle.x + rectangle.width < placeHolder.x ||
rectangle.y > placeHolder.y + placeHolder.height ||
rectangle.y + rectangle.height < placeHolder.y
);
} else {
return !(
rectangle.x > placeHolder.x + 25 ||
rectangle.x + rectangle.width < placeHolder.x ||
rectangle.y > placeHolder.y + placeHolder.height + 90 ||
rectangle.y + rectangle.height < placeHolder.y
);
}
}
//function to create rectangle group (so we can place text on the rectangle)
function spawnRectangle(angle) {
var rectangleGroup = new Konva.Group({
x: 95,
y: 95,
width: 130,
height: 25,
rotation: angle,
draggable: true,
});
rectangleGroup.add(new Konva.Rect({
width: 130,
height: 25,
fill: 'lightblue'
}));
rectangleGroup.add(new Konva.Text({
text: '123',
fontSize: 18,
fontFamily: 'Calibri',
fill: '#000',
width: 130,
padding: 5,
align: 'center'
}));
//function tied to an on drag move event
rectangleGroup.on('dragmove', (e) => {
//shrink rectangle hitbox for use in placeholder intersection
var dimensions = {
"height": 3,
"width": 5,
"x": e.target.attrs.x,
"y": e.target.attrs.y,
'rotation': e.target.attrs.rotation
};
//loop over holding slots to see if there is an intersection.
for (var i = 0; holdingSlotsLayer.children.length > i; i++) {
//if true, change the look of the slot we are hovering
if (haveIntersection(holdingSlotsLayer.children[i].attrs, dimensions, false)) {
holdingSlotsLayer.children[i].attrs.fill = '#C41230';
holdingSlotsLayer.children[i].attrs.dash = [10, 3];
holdingSlotsLayer.children[i].attrs.stroke = '#000';
//set attributes back to normal otherwise
} else {
holdingSlotsLayer.children[i].attrs.fill = '#fff';
holdingSlotsLayer.children[i].attrs.dash = null;
holdingSlotsLayer.children[i].attrs.stroke = null;
}
}
//check to see if we are in a zone that requires the rectangle to be flipped 90 degrees
if (haveIntersection(controlLayer.children[0].attrs, dimensions, true)) {
if (rectangleGroup.attrs.rotation != 90) {
rectangleGroup.attrs.rotation = 90;
}
} else {
rectangleGroup.attrs.rotation = 0;
}
stage.batchDraw();
});
rectangleGroup.on('dragend', (e) => {
for (var i = 0; holdingSlotsLayer.children.length > i; i++) {
//If the parking layer has an element that is lit up, then snap to position..
if (holdingSlotsLayer.children[i].attrs.fill == '#C41230') {
rectangleGroup.position({
x: holdingSlotsLayer.children[i].attrs.x,
y: holdingSlotsLayer.children[i].attrs.y
});
holdingSlotsLayer.children[i].attrs.fill = '#fff';
holdingSlotsLayer.children[i].attrs.dash = null;
holdingSlotsLayer.children[i].attrs.stroke = null;
}
}
stage.batchDraw();
});
rectangleLayer.add(rectangleGroup);
stage.add(rectangleLayer);
}
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #D3D3D3;
background-size: cover;
}
#desc {
position: absolute;
top: 5px;
left: 5px;
}
<script src="https://unpkg.com/konva#4.0.18/konva.min.js"></script>
<body>
<div id="container"></div>
<div id="desc">
<button onclick="spawnRectangle(0)">spawn rectangle</button>
</div>
</body>
Here is a simple function to rotate the rectangle under the mouse, without using konva offset(). I used a tween to apply the movement but if you prefer to use it without the tween just apply the rect.rotate() then apply the newPos x & y as the position.
EDIT: The OP pointed out that if you clicked, held the mouse down whilst the rectangle completed its animation, then dragged, then the rectangle would jump away. What gives ? Well, when the mousedown event runs Konva takes note of the shape's initial position in its internal drag function. Then when we start to actually drag the mouse, Konva dutifully redraws the shape in the position it calculates. Now, 'we' know that we moved the shape in out code, but we didn't let Konva in on our trick.
The fix is to call
rect.stopDrag();
rect.startDrag();
immediately after the new position has been set. Because I am using a tween I do this in the onFinish() callback function of one of the tweens - you would want to ensure its the final tween if you apply more than one. I got away with it because my tweens run over the same period. If you aren't using tweens, just call the above immediately you apply your last rotate() or position() call on the shape.
function rotateUnderMouse(){
// Get the stage position of the mouse
var mousePos = stage.getPointerPosition();
// get the stage position of the mouse
var shapePos = rect.position();
// compute the vector for the difference
var rel = {x: mousePos.x - shapePos.x, y: mousePos.y - shapePos.y}
// Now apply the rotation
angle = angle + 90;
// and reposition the shape to keep the same point in the shape under the mouse
var newPos = ({x: mousePos.x + rel.y , y: mousePos.y - rel.x})
// Just for fun, a tween to apply the move: See https://konvajs.org/docs/tweens/Linear_Easing.html
var tween1 = new Konva.Tween({
node: rect,
duration: 0.25,
x: newPos.x,
y: newPos.y,
easing: Konva.Easings.Linear,
onFinish: function() { rect.stopDrag(); rect.startDrag();}
});
// and a tween to apply the rotation
tween2 = new Konva.Tween({
node: rect,
duration: 0.25,
rotation: angle,
easing: Konva.Easings.Linear
});
tween2.play();
tween1.play();
}
function setup() {
// Set up a stage and a shape
stage = new Konva.Stage({
container: 'canvas-container',
width: 650,
height: 300
});
layer = new Konva.Layer();
stage.add(layer);
newPos = {x: 80, y: 40};
rect = new Konva.Rect({
width: 140, height: 50, x: newPos.x, y: newPos.y, draggable: true, stroke: 'cyan', fill: 'cyan'
})
layer.add(rect);
stage.draw()
rect.on('mousedown', function(){
rotateUnderMouse()
})
}
var stage, layer, rect, angle = 0;
setup()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.0.13/konva.js"></script>
<p>Click the rectangle - it will rotate under the mouse.</p>
<div id="canvas-container"></div>
I'm struggling to implement a little things on canvas with KineticJS.
I want to create a circle + a line which form a group (plane).
The next step is to allow the group to rotate around itself with a button that appears when you click on the group.
My issue is that when I click on the rotate button, it does not rotate near the button but elsewhere. Have a look :
My rotation atm : http://hpics.li/b46b73a
I want the rotate button to be near the end of the line. Not far away..
I tried to implement it on jsfiddle but I'm kinda new and I didn't manage to put it correctly , if you could help me on that, I would be thankful !
http://jsfiddle.net/49nn0ydh/1/
function radians (degrees) {return degrees * (Math.PI/180)}
function degrees (radians) {return radians * (180/Math.PI)}
function angle (cx, cy, px, py) {var x = cx - px; var y = cy - py; return Math.atan2 (-y, -x)}
function distance (p1x, p1y, p2x, p2y) {return Math.sqrt (Math.pow ((p2x - p1x), 2) + Math.pow ((p2y - p1y), 2))}
jQuery (function(){
var stage = new Kinetic.Stage ({container: 'kineticDiv', width: 1200, height:600})
var layer = new Kinetic.Layer(); stage.add (layer)
// group avion1
var groupPlane1 = new Kinetic.Group ({
x: 150, y: 150,
draggable:true
}); layer.add (groupPlane1)
// avion 1
var plane1 = new Kinetic.Circle({
radius: 10,
stroke: "darkgreen",
strokeWidth: 3,
}); groupPlane1.add(plane1);
var trackPlane1 = new Kinetic.Line({
points: [10, 0, 110, 0],
stroke: "darkgreen",
strokeWidth: 2
}); groupPlane1.add(trackPlane1);
groupPlane1.on('click', function() {
controlGroup.show();
});
groupPlane1.setOffset (plane1.getWidth() * plane1.getScale().x / 2, plane1.getHeight() * plane1.getScale().y / 2)
var controlGroup = new Kinetic.Group ({
x: groupPlane1.getPosition().x + 120,
y: groupPlane1.getPosition().y ,
opacity: 1, draggable: true,
}); layer.add (controlGroup)
var signRect2 = new Kinetic.Rect({
x:-8,y: -6,
width: 20,
height: 20,
fill: 'white',
opacity:0
});
controlGroup.add(signRect2);
var sign = new Kinetic.Path({
x: -10, y: -10,
data: 'M12.582,9.551C3.251,16.237,0.921,29.021,7.08,38.564l-2.36,1.689l4.893,2.262l4.893,2.262l-0.568-5.36l-0.567-5.359l-2.365,1.694c-4.657-7.375-2.83-17.185,4.352-22.33c7.451-5.338,17.817-3.625,23.156,3.824c5.337,7.449,3.625,17.813-3.821,23.152l2.857,3.988c9.617-6.893,11.827-20.277,4.935-29.896C35.591,4.87,22.204,2.658,12.582,9.551z',
scale: {x:0.5, y:0.5}, fill: 'black'
}); controlGroup.add (sign)
controlGroup.setDragBoundFunc (function (pos) {
var groupPos = groupPlane1.getPosition();
var rotation = degrees (angle (groupPos.x, groupPos.y, pos.x, pos.y));
var dis = distance (groupPos.x, groupPos.y, pos.x, pos.y);
groupPlane1.setRotationDeg (rotation);
layer.draw()
return pos
})
controlGroup.on ('dragend', function() {
controlGroup.hide();
layer.draw()
})
controlGroup.hide();
layer.draw()
})
You can adjust the rotation point by setting the offsetX and offsetY of the group.
I have made a Bezier Shape in kinetic js with control points on it vertices. the code allows the user to drag the starting, ending and control points thereby modifying the shape of the curve like shown below.
The link to the js fiddle containing the above code is http://jsfiddle.net/Lucy1/da90vct4/2/
Code for the anchor points is
var room = new Kinetic.Shape({
x: 0,
y: 0,
width: 100,
height: 100,
stroke: "black",
fill: 'ivory',
drawFunc: function (context) {
var x = this.x();
var y = this.y();
var w = this.width();
var h = this.height();
var trX = anchorTR.x();
var trY = anchorTR.y();
var brX = anchorBR.x();
var brY = anchorBR.y();
var blX = anchorBL.x();
var blY = anchorBL.y();
var tlX = anchorTL.x();
var tlY = anchorTL.y();
context.beginPath();
context.moveTo(tlX, tlY);
// top
context.bezierCurveTo(x + w / 3, y, x + w * 2 / 3, y, trX, trY);
// right
context.bezierCurveTo(x + w, y + h / 3, x + w, y + h * 2 / 3, brX, brY);
// bottom
context.bezierCurveTo(x + w * 2 / 3, y + h, x + w / 3, y + h, blX, blY);
// left
context.bezierCurveTo(x, y + h * 2 / 3, x, y + h / 3, tlX, tlY);
context.closePath();
context.fillStrokeShape(this);
}
});
g.add(room);
var anchorTR = new Kinetic.Circle({
x: 100,
y: 0,
radius: 8,
fill: "green",
stroke: 'black',
strokeWidth: 1,
draggable: true
});
g.add(anchorTR);
var anchorBR = new Kinetic.Circle({
x: 100,
y: 100,
radius: 8,
fill: "green",
stroke: 'black',
strokeWidth: 1,
draggable: true
});
g.add(anchorBR);
var anchorBL = new Kinetic.Circle({
x: 0,
y: 100,
radius: 8,
fill: "green",
stroke: 'black',
strokeWidth: 1,
draggable: true
});
g.add(anchorBL);
var anchorTL = new Kinetic.Circle({
x: 0,
y: 0,
radius: 8,
fill: "green",
stroke: 'black',
strokeWidth: 1,
draggable: true
});
g.add(anchorTL);
layer.draw();
Currently i'm defining multiple kinetic circles for the anchor points and multiple variables for positioning the anchor points.I'm trying to optimize the code in such a way that i can reuse the code multiple times without using loops but not being able to..Please help..
You can make the code reusable by encapsulating it into functions and adding some references.
Put the code that creates a group & room into a function and return the new room from that function.
Put the code that creates an anchor into a function and return the new anchor from that function.
Attach references to a room's anchors to the room node itself.
Here's a refactoring of the code and a Demo: http://jsfiddle.net/m1erickson/opsy1pn9/
<!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 room1=makeRoom(50,50,50,50);
var room2=makeRoom(150,150,50,50);
function makeRoom(x,y,w,h){
var g=new Kinetic.Group({x:x,y:y,draggable:true});
layer.add(g);
var room=new Kinetic.Shape({
x:0,
y:0,
width:w,
height:h,
stroke:"blue",
fill: 'red',
drawFunc: function(context) {
var x=this.x();
var y=this.y();
var w=this.width();
var h=this.height();
var tlX=this.anchorTL.x();
var tlY=this.anchorTL.y();
context.beginPath();
context.moveTo(tlX,tlY);
// top
context.bezierCurveTo(x+w/3,y, x+w*2/3,y, this.anchorTR.x(),this.anchorTR.y());
// right
context.bezierCurveTo(x+w,y+h/3, x+w,y+h*2/3, this.anchorBR.x(),this.anchorBR.y());
// bottom
context.bezierCurveTo(x+w*2/3,y+h, x+w/3,y+h, this.anchorBL.x(),this.anchorBL.y());
// left
context.bezierCurveTo(x,y+h*2/3, x,y+h/3, tlX,tlY);
context.closePath();
context.fillStrokeShape(this);
}
});
g.add(room);
room.anchorTR=makeAnchor(w,0,g);
room.anchorBR=makeAnchor(w,h,g);
room.anchorBL=makeAnchor(0,h,g);
room.anchorTL=makeAnchor(0,0,g);
layer.draw();
}
function makeAnchor(x,y,group){
var anchor=new Kinetic.Circle({
x:x,
y:y,
radius:8,
fill:"green",
stroke: 'black',
strokeWidth: 1,
draggable: true
});
group.add(anchor);
anchor.moveToTop();
return(anchor);
}
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag green circle to change red rect</h4>
<div id="container"></div>
</body>
</html>