If I have a kinetic line
for example:
line = new Kinetic.Line({
x: 80,
y:80,
points: [10, 10, 60, 60, 60-headlen*Math.cos(angle-Math.PI/6),60-headlen*Math.sin(angle-Math.PI/6),60, 60, 60-headlen*Math.cos(angle+Math.PI/6),60-headlen*Math.sin(angle+Math.PI/6)],
stroke: "green",
// draggable: true,
strokeWidth: 4,
name: "letter_arrow",
offset: [140,140]
});
and say some circles
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: 'red',
fill: 'white',
strokeWidth: 2,
radius: 8,
name: name,
draggable: false,
dragOnTop: false,
//TODO SET THIS TO 0!!!!!
opacity: 1
});
where x and y will be the first 2 points of the line (10,10) and (60,60)
how can i make the circles drag bound, so that they can only be dragged on a imaginal line made through the first two points (10,10) and (60,60) i read the tutorials about drag bounds but i have no clue maybe you can help me
regards
You can add a custom dragBoundFunc to limit your anchors movement to a line:
// dragBoundFunc will constrain your shape to your desired x/y
// you receive the current mouse position in pos.x and pos.y
// you return the x/y where you want the shape to be located
dragBoundFunc: function(pos) {
// get the mouse x position
var x=pos.x;
// if the mouse is left or right of the line
// force the anchor to the far-left or far-right of the line
if(x<lineMinX){ return({ x:lineMinX, y:lineMinY}); }
if(x>lineMaxX){ return({ x:lineMaxX, y:lineMaxY}); }
// if the mouse between the left and right points of the line
// calc the desired y-position based on the formula: y = lineSlope * x + lineB
return({x:x,y:lineSlope*x+lineB});
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/UHwW9/
<!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.7.2.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:300px;
height:300px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
stage.add(layer);
var x1=10;
var y1=10;
var x2=60;
var y2=60;
var line=new Kinetic.Line({
points:[x1,y1,x2,y2],
stroke:"gray"
});
layer.add(line);
var anchor1=newAnchor(x1,y1,x2,y2);
function newAnchor(x1,y1,x2,y2){
var anchor = new Kinetic.Circle({
x: x1,
y: y1,
radius: 8,
fill: 'skyblue',
stroke: 'lightgray',
strokeWidth: 3,
draggable:true,
dragBoundFunc: function(pos) {
var x=pos.x;
if(x<this.minX){
return({x:this.minX,y:this.minY});
}
if(x>this.maxX){
return({x:this.maxX,y:this.maxY});
}
return({x:x,y:this.slope*x+this.b});
}
});
// dragBoundFunc stuff
anchor.minX=x1;
anchor.minY=y1;
anchor.maxX=x2;
anchor.maxY=y2;
anchor.slope=(y1-y2)/(x1-x2);
anchor.b=y1/(anchor.slope*x1);
//
layer.add(anchor);
layer.draw();
return(anchor);
}
}); // end $(function(){});
</script>
</head>
<body>
<button id="rotateBtn">rotate</button>
<div id="container"></div>
</body>
</html>
In MarkE's code, I believe the way to calculate anchor.b should be
anchor.b = y1 - anchor.slope * x1;
instead of
anchor.b = y1 / (anchor.slope * x1);
The formula is y = ax + b.
That could cause the bad behavior. http://jsfiddle.net/UHwW9/26/
Related
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 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>
Just started using Kinetic.js yesterday. I want to draw some text (a label) inside a wedge so that it's placed inside the wedge with a rotation relative to the wedges' angle.
Like so:
Here's my code:
var numSegments = 5; // Number of wedges in circle
var endPos = 0;
//Center of the div container
var center = document.getElementById('canvas_container').offsetWidth * 0.5;
var centerY = document.getElementById('canvas_container').offsetHeight * 0.5;
for (var i = 0; i < numSegments; ++i) {
//Wedge + corresponding label stored in their own group
var group = new Kinetic.Group();
var wedge = new Kinetic.Wedge({
radius: center,
x: center,
y: centerY,
fill: colors[i],
stroke: '#aaaaff',
strokeWidth: 2,
angleDeg: 360 / numSegments,
rotationDeg: endPos,
});
var label = new Kinetic.Label({
x : wedge.getX(),
y : wedge.getY(),
//The rotation value is where I assume I'm going wrong, this
//Is one of many values i've tried.
rotation : (endPos == 0) ? (360 / numSegments) * 0.5 : endPos
});
label.add(new Kinetic.Text({
text : titles[i],
fontFamily: 'Calibri',
fontSize: 26,
fill : 'white',
align: 'center',
listening: false
}));
group.add(wedge);
group.add(label);
WedgeLayer.add(group);
endPos += 360 / numSegments;
}
I've hit a brick wall with this and am looking for anyone to share any insight into how to achieve the desired outcome..
So far the above results are producing this:
Any help would be greatly appreciated, cheers.
A Demo: http://jsfiddle.net/m1erickson/fu5LP/
You calculate the text offset and rotation angle like this:
Calculating the text rotation angle
Track the accumulated angle for each new wedge you add and use that accum. angle to set the text angle.
Adjusting the angle for various accumulated angles helps keep the text from appearing upside down.
If the accumulated angle is between 90 & 270 degrees then set the text angle as the accumulated angle minus 180.
If the accumulated angle is <90 or >270 then set the text angle as the accumulated angle.
Setting the text offset
The offset depends on the radius of the wedge.
But again the offset is adjusted based on the accumulated angle
If the accumulated angle is between 90 & 270 degrees then set the text offsetX to approximately the wedge radius minus 10.
If the accumulated angle is <90 or >270 then set the text offset to approximately negative half of the wedge radius.
Example code:
<!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.1.0.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 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({
x: cx,
y: cy,
radius: wedgeRadius,
angleDeg: angle,
stroke: 'gray',
strokeWidth: 1,
rotationDeg:-accumAngle+angle/2
});
layer.add(wedge);
wedge.moveToBottom();
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;
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I'm using fabric.js to create objects on a canvas. I have a couple of objects together in a Group. When the group is selected, an event is triggered, which creates and adds a circle, centered at the end of a line. When a selection is cleared, another event is triggered, which removes the circle.
What I don't understand is why the circle doesn't change position to the line's new end point, when I move the group, deselect it, and then re-select it.
<html>
<head>
<script type="text/javascript" src="path/to/fabric.1.4.5.js"></script>
</head>
<body>
<canvas id="c" width="800" height="600"></canvas>
<script type="text/javascript">
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
var canvas = new fabric.Canvas('c');
var circle;
var text = new fabric.Text('hello world', {
fontSize: 30,
originX: 'left',
originY: 'top',
left: 25,
top: 30
});
var line = new fabric.Line([10,10, 100,100], {
stroke: 'green',
strokeWidth: 2
});
var group = new fabric.Group([line, text], {
});
group.on('selected', function() {
circle = new fabric.Circle({
strokeWidth: 5,
radius: 28,
fill: 'rgba(200,200,200,0.4)',
stroke: '#666',
left: line.get('x2'),
top: line.get('y2')
})
canvas.add(circle);
});
canvas.add(group);
canvas.renderAll();
canvas.on('selection:cleared', function () {
group._objects.length = 2;
canvas.remove(circle);
});
</script>
</body>
</html>
Here's the same code on jsFiddle: http://jsfiddle.net/Tqmdw/
The position of your line actually doesn't change. Have a look at the groups tutorial. http://fabricjs.com/fabric-intro-part-3/#groups. In a group items are positioned relative to the groups center and the group is handled as a single entity. That means moving the group will only update the groups top and left position. You can use these new top/left values and calculate the endpoint of the line.
group.on('selected', function() {
circle = new fabric.Circle({
strokeWidth: 5,
radius: 28,
fill: 'rgba(200,200,200,0.4)',
stroke: '#666',
left: group.left + line.get('x2'),,
top: group.top + line.get('y2'),
})
canvas.add(circle);
});
I created an updated fiddle: http://jsfiddle.net/2e9B9/5/
I'm trying to create a line within a bounded area that can also be dragged around once it has been drawn on the layer. Although there are solutions for creating lines dynamically - http://jsfiddle.net/42RHD/65/, I also need them to be draggable around the canvas.
Setting
draggable: true
does not work. I'm guessing it's because we are overriding the mouse down and mouse up events? Here's my attempt with a different approach, which also doesn't work -
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
<script defer="defer">
var x1, y1, x2, y2
var stage = new Kinetic.Stage({
container: 'container',
width: 700,
height: 700
});
var layer = new Kinetic.Layer();
var line = new Kinetic.Line({
y: 0,
points: [x1, y1, x2, y2],
stroke: 'black',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round',
draggable: true
});
var bounds = new Kinetic.Rect({
x: 50,
y: 50,
width: 600,
height: 600,
fill: 'white',
stroke: 'black',
strokeWidth: 4
});
layer.add(bounds);
layer.add(line);
stage.add(layer);
bounds.on('mousedown', function() {
var start = stage.getPointerPosition();
x1 = start.x - 190;
y1 = start.y - 40;
});
bounds.on('mouseup', function() {
var end = stage.getPointerPosition();
x2 = end.x - 190;
y2 = end.y - 40;
line.draw();
});
</script>
Made the switch to FabricJS. The following fiddle shows what I wanted to do:
http://jsfiddle.net/RDqTd/27/
updateComplexity();
takes care of it.