I am quite new to javascript, and I have been following tutorials at https://konvajs.org/ to help me learn their library.
I am currently trying to make it so you can load and select local images to move, resize, and rotate them.
This is the code I have so far:
<head>
<!-- USE DEVELOPMENT VERSION -->
<script src="https://unpkg.com/konva#7.0.0/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Select and Transform Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<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/3.2.5/konva.min.js"></script>
<div>Render a local image without upload</div>
<div>
<input type="file" id="file_input">
</div>
<div id="container"></div>
<script>
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);
//add images
// listen for the file input change event and load the image.
$("#file_input").change(function(e){
var URL = window.webkitURL || window.URL;
var url = URL.createObjectURL(e.target.files[0]);
var img = new Image();
img.src = url;
img.onload = function() {
var img_width = img.width;
var img_height = img.height;
// calculate dimensions to get max 300px
var max = 300;
var ratio = (img_width > img_height ? (img_width / max) : (img_height / max))
// now load the Konva image
var theImg = new Konva.Image({
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
layer.add(theImg);
layer.draw();
}
});
var tr = new Konva.Transformer();
layer.add(tr);
// by default select all shapes
// at this point basic demo is finished!!
// we just have several transforming nodes
layer.draw();
// add a new feature, lets add ability to draw selection rectangle
var selectionRectangle = new Konva.Rect({
fill: 'rgba(0,0,255,0.5)',
});
layer.add(selectionRectangle);
var x1, y1, x2, y2;
stage.on('mousedown touchstart', (e) => {
// do nothing if we mousedown on eny shape
if (e.target !== stage) {
return;
}
x1 = stage.getPointerPosition().x;
y1 = stage.getPointerPosition().y;
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.visible(true);
selectionRectangle.width(0);
selectionRectangle.height(0);
layer.draw();
});
stage.on('mousemove touchmove', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
x2 = stage.getPointerPosition().x;
y2 = stage.getPointerPosition().y;
selectionRectangle.setAttrs({
x: Math.min(x1, x2),
y: Math.min(y1, y2),
width: Math.abs(x2 - x1),
height: Math.abs(y2 - y1),
});
layer.batchDraw();
});
stage.on('mouseup touchend', () => {
// no nothing if we didn't start selection
if (!selectionRectangle.visible()) {
return;
}
// update visibility in timeout, so we can check it in click event
setTimeout(() => {
selectionRectangle.visible(false);
layer.batchDraw();
});
var shapes = stage.find('.rect').toArray();
var box = selectionRectangle.getClientRect();
var selected = shapes.filter((shape) =>
Konva.Util.haveIntersection(box, shape.getClientRect())
);
tr.nodes(selected);
layer.batchDraw();
});
// clicks should select/deselect shapes
stage.on('click tap', function (e) {
// if we are selecting with rect, do nothing
if (selectionRectangle.visible()) {
return;
}
// if click on empty area - remove all selections
if (e.target === stage) {
tr.nodes([]);
layer.draw();
return;
}
// do nothing if clicked NOT on our rectangles
if (!e.target.hasName('rect')) {
return;
}
// do we pressed shift or ctrl?
const metaPressed = e.evt.shiftKey || e.evt.ctrlKey || e.evt.metaKey;
const isSelected = tr.nodes().indexOf(e.target) >= 0;
if (!metaPressed && !isSelected) {
// if no key pressed and the node is not selected
// select just one
tr.nodes([e.target]);
} else if (metaPressed && isSelected) {
// if we pressed keys and node was selected
// we need to remove it from selection:
const nodes = tr.nodes().slice(); // use slice to have new copy of array
// remove node from array
nodes.splice(nodes.indexOf(e.target), 1);
tr.nodes(nodes);
} else if (metaPressed && !isSelected) {
// add the node into selection
const nodes = tr.nodes().concat([e.target]);
tr.nodes(nodes);
}
layer.draw();
});
</script>
Demo: https://www.w3schools.com/code/tryit.asp?filename=GG5QCXFMLFXJ
I am unsure how to make the selecting work on images, rather than rectangles.
Thank you
In the demo, you will see that "rect" names is used to detect selectable shapes. That is a useful approach, because you may have non-selectable shapes on the stage (like a background).
So to check a shape if it is selectable, we use:
e.target.hasName('rect')
So just remember to add "rect" name to new images on the stage:
// now load the Konva image
var theImg = new Konva.Image({
name: 'rect',
image: img,
x: 50,
y: 30,
width: img_width/ratio,
height: img_height/ratio,
draggable: true,
rotation: 0
});
The name itself is not very important. You can find a different way to detect "selectable" nodes.
https://www.w3schools.com/code/tryit.asp?filename=GG6XVLB39IKW
Related
I am using the below HTML to draw paths using paper.js. On the background we want to set a background image.
I tried to set image 'room.jpeg' which is stored locally. It loads correctly but it is not in the background. As a result it gets removed when I try drawing the path. The image should fit in the browser window.
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.14/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.js"></script>
<script type="text/paperscript" canvas="canvas">
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var img1 = new Image();
//drawing of the test image - img1
img1.onload = function() {
//draw background image
ctx.drawImage(img1, 0, 0);
//draw a box over the top
ctx.fillStyle = "rgba(200, 0, 0, 0.5)";
ctx.fillRect(0, 0, 500, 500);
};
img1.src = 'https://i.imgur.com/6gU9m8O.png'; // 'room.jpeg'; amended for this demo
var path;
var currentPath = [];
var textItem = new PointText({
content: '',
point: new Point(20, 30),
fillColor: 'black',
});
function onMouseDown(event) {
// If we produced a path before, deselect it:
if (path) {
path.selected = false;
}
// Create a new path and set its stroke color to black:
path = new Path({
segments: [event.point],
strokeColor: 'black',
// Select the path, so we can see its segment points:
fullySelected: false
});
}
// While the user drags the mouse, points are added to the path
// at the position of the mouse:
function onMouseDrag(event) {
console.log('Capturing new path');
path.add(event.point);
var point = event.point;
currentPath.push(point.x + ', ' + point.y);
// Update the content of the text item to show how many
// segments it has:
textItem.content = '';
}
// When the mouse is released, we simplify the path:
function onMouseUp(event) {
var segmentCount = path.segments.length;
// console.log(currentPath.toString());
console.log('End');
var poi = prompt("Please enter your poi start and end");
console.log('Saving Paths' + poi + (currentPath.toString()));
// When the mouse is released, simplify it:
path.simplify(10);
// Select the path, so we can see its segments:
path.fullySelected = false;
var newSegmentCount = path.segments.length;
var difference = segmentCount - newSegmentCount;
var percentage = 100 - Math.round(newSegmentCount / segmentCount * 100);
textItem.content = '';
}
</script>
<canvas id="canvas" resize></canvas>
Using an img as background gives more trouble since you'll need to redraw/move it on every run.
I'd just use some css to set an background-image to the <canvas> itself:
canvas {
width: 100vw;
height: 100vh;
background-image: url('https://via.placeholder.com/500/FFFFF3?text=BG');
}
canvas {
width: 100vw;
height: 100vh;
background-image: url('https://via.placeholder.com/500/FFFFF3?text=BG');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.15/paper-core.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.14/fabric.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" resize></canvas>
<script type="text/paperscript" canvas="canvas">
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var path;
var currentPath = [];
var textItem = new PointText({
content: '',
point: new Point(20, 30),
fillColor: 'black',
});
function onMouseDown(event) {
// If we produced a path before, deselect it:
if (path) {
path.selected = false;
}
// Create a new path and set its stroke color to black:
path = new Path({
segments: [event.point],
strokeColor: 'black',
// Select the path, so we can see its segment points:
fullySelected: false
});
}
// While the user drags the mouse, points are added to the path
// at the position of the mouse:
function onMouseDrag(event) {
//console.log('Capturing new path');
path.add(event.point);
var point = event.point;
currentPath.push(point.x + ', ' + point.y);
// Update the content of the text item to show how many
// segments it has:
textItem.content = '';
}
// When the mouse is released, we simplify the path:
function onMouseUp(event) {
var segmentCount = path.segments.length;
// console.log(currentPath.toString());
// console.log('End');
var poi = prompt("Please enter your poi start and end");
console.log('Saving Paths' + poi + (currentPath.toString()));
// When the mouse is released, simplify it:
path.simplify(10);
// Select the path, so we can see its segments:
path.fullySelected = false;
var newSegmentCount = path.segments.length;
var difference = segmentCount - newSegmentCount;
var percentage = 100 - Math.round(newSegmentCount / segmentCount * 100);
textItem.content = '';
}
</script>
I am using fabric js v4.1.0 and I would like to show the blue select boundary of the selected object outside the canvas boundary if it is partially dragged out of canvas and have the scaling and rotate functions also in this as the object which is selected inside the canvas.
Here is a demo of my current code https://codepen.io/raja-basumatary/pen/qBZGobQ
function isCanvasSupported() {
var elem = document.createElement("canvas");
return !!(elem.getContext && elem.getContext("2d"));
}
if (!isCanvasSupported()) {
document.getElementById("nocanvas").className = "";
document.getElementById("myCanvas").className = "hidden";
} else {
// Constants
var canvasHeight = 580;
var canvasWidth = 865;
var canvas = new fabric.Canvas("myCanvas");
canvas.setHeight(canvasHeight);
canvas.setWidth(canvasWidth);
var rect = new fabric.Rect({
left: 150,
top: 100,
fill: "#eef",
width: 150,
height: 250
});
canvas.add(rect);
}
I want something like this
image
Any discussion is welcomed. Thanks for reading!
What I am trying to do
I'm trying to implement simple paper(whiteboard) using Konva.js.
So far I've implemented Drag, Zoom and Free drawing on paper.
I referred to
https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html for Zoom
https://konvajs.org/docs/sandbox/Free_Drawing.html for Free drawing
I want to draw only on the region with beige color background, and I want to draw exactly under the pointer even though it is zoomed or dragged.
But Free drawing and both Drag and Zoom features don't work well together.
Bug
Can't draw correctly after dragging or zooming.
Where I think wrong thing is happening, but can't fix
I think something is wrong in the 2 parts bellow.
Implementation of zoom
How I use stage.getPointerPosition() in drawing implementation
Or implementations of these two doesn't fit together
Code
Minimum code is here.
/* ---- Mode management ---- */
let modeSelector = document.getElementById('mode-selector');
let mode = modeSelector.value;
modeSelector.addEventListener('change', () => {
// Discaed event handlers used by old mode
switch (mode) {
case 'Hand': {
endHand();
break;
}
case 'Pen': {
endPen();
break;
}
}
// Set event handlers for new mode
mode = modeSelector.value;
switch (mode) {
case 'Hand': {
useHand();
break;
}
case 'Pen': {
usePen();
break;
}
}
});
/* ---- Konva Objects ---- */
let stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
// A layer that is only used for background color
let backgroundLayer = new Konva.Layer();
let backgroundColor = new Konva.Image({
width: window.innerWidth,
height: window.innerHeight,
fill: 'rgb(242,233,226)'
})
backgroundLayer.add(backgroundColor);
stage.add(backgroundLayer);
backgroundLayer.draw();
// A layer for free drawing
let drawLayer = new Konva.Layer();
stage.add(drawLayer);
/* ---- Functions for mode change ----*/
function useHand () {
// Make stage draggable
stage.draggable(true);
// Make stage zoomable
// *** Code is copy and pasted from
// *** https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.htmlhttps://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html
let scaleBy = 1.3;
stage.on('wheel', (evt) => {
evt.evt.preventDefault();
let oldScale = stage.scaleX();
let mousePointTo = {
x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale
};
let newScale = evt.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;
stage.scale({ x: newScale, y: newScale });
let newPos = {
x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale
};
stage.position(newPos);
stage.batchDraw();
});
}
function endHand () {
stage.draggable(false);
stage.off('wheel');
}
function usePen () {
let isDrawing = false;
let currentLine;
stage.on('mousedown', (evt) => {
// Start drawing
isDrawing = true;
// Create new line object
let pos = stage.getPointerPosition();
currentLine = new Konva.Line({
stroke: 'black',
strokeWidth: 3,
points: [pos.x, pos.y]
});
drawLayer.add(currentLine);
});
stage.on('mousemove', (evt) => {
if (!isDrawing) {
return;
}
// If drawing, add new point to the current line object
let pos = stage.getPointerPosition();
let newPoints = currentLine.points().concat([pos.x, pos.y]);
currentLine.points(newPoints);
drawLayer.batchDraw();
});
stage.on('mouseup', (evt) => {
// End drawing
isDrawing = false;
});
}
function endPen () {
stage.off('mousedown');
stage.off('mousemove');
stage.off('mouseup');
}
/* ---- Init ---- */
useHand();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Paper</title>
</head>
<body>
<select id="mode-selector">
<option value="Hand">Hand</option>
<option value="Pen">Pen</option>
</select>
<div id="container"></div>
<script src="https://unpkg.com/konva#4.0.0/konva.min.js"></script>
<!-- <script src="konvaTest.js"></script> -->
<script src="buggyPaper.js"></script>
</body>
</html>
stage.getPointerPosition() returns absolute position of pointer (related top-left corner of canvas container).
As you are transforming (moving and scaling a stage) you need to find a relative position, so you can use it for the line.
Relative mouse position demo demonstrates how to do that:
function getRelativePointerPosition(node) {
// the function will return pointer position relative to the passed node
var transform = node.getAbsoluteTransform().copy();
// to detect relative position we need to invert transform
transform.invert();
// get pointer (say mouse or touch) position
var pos = node.getStage().getPointerPosition();
// now we find a relative point
return transform.point(pos);
}
/* ---- Mode management ---- */
let modeSelector = document.getElementById('mode-selector');
let mode = modeSelector.value;
modeSelector.addEventListener('change', () => {
// Discaed event handlers used by old mode
switch (mode) {
case 'Hand': {
endHand();
break;
}
case 'Pen': {
endPen();
break;
}
}
// Set event handlers for new mode
mode = modeSelector.value;
switch (mode) {
case 'Hand': {
useHand();
break;
}
case 'Pen': {
usePen();
break;
}
}
});
/* ---- Konva Objects ---- */
let stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
// A layer that is only used for background color
let backgroundLayer = new Konva.Layer();
let backgroundColor = new Konva.Image({
width: window.innerWidth,
height: window.innerHeight,
fill: 'rgb(242,233,226)'
})
backgroundLayer.add(backgroundColor);
stage.add(backgroundLayer);
backgroundLayer.draw();
// A layer for free drawing
let drawLayer = new Konva.Layer();
stage.add(drawLayer);
/* ---- Functions for mode change ----*/
function useHand () {
// Make stage draggable
stage.draggable(true);
// Make stage zoomable
// *** Code is copy and pasted from
// *** https://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.htmlhttps://konvajs.org/docs/sandbox/Zooming_Relative_To_Pointer.html
let scaleBy = 1.3;
stage.on('wheel', (evt) => {
evt.evt.preventDefault();
let oldScale = stage.scaleX();
let mousePointTo = {
x: stage.getPointerPosition().x / oldScale - stage.x() / oldScale,
y: stage.getPointerPosition().y / oldScale - stage.y() / oldScale
};
let newScale = evt.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy;
stage.scale({ x: newScale, y: newScale });
let newPos = {
x: -(mousePointTo.x - stage.getPointerPosition().x / newScale) * newScale,
y: -(mousePointTo.y - stage.getPointerPosition().y / newScale) * newScale
};
stage.position(newPos);
stage.batchDraw();
});
}
function endHand () {
stage.draggable(false);
stage.off('wheel');
}
function getRelativePointerPosition(node) {
// the function will return pointer position relative to the passed node
var transform = node.getAbsoluteTransform().copy();
// to detect relative position we need to invert transform
transform.invert();
// get pointer (say mouse or touch) position
var pos = node.getStage().getPointerPosition();
// now we find relative point
return transform.point(pos);
}
function usePen () {
let isDrawing = false;
let currentLine;
stage.on('mousedown', (evt) => {
// Start drawing
isDrawing = true;
// Create new line object
let pos = getRelativePointerPosition(stage);
currentLine = new Konva.Line({
stroke: 'black',
strokeWidth: 3,
points: [pos.x, pos.y]
});
drawLayer.add(currentLine);
});
stage.on('mousemove', (evt) => {
if (!isDrawing) {
return;
}
// If drawing, add new point to the current line object
let pos = getRelativePointerPosition(stage);
let newPoints = currentLine.points().concat([pos.x, pos.y]);
currentLine.points(newPoints);
drawLayer.batchDraw();
});
stage.on('mouseup', (evt) => {
// End drawing
isDrawing = false;
});
}
function endPen () {
stage.off('mousedown');
stage.off('mousemove');
stage.off('mouseup');
}
/* ---- Init ---- */
useHand();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Paper</title>
</head>
<body>
<select id="mode-selector">
<option value="Hand">Hand</option>
<option value="Pen">Pen</option>
</select>
<div id="container"></div>
<script src="https://unpkg.com/konva#4.0.0/konva.min.js"></script>
<!-- <script src="konvaTest.js"></script> -->
<script src="buggyPaper.js"></script>
</body>
</html>
I have a fabricjs canvas that I need to be able to zoom in and out and also change the image/object inside several times.
For this I setup the canvas in the first time the page loads like this:
fabric.Object.prototype.hasBorders = false;
fabric.Object.prototype.hasControls = false;
canvas = new fabric.Canvas('my_canvas', {renderOnAddRemove: false, stateful: false});
canvas.defaultCursor = "pointer";
canvas.backgroundImageStretch = false;
canvas.selection = false;
canvas.clear();
var image = document.getElementById('my_image');
if (image != null) {
imageSrc = image.src;
if(imageSrc.length > 0){
fabric.Image.fromURL(imageSrc, function(img) {
img = scaleImage(canvas, img); //shrinks the image to fit the canvas
img.selectable = false;
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
});
}
}
canvas.deactivateAll().renderAll();
Then when I need to change the image/object in the canvas or when the page reloads, I try to reset the canvas like this:
canvas.clear();
canvas.remove(canvas.getActiveObject());
var image = document.getElementById('my_image');
if (image != null) {
imageSrc = image.src;
if(imageSrc.length > 0){
fabric.Image.fromURL(imageSrc, function(img) {
img = scaleImage(canvas, img); //shrinks the image to fit the canvas
img.selectable = false;
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
});
}
}
Not sure if it matters but the way I change the image is by changing the source in 'my_image' and reseting the canvas with the above method.
This works well until I use canvas.zoomToPoint, as per this thread, after this, the image/object starts changing position when I reset the zoom or click the canvas with the mouse while it is zoomed, seeming to jump at each change in the top left corner direction, eventually disappearing from view.
Reset Zoom:
canvas.setZoom(1);
resetCanvas(); //(above method)
How can I restore the image/object position?
I tried doing the initial setup instead of the reset and seamed to work visually but was in fact adding a new layer of upper canvas at each new setup so it is no good.
Is there a way to reset the canvas to original state without causing this behavior and still be able to zoom in/out correctly?
Although this question is very old, here is what I did using the current version of fabric.js 2.2.4:
canvas.setViewportTransform([1,0,0,1,0,0]);
For your information: zooming to a point is a recalculation of the viewport transformation. The upper matrix is this is the initial viewport transform matrix.
I eventually fixed the problems I was having.
To reset the zoom, instead of just setting the zoom to 1 with canvas.setZoom(1), I reapplied the canvas.zoomToPoint method to the same point but with zoom 1, to force the initial zoom but regarding the same point that was used to zoom in.
As for the problem of restoring the image position in canvas (after panning for instance) it is as simple as removing the image, centering it in the canvas and re-adding it to the canvas as was done when adding first time:
var img = canvas.getActiveObject();
canvas.remove(img);
canvas.centerObject(img);
canvas.setActiveObject(img);
canvas.add(img);
canvas.renderAll();
See below snippet - here I do the same - zooming together, but degrouping the objects in case somebody clicks on it.
The problem to get to original object properties can be solved, ungrouping the group and creating copies of them and reattaching - a bit annoying, but the only solution I found.
<script id="main">
// canvas and office background
var mainGroup;
var canvas = this.__canvas = new fabric.Canvas('c');
fabric.Object.prototype.transparentCorners = false;
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
createOnjects(canvas);
// events - zoom
$(canvas.wrapperEl).on('mousewheel', function(e) {
var target = canvas.findTarget(e);
var delta = e.originalEvent.wheelDelta / 5000;
if (target) {
target.scaleX += delta;
target.scaleY += delta;
// constrain
if (target.scaleX < 0.1) {
target.scaleX = 0.1;
target.scaleY = 0.1;
}
// constrain
if (target.scaleX > 10) {
target.scaleX = 10;
target.scaleY = 10;
}
target.setCoords();
canvas.renderAll();
return false;
}
});
// mouse down
canvas.on('mouse:up', function(options) {
if (options.target) {
var thisTarget = options.target;
var mousePos = canvas.getPointer(options.e);
if (thisTarget.isType('group')) {
// unGroup
console.log(mousePos);
var clone = thisTarget._objects.slice(0);
thisTarget._restoreObjectsState();
for (var i = 0; i < thisTarget._objects.length; i++) {
var o = thisTarget._objects[i];
if (o._element.alt == "officeFloor")
continue;
else {
if (mousePos.x >= o.originalLeft - o.currentWidth / 2 && mousePos.x <= o.originalLeft + o.currentWidth / 2
&& mousePos.y >= o.originalTop - o.currentHeight / 2 && mousePos.y <= o.originalTop + o.currentHeight / 2)
console.log(o._element.alt);
}
}
// remove all objects and re-render
canvas.remove(thisTarget);
canvas.clear().renderAll();
var group = new fabric.Group();
for (var i = 0; i < clone.length; i++) {
group.addWithUpdate(clone[i]);
}
canvas.add(group);
canvas.renderAll();
}
}
});
// functions
function createOnjects(canvas) {
// ToDo: jQuery.parseJSON() for config file (or web service)
fabric.Image.fromURL('pics/OfficeFloor.jpg', function(img) {
var back = img.set({ left: 100, top: 100 });
back._element.alt = "officeFloor";
back.hasControls = false;
fabric.Image.fromURL('pics/me.png', function(img) {
var me = img.set({ left: -420, top: 275 });
me._element.alt = "me";
console.log(me);
var group = new fabric.Group([ back, me], { left: 700, top: 400, hasControls: false });
canvas.clear().renderAll();
canvas.add(group);
// remove all objects and re-render
});
});
}
</script>
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.