Hi I am looking to make a floor plan editor (something like MsPaint) using JavaScript. I have shortlisted EaselJS or KinetiJS as my preferred libraries.
I would like to know how to create a dynamic rectangular box/line with these libraries. I intend to draw a rectangle by clicking the mouse and dragging it (while the mouse button remains pressed). Thus the size of the rectangle will depend on how far the mouse is dragged.
Any help will be appreciated. If anyone feels that any other library like fabrisJs or paperJs will be better alternative then I am open to solutions in these libraries as well.
Ok... by trial and error and lots of googling and reusing net code I got the answer for KineticJs.
Heres the complete solution:
http://jsfiddle.net/sandeepy02/8kGVD/
<html>
<head>
<script>
window.onload = function() {
layer = new Kinetic.Layer();
stage = new Kinetic.Stage({
container: "container",
width: 320,
height: 320
});
background = new Kinetic.Rect({
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
fill: "white"
});
layer.add(background);
stage.add(layer);
moving = false;
stage.on("mousedown", function(){
if (moving){
moving = false;layer.draw();
} else {
var mousePos = stage.getMousePosition();
rect= new Kinetic.Rect({
x: 22,
y: 7,
width: 0,
height: 0,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
layer.add(rect);
//start point and end point are the same
rect.setX(mousePos.x);
rect.setY(mousePos.y);
rect.setWidth(0);
rect.setHeight(0);
moving = true;
layer.drawScene();
}
});
stage.on("mousemove", function(){
if (moving) {
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y;
rect.setWidth(mousePos.x-rect.getX());
rect.setHeight(mousePos.y-rect.getY());
moving = true;
layer.drawScene();
}
});
stage.on("mouseup", function(){
moving = false;
});
};
</script>
</head>
<body>
<div id="container" ></div>
</body>
</html>
Related
I have JS object with 3 JSON entries, as JavaScript loops through the 3 it creates shapes on the canvas using KineticJS. I'm trying to make it so that when I pass a pixel threshold, in this case 400px, It creates an alert box with the JSON jstext tied to the shape. Here's the code
var tools = [{'title':'method', 'jstext':'function newMethod() {'},
{'title':'var', 'jstext':'var'},
{'title':'end', 'jstext':'}'},
]
var startX = 20;
var startY = 30;
for (var i=0; i<tools.length; i++) {
alert(tools[i].jstext)
var x = new Kinetic.Rect({
x: startX,
y: startY,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 3,
draggable: true,
offset:10,
});
startY = startY + 65;
layer.add(x);
x.on('dragend', function() {
if (x.getAttr('x')>=400) {
console.log(tools[i].jstext)
};
}
It creates the rectangles, it just only logs if the last shape is moved and I want it to pull that text if any shape is moved. Any Ideas? Thanks!
You can:
Create new rectangle inside a function,
Add .originalX and originalY properties so each rect saves its original XY position,
Add a dragend handler that calculates if .getX/.getY are further than 400 px from original XY.
The code would be something like this:
<!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>
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 startX = 20;
var startY = 30;
// create 5 test rects
for (var i=0; i<5; i++) {
newRect(startX,startY,i);
startY = startY + 65;
}
// function to create a new rect
function newRect(x,y,id){
var rect = new Kinetic.Rect({
id:id,
x: startX,
y: startY,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 3,
draggable: true,
offset:10,
});
// have the rect save its original XY
rect.originalX=x;
rect.originalY=y;
// on dragend, calc if the rect has moved >400px
rect.on("dragend",function(){
var dx=this.getX()-this.originalX;
var dy=this.getY()-this.originalY;
var id=this.getId();
if(dx*dx+dy*dy>400*400){
alert(id+" is currently beyond 400px of original XY");
}else{
console.log(id+" is currently inside 400px of original XY");
}
});
layer.add(rect);
layer.draw();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Ok, so I am new to KineticJS and while playing with it, I can't seem to combine an image background with a rectangle layered above that image. Now, if I remove the background image, then the rectangle shows. Even if I put the rectangle code above the image, still doesn't show on top. Sure it is something simple I am missing but I can't seem to figure out what it is and can't find a similar issue here on stackoverflow. Thanks for the help.
Here is my code:
<!DOCTYPE HTML>
<html>
<head>
<style>
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.4.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 600,
height: 450
});
//Layer for our background
var background_layer = new Kinetic.Layer();
//Canvas background image
var canvasBackgroundImage = new Image();
canvasBackgroundImage.onload = function() {
var backgroundImage = new Kinetic.Image({
x: 0,
y: 0,
image: canvasBackgroundImage,
width: 600,
height: 450
});
background_layer.add(backgroundImage);
stage.add(background_layer);
};
canvasBackgroundImage.src = 'images/quiz_back.jpg'; //Location of our background
//Question container
var question_container_layer = new Kinetic.Layer();
var question_container = new Kinetic.Rect({
x: 100,
y: 100,
width: 200,
height: 200,
fill: 'green',
stroke: 'black',
strokeWidth: 2
});
question_container_layer.add(question_container);
stage.add(question_container_layer);
</script>
</body>
Your problem is that you're adding background_layer to the stage inside the canvasBackgroundImage.onload function. Javascript will run through the entire script, and add the question_container_layer to the stage first, AND THEN when your image loads, the background_layer will be added to the stage. As a result, the background image always appears on top of your rectangle layer.
To fix this, add the layers to your stage outside of your onload function:
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 600,
height: 450
});
//Layer for our background
var background_layer = new Kinetic.Layer();
var question_container_layer = new Kinetic.Layer();
stage.add(background_layer);
stage.add(question_container_layer);
//Canvas background image
var canvasBackgroundImage = new Image();
canvasBackgroundImage.onload = function() {
var backgroundImage = new Kinetic.Image({
x: 0,
y: 0,
image: canvasBackgroundImage,
width: 600,
height: 450
});
background_layer.add(backgroundImage);
background_layer.draw();
};
canvasBackgroundImage.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Location of our background
//Question container
var question_container = new Kinetic.Rect({
x: 50,
y: 50,
width: 200,
height: 200,
fill: 'green',
stroke: 'black',
strokeWidth: 2
});
question_container_layer.add(question_container);
question_container_layer.draw();
</script>
To avoid this in the future, unless you have dynamic layers to be added to the stage, I would recommend adding all known layers to the stage before doing anything else. That way you can control the ordering of your layers.
Or alternatively, you can use the zIndex property to order your layers. See here: Kinetic.Container#setZIndex
how to use draggable and double click together in kineticjs?
when using draggable then double click will not work.
Here is my code to draw the image..
function draw(images) {
abcImg= new Kinetic.Rect({
x: 50,
y: 150,
width: 50,
height: 50,
fillPatternImage: images.abc,
name: "abc",
draggable: true
});
}
and here the code when double click..
layer.on('dblclick', function(evt) {
var shape = evt.shape;
name = shape.getName();
$( "#dialog-form" ).dialog( "open" );
});
I'm use kineticjs and jquery.. Thank you..
Here is how to listen for mouse/touch events on the empty areas of the stage.
To listen for mouse/touch events on the stage (any non-object area), you need to add a new layer containing a rectangle that fills the stage. Then you can handle mouse/touch events on the empty stage areas: eventLayer.on(“dblclick”,function(e) {//do doubleclick stuff}
That layer code looks like this:
// Create a layer that will listen for mouse/touch events
var eventLayer = new Kinetic.Layer();
eventLayer.add(new Kinetic.Rect({
x:0,
y:0,
width:400,
height:300
}));
stage.add(eventLayer);
// TEST--listen for "dblclick"
eventLayer.on('dblclick', function(evt) {
alert("2click");
});
Here is the full code and a Fiddle: http://jsfiddle.net/m1erickson/gNMRq/
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.2-beta.js"></script>
</head>
<body>
<div id="container"></div>
<script>
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 300
});
var layer = new Kinetic.Layer();
var rectX = stage.getWidth() / 2 - 50;
var rectY = stage.getHeight() / 2 - 25;
var box = new Kinetic.Rect({
x: rectX,
y: rectY,
width: 100,
height: 50,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
// add cursor styling
box.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
box.on('mouseout', function() {
document.body.style.cursor = 'default';
});
// Create a layer that will listen for mouse/touch events
var eventLayer = new Kinetic.Layer();
eventLayer.add(new Kinetic.Rect({
x:0,
y:0,
width:400,
height:300
}));
stage.add(eventLayer);
// TEST--listen for "dblclick"
eventLayer.on('dblclick', function(evt) {
alert("2click");
});
layer.add(box);
stage.add(layer);
</script>
</body>
</html>
it is working fine. Take a look at this, it's using draggable and dblclick, and both works fine.
http://jsbin.com/oruhif/1/edit
I'm using KinectJS to draw lines based on mouse movement. When a user holds down the mouse button, I want it to be the 'start' point of the line, and when the user release, it will be the 'end' of the line, but as they are holding the mouse down I want to be able to dynamically redraw the line as my mouse moves. Is this possible?
Yes, its possible.
Basically, you has to redraw your layer during onMouseMove event. You'll need a flag to control when the line is moving or not.
When the script initialize, this flag should be false.
At onMouseDown, the line start should receive the current mouse coordinates and set the flag to true.
At onMouseMouve, if the flag is true, you should update the line end to receive the current mouse coordinates.
At onMouseUp, the flag should be set to false.
See the example below:
<!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.1.js"></script>
<script>
window.onload = function() {
layer = new Kinetic.Layer();
stage = new Kinetic.Stage({
container: "container",
width: 320,
height: 320
});
background = new Kinetic.Rect({
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
fill: "white"
});
line = new Kinetic.Line({
points: [0, 0, 50, 50],
stroke: "red"
});
layer.add(background);
layer.add(line);
stage.add(layer);
moving = false;
stage.on("mousedown", function(){
if (moving){
moving = false;layer.draw();
} else {
var mousePos = stage.getMousePosition();
//start point and end point are the same
line.getPoints()[0].x = mousePos.x;
line.getPoints()[0].y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
stage.on("mousemove", function(){
if (moving) {
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y;
line.getPoints()[1].x = mousePos.x;
line.getPoints()[1].y = mousePos.y;
moving = true;
layer.drawScene();
}
});
stage.on("mouseup", function(){
moving = false;
});
};
</script>
</head>
<body>
<div id="container" ></div>
</body>
</html>
I'd like to draw a rectangle with click and drag. How can I do this ? Where do I have to put my click event listener ? On the stage or on the layer ? I have the following code but it doesn't work :
stage = new Kinetic.Stage({...})
layer = new Kinetic.Layer({...})
stage.add(layer)
stage.on('click', function() {
var pos = stage.getMousePosition();
var rect = new Kinetic.Rect({
x: pos.x,
y: pos.y,
width: 10,
height: 10,
});
layer.add(rect);
layer.draw();
})
Thanks.
As far as i know there is no "click" event on stage in kineticjs. You should use something like this:
stage.getContainer().addEventListener('mousedown', function(evt) {});
Link to a fiddle that shows what I've been working on:
http://jsfiddle.net/robtown/SGQq7/22/
It's a set of drawing tools using KineticJS and Sketch.js
You need to select "make sketch" to draw freehand and then "copy sketch to Kinetic" to copy your sketch into the kinetic stage. Select "Make rectangle" make a rectangle.
I need to include code to post this so here's the code for when you select the "Make Rectangle" button:
$('#makeRect').click(function (e) {
followRect = new Kinetic.Rect({
width: 120,
height: 40,
x: -200,
y:-200,
stroke: 'red',
strokeWidth: 3
});
drawLayer.setVisible(true);
drawLayer.add(followRect);
drawLayer.draw();
makeRect = true;
drawLayer.on("mousemove", function (e) {
if (makeRect) {
followRect.setX(e.x+5);
followRect.setY(e.y+5);
drawLayer.draw();
}
});
This creates a rectangle that follows the mouse until you click on the canvas, then it drops the rectangle into the Redlines layer of the stage:
drawLayer.on("mousedown", function (e) {
//for (var f = 0 ; f < 1; f++) {
//alert(e.length);
if (makeRect) {
addToRedlineLayer(e.x, e.y);
}
//}
followRect.setX(-200);
drawLayer.setVisible(false);
return;
});
I had the exact same problem, and indeed the method of Guilherme works greatly.
But there's a simple alternative: create a transparent Rect (Kinetic rectangle) the same size as the canvas:
<script type='text/javascript'>//<![CDATA[
window.onload=function(){
function writeMessage(messageLayer, message) {
var context = messageLayer.getContext();
messageLayer.clear();
context.font = '18pt Calibri';
context.fillStyle = 'black';
context.fillText(message, 10, 25);
}
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var shapesLayer = new Kinetic.Layer();
var messageLayer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x:0,
y:0,
width:stage.getWidth(),
height:stage.getHeight(),
stroke:0
});
rect.on('mousemove', function() {
var mousePos = stage.getMousePosition();
var x = mousePos.x;
var y = mousePos.y;
writeMessage(messageLayer, 'x: ' + x + ', y: ' + y);
});
stage.getContainer().addEventListener('mouseout', function(evt) {
writeMessage(messageLayer, '');
});
shapesLayer.add(rect);
stage.add(shapesLayer);
stage.add(messageLayer);
}//]]>
</script>
The above code will print the x and y position of the mouse when you hover it over the canvas (a div with id "container"). You of course need to load the KineticJS library before using this code.