$(function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// get the offset position of the container
var $canvas = $("#canvas");
var Offset = $canvas.offset();
var offsetX = Offset.left;
var offsetY = Offset.top;
// select all .tool's
var $tools = $(".tool");
// make all .tool's draggable
$tools.draggable({
helper: 'clone',
revert: 'invalid'
});
// assign each .tool its index in $tools
$tools.each(function (index, element) {
$(this).data("toolsIndex", index);
});
// make the canvas a dropzone
$canvas.droppable({
drop: dragDrop,
});
// handle a drop into the canvas
function dragDrop(e, ui) {
// get the drop point (be sure to adjust for border)
var x = parseInt(ui.offset.left - offsetX);
var y = parseInt(ui.offset.top - offsetY);
// get the drop payload (here the payload is the $tools index)
var theIndex = ui.draggable.data("toolsIndex");
// drawImage at the drop point using the dropped image
ctx.drawImage($tools[theIndex], x, y, 32, 32);
}
});
I tried many things but I failed. This code allows me to drag and drop multiple images onto a canvas element. What I need to do is to add the possibility of dragging the image again after it's been dropped. I know that the canvas has to be redrawn each time, but I didn't know how.
Can anyone fix this for me?
Since you commented that you're open to canvas libraries, here's an example that lets you:
drag an img element from a toolbar-div using jqueryUI.
drop the img on the canvas and create a KineticJS.Image object that you can drag around the canvas.
A Demo: http://jsfiddle.net/m1erickson/gkefk/
Results: An img dragged 3X from blue toolbar, dropped on gray canvas, and then dragged on the canvas.
Here's a commented code example:
$(function() {
// get a reference to the house icon in the toolbar
// hide the icon until its image has loaded
var $house = $("#house");
$house.hide();
// get the offset position of the kinetic container
var $stageContainer = $("#container");
var stageOffset = $stageContainer.offset();
var offsetX = stageOffset.left;
var offsetY = stageOffset.top;
// create the Kinetic.Stage and layer
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
// start loading the image used in the draggable toolbar element
// this image will be used in a new Kinetic.Image
var image1 = new Image();
image1.onload = function() {
$house.show();
}
image1.src = "https://i.stack.imgur.com/GeibZ.png";
// make the toolbar image draggable
$house.draggable({
helper: 'clone',
});
// set the data payload
$house.data("url", "house.png"); // key-value pair
$house.data("width", "32"); // key-value pair
$house.data("height", "33"); // key-value pair
$house.data("image", image1); // key-value pair
// make the Kinetic Container a dropzone
$stageContainer.droppable({
drop: dragDrop,
});
// handle a drop into the Kinetic container
function dragDrop(e, ui) {
// get the drop point
var x = parseInt(ui.offset.left - offsetX);
var y = parseInt(ui.offset.top - offsetY);
// get the drop payload (here the payload is the image)
var element = ui.draggable;
var data = element.data("url");
var theImage = element.data("image");
// create a new Kinetic.Image at the drop point
// be sure to adjust for any border width (here border==1)
var image = new Kinetic.Image({
name: data,
x: x,
y: y,
image: theImage,
draggable: true
});
layer.add(image);
layer.draw();
}
}); // end $(function(){});
body {
padding: 20px;
}
#container {
border: solid 1px #ccc;
margin-top: 10px;
width: 350px;
height: 350px;
}
#toolbar {
width: 350px;
height: 35px;
border: solid 1px blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/kineticjs/4.7.2/kinetic.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script
src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"
integrity="sha256-VazP97ZCwtekAsvgPBSUwPFKdrwD3unUfSGVYrahUqU="
crossorigin="anonymous"></script>
</head>
<body>
<div id="toolbar">
<img id="house" width=32 height=32 src="https://i.stack.imgur.com/GeibZ.png"><br>
</div>
<div id="container"></div>
</body>
</html>
What you want is certainly not easy. Now you just drop the image and draw it in the mouse position. To do what you want, you'll need:
Keep track of the images added, their positions, their sizes, and their z-index. The best way to do this is using a stack structure, an array of objects with this properties: url x, y, width, height. The z-index can be the index of the array.
Once you start a drag operation on the canvas, you need to get the point you're dragging, and find the image with the highest z-index that contains that point (basically, implement hit-testing).
To move it, then you have to remove it from the canvas, which implies redrawing the entire canvas with all the images except the one you're dragging. For this you can use the stack previously defined, and draw the images in order.
Finally, you need to draw your image again once you drop it, take it from its position in the array and append it at the end.
This is not an easy task. I suggest you to use some library for it. I cannot recommend you one, because I have little to no experience with canvas.
Related
I would like show a cutting of a canvas element in another canvas element. For explanation i have the following structure:
Canvas Element which gets filled it's background by an image. On top of this image i draw a arrow and a possible path. The background-image is really big, which means that i can not get that much Information from this big image. This is the reason for point two.
I would like to show a cutting of the canvas element 1. For example like the following image:
Currently i get the coordinate of the red arrow in canvas element 1, now i would like to do something like a cutting of this section with offset like in the image.
How could i solve something like this with JavaScript / JQuery. In summary i have two canvas elements. One of them is showing a big map with a red arrow which represents the current location (this works already), but now i wanna show a second canvas element with the zoom of this section where the red arrow is. Currently i am getting the coordinates, but no idea how i could "zoom" into an canvas element.
Like some of the current answers said, i provide some code:
My HTML Code, there is the mainCanvasMap, which has a Background Image and there is the zoomCanvas, which should display a section of the mainCanvasMap!
Here is a JavaScript snippet, which renders the red arrow on the map and should provide a zoom function (where the red-arrow is located) to the zoomCanvas Element.
var canvas = {}
canvas.canvas = null;
canvas.ctx = null;
canvas.scale = 0;
var zoomCanvas = {}
zoomCanvas.canvas = null;
zoomCanvas.ctx = null;
zoomCanvas.scale = 0;
$(document).ready(function () {
canvas.canvas = document.getElementById('mainCanvasMap');
canvas.ctx = canvas.canvas.getContext('2d');
zoomCanvas.canvas = document.getElementById('zoomCanvas');
zoomCanvas.ctx = zoomCanvas.canvas.getContext('2d');
setInterval(requestTheArrowPosition, 1000);
});
function requestTheArrowPosition() {
renderArrowOnMainCanvasElement();
renderZoomCanvas();
}
function renderArrowOnMainCanvasElement(){
//ADD ARROW TO MAP AND RENDER THEM
}
function renderZoomCanvas() {
//TRY TO ADD THE ZOOM FUNCTION, I WOULD LIKE TO COPY A SECTION OF THE MAINCANVASMAP
zoomCanvas.ctx.fillRect(0, 0, zoomCanvas.canvas.width, zoomCanvas.canvas.height);
zoomCanvas.ctx.drawImage(canvas.canvas, 50, 100, 200, 100, 0, 0, 400, 200);
zoomCanvas.canvas.style.top = 100 + 10 + "px"
zoomCanvas.canvas.style.left = 100 + 10 + "px"
zoomCanvas.canvas.style.display = "block";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<!--MY MAIN CANVAS ELEMENT, WHICH HAS A BACKGROUND IMAGE AND WHERE THE ARROW IS RENDEREED-->
<canvas id="mainCanvasMap" style="width:100%; height:100%; background: url('https://image.jimcdn.com/app/cms/image/transf/dimension=624x10000:format=jpg/path/s7d1eecaa5cee1012/image/i4484f962de0bf3c2/version/1543751018/image.jpg') 0% 0% / 100% 100%;"></canvas>
<!-- MY ZOOM CANVAS ELEMENT, SHOULD SHOW A CUTTING OF THE MAINCANVASMAP -->
<canvas id="zoomCanvas" style="height:100%;width:100%"></canvas>
The code is only a pseudo-code, but it shows what i like to do.
Your code is using css for the canvas image, that not always looks the way we think...
I will recommend you to draw everything from scratch, here is a starting point:
canvas = document.getElementById('mainCanvasMap');
ctx = canvas.getContext('2d');
zoomCanvas = document.getElementById('zoomCanvas');
zoomCtx = zoomCanvas.getContext('2d');
var pos = {x:0, y:40}
image = document.getElementById('source');
image.onload = draw;
function draw() {
ctx.drawImage(image,0,0);
setInterval(drawZoom, 80);
}
function drawZoom() {
// simple animation on the x axis
x = Math.sin(pos.x++/10 % (Math.PI*2)) * 20 + 80
zoomCtx.drawImage(image, x, pos.y, 200, 100, 0, 0, 400, 200);
}
<canvas id="mainCanvasMap"></canvas>
<canvas id="zoomCanvas"></canvas>
<img id="source" src="https://image.jimcdn.com/app/cms/image/transf/dimension=624x10000:format=jpg/path/s7d1eecaa5cee1012/image/i4484f962de0bf3c2/version/1543751018/image.jpg" style="display:none">
I have three questions. The first question is the most important but I appreciate to get answers to the others.
First question, see this jsfiddle:
https://jsfiddle.net/owLdgrdq/10
//copia nariz
$(document).on('click', '#add-nariz', function(){
var a = $('#add-nariz');
var src = a.attr('src');
var elem = $('<img class="objetos" src="' + src + '" width="30px" height="30px" style="positon: relative;" />');
$('#fotoAlterada').append(elem);
elem.draggable();
});
//copia bolinha azul
$(document).on('click', '#add-bb', function(){
var a = $('#add-bb');
var src = a.find('img:first').attr('src');
var elem = $('<img class="objetos" src="' + src + '" width="30px" height="30px" style="positon: relative;" />');
$('#fotoAlterada').append(elem);
elem.draggable();
});
$(document).on('click', '#salvaImagem', function(){
var m = $('#foto');
var totX = parseInt(m.css('width'));
var totY = parseInt(m.css('height'));
var c = document.getElementById('myCanvas');
c.width = totX;
c.height = totY;
var ctx = c.getContext('2d');
alert(totX + '\n' + totY);
var base = document.getElementById('foto');
ctx.drawImage(base,0,0,totX,totY,0,0,totX,totY);
var posicoes = [];
$(".objetos").each(function(){
var img = $(this);
x = parseInt(img.css("left"))+totX;
y = parseInt(img.css("top"))+totY;
altura = parseInt(img.css("width"));
largura = parseInt(img.css("height"));
posicoes.push([
x,
y,
largura,
altura
]);
});
alert( JSON.stringify(posicoes));
var j;
var numAderecos = posicoes.length;
for(j = 0; j < numAderecos; j++){
ctx.drawImage(base,posicoes[j][0],posicoes[j][1],posicoes[j][2],posicoes[j][3]);
}
});
I have some icons (Adicionar isto:) what I want add to a photo (Editar isto:). When the user clicks on the icons, a copy is made beside the photo. More click make more copies. These copies are draggable. The user choose the position of the objects and click in a button to save ("Salvar Mudanças"). This button makes a copy of the original photo with the new objects on it (inside a canvas).
At final of the JS code I put little photos (same as original) as little objects added to the photo in the canvas, but just because I don't know how to copy each object added. How can I do that?
Second question, when click on the button, the positions are not the same in the canvas, they are pull to down a little (and left too). Why is this happening if I put padding and margin 0px in CSS code?
Third question, the variable 'base' I used $('#foto') to get by id, but I can't use it at canvas arguments. When I use document.getElementById('foto') I can. What is the difference among them?
----editing ----
My aim with this is to make a mobile application, through cordova/phonegap. The user must be able to get a picture from the device or a selfie with the cam (it's already ok). When the picture/photo is gotten, some new objects like a crown's nose, colorful hat and other silly things appear on the window (it's ok, just change style="display: none;" to be displayed), when the user clicks on these things they make a copy at the bottom of the photo and these copies must be draggable (it's nice too). Then, with jQuery-UI I'm getting the position of all dragged objects into the photo, the user clicks on a button "Salvar Mudanças" ("save changes"), and this action copy the photo plus objects to a canvas area (this is the way I got to make the app). After, the user clicks on another button to share the modified image (in canvas) through whatsapp, facebook, email and any other way which the device could do.
Here is an alternate way of appending icons onto an image using just a canvas
Carve out a toolbar area at the top of an html5 canvas and fill it with your desired icons.
Put the destination image below the toolbar.
Listen for mouse events.
Allow the user to icons from the toolbar onto the image below.
When the user "drops" the dragging icon by releasing the mouse, create a duplicate of the dragged icon at the dropped position.
Here is annotated code and a Demo:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var isDown=false;
var startX,startY;
ctx.lineWidth=0.50;
ctx.strokeStyle='lightgray';
ctx.fillStyle='white';
// vars for icons, etc
var tbar={width:cw,height:35}
var tw=30;
var th=30;
var dragging=null;
var dropped=[];
var icons=[
{name:'Flower',x:tw*0,y:2,url:'https://dl.dropboxusercontent.com/u/139992952/multple/flower.png'},
{name:'Star',x:tw*1,y:2,url:'https://dl.dropboxusercontent.com/u/139992952/multple/star.png'},
{name:'Plane',x:tw*2,y:2,url:'https://dl.dropboxusercontent.com/u/139992952/multple/plane2.png'},
{name:'Mario',x:tw*3,y:2,url:'https://dl.dropboxusercontent.com/u/139992952/multple/marioStanding.png'},
];
var thumbs=[];
var mainImg=new Image();
mainImg.crossOrigin='anonymous';
mainImg.onload=start;
mainImg.src='https://dl.dropboxusercontent.com/u/139992952/multple/husky.jpg';
var imgCount=icons.length+1;
for(var i=0;i<icons.length;i++){
var icon=icons[i];
icon.index=i;
icon.img=new Image();
icon.img.crossOrigin='anonymous';
icon.img.onload=start;
icon.img.src=icon.url;
}
// start is called when each image is fully loaded
function start(){
// wait for all images to load
if(--imgCount>0){return;}
// create
for(var i=0;i<icons.length;i++){
var icon=icons[i];
thumbs.push(thumb(icon.img,tw,th));
}
// draw the toolbar & image
draw();
// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});
}
// create thumbnails for each image (to be used as icons in the toolbar)
function thumb(img,w,h){
var iw=img.width;
var ih=img.height;
var s=Math.min((w/iw),(h/ih))
var c=document.createElement('canvas');
c.width=iw*s;
c.height=ih*s;
c.getContext('2d').drawImage(img,0,0,iw,ih,0,0,iw*s,ih*s);
return(c);
}
// draw the toolbar, image & any clone thumbnails added to the image
function draw(){
ctx.clearRect(0,0,cw,ch);
ctx.fillRect(0,0,cw,tbar.height);
ctx.strokeRect(0,0,cw,tbar.height);
ctx.drawImage(mainImg,0,tbar.height);
for(var i=0;i<icons.length;i++){
var icon=icons[i];
ctx.drawImage(thumbs[icon.index],icon.x,icon.y);
}
for(var i=0;i<dropped.length;i++){
var icon=dropped[i];
ctx.drawImage(thumbs[icon.thumbIndex],icon.x,icon.y);
}
if(dragging){
ctx.drawImage(thumbs[dragging.thumbIndex],dragging.x,dragging.y);
}
}
//
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get the mouse position
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// hit test the toolbar icons and any dropped icons
var mx=startX;
var my=startY;
// hit test toolbar icons
if(mx>0 && mx<tw*icons.length && my>2 && my<2+tw){
var icon=icons[parseInt(mx/tw)];
dragging={thumbIndex:icon.index,x:icon.x,y:icon.y};
dragging.source='icons';
return;
}
// hit test dropped icons
for(var i=0;i<dropped.length;i++){
var icon=dropped[i];
if(mx>icon.x && mx<icon.x+tw && my>icon.y && my<icon.y+th){
dragging=dropped[i];
dragging.source='dropped';
dragging.droppedIndex=i;
return;
}
}
}
// Add any
function handleMouseUpOut(e){
if(!dragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
//
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// add the icon to its dropped position
if(dragging.source=='icons'){
if(dragging.y>tbar.height){
dropped.push(dragging);
}
// remove the dropped icon if it's back in the toolbar
}else if(dragging.y<tbar.height){
dropped.splice(dragging.droppedIndex,1);
}
// clear dragging
dragging=null;
// redraw
draw();
}
// move any icon that's being dragged
function handleMouseMove(e){
if(!dragging){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// get mouse position
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// move the dragged icon by the distance the mouse
// has moved since the last mousemove event
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
dragging.x+=dx;
dragging.y+=dy;
// redraw
draw();
}
// save just the image with dropped icons
$('#save').click(function(){
var c=document.createElement('canvas');
c.width=cw;
c.height=ch-tbar.height;
c.getContext('2d').drawImage(canvas,0,tbar.height,cw,ch-tbar.height,0,0,c.width,c.height);
var img=new Image();
img.onload=function(){
document.body.appendChild(img);
}
img.src=c.toDataURL();
});
body{ background-color: ivory; }
#canvas{border:1px solid lightgray; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id='save'>Save</button>
<h4>Drag from top toolbar & icon will be drop-copied<br>Drag dropped icons around image<br>Drag dropped icon back to toolbar to delete.</h4>
<canvas id="canvas" width=300 height=300></canvas>
It's a little tough to follow, but I suspect you're asking about compositing all of the existing DOM images onto a single canvas context. For that you'll probably want to look at the globalCompositeOperation property on the 2dcanvas:
globalCompositeOperation - the property
Compositing Tutorial - basic outline of how the different types work
Also your 3rd question: $('#foto') returns a jquery object, and document.getElementById returns a DOM object. To get the actual DOM element you would do something like: var theEl = $('#foto')[0]
I am trying to drag drop image in canvas and i am getting perfect co-ordinates of that image in canvas.But whenever i move that same image in the canvas i am not getting the new co-ordinates of that image. I want help to determine the new co-ordinates of that image when i move it.
this is my code:
// get the offset position of the kinetic container
var $stageContainer=$("#container");
var stageOffset=$stageContainer.offset();
var offsetX=stageOffset.left;
var offsetY=stageOffset.top;
// create the Kinetic.Stage and layer
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
// start loading the image used in the draggable toolbar element
// this image will be used in a new Kinetic.Image
var image1=new Image();
image1.onload=function(){
$house.show();
}
image1.src="https://dl.dropboxusercontent.com/u/139992952/multple/4top.png";
// make the toolbar image draggable
$house.draggable({
helper:'clone',
});
// set the data payload
$house.data("url","house.png"); // key-value pair
$house.data("width","32"); // key-value pair
$house.data("height","33"); // key-value pair
$house.data("image",image1); // key-value pair
// make the Kinetic Container a dropzone
$stageContainer.droppable({
drop:dragDrop,
});
// handle a drop into the Kinetic container
function dragDrop(e,ui){
// get the drop point
var x=parseInt(ui.offset.left-offsetX);
var y=parseInt(ui.offset.top-offsetY);
// get the drop payload (here the payload is the image)
var element=ui.draggable;
var data=element.data("url");
var theImage=element.data("image");
// create a new Kinetic.Image at the drop point
// be sure to adjust for any border width (here border==1)
var image = new Kinetic.Image({
name:data,
x:x,
y:y,
image:theImage,
draggable: true
});
layer.add(image);
layer.draw();
}
body{padding:20px;}
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:350px;
height:350px;
}
#toolbar{
width:350px;
height:35px;
border:solid 1px blue;
}
<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>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.min.js"></script>
<h4>Drag from toolbar onto canvas. Then drag around canvas.</h4>
<div id="toolbar">
<img id="house" width=32 height=32 src="https://dl.dropboxusercontent.com/u/139992952/multple/4top.png"><br>
</div>
<div id="container"></div>
Each KineticJS object, like the image object, has x,y properties that hold its current location.
In recent versions of KineticJS, you can fetch an object's x,y using:
var x=myImageObject.x();
var y=myImageObject.y();
Or you can fetch an object containing the current x,y like this:
// myXY has x,y properties: myXY.x and myXY.y
var myXY=myImageObject.position();
I'm writing an app and using Kinetic JS library to load image from client's computer. The image is contained in a photo object and is initialised as below
var photoObj = new Image();
photoObj.onload = function() {
var photoImage = new Kinetic.Image({
x: 0,
y: 0,
image: photoObj,
width: photoObj.width,
height: photoObj.height,
name: "photo",
id: "photo"
});
photoGroup.removeChildren();
photoGroup.add(photoImage);
The object is included in a Kinetic Group object, named photoGroup, which is created earlier.
photoGroup = new Kinetic.Group({
x : 0,
y : 0,
draggable : true,
id : "photoGroup"
});
photoLayer = new Kinetic.Layer({
drawBorder: true
});
photoLayer.add(photoGroup);
stage = new Kinetic.Stage({
container : "kinetic-kard-preview",
width : 320,
height : 480
});
stage.add(photoLayer);
stage.draw();
The group object is included in a Kinetic Layer object, named photoLayer, which is included in a Kinetic Stage object, named stage.
Anyway, my question is, now I would like to get the screen coordinates of the image. I successfully got the coordinates of the stage by
var containerOffset=$("#kinetic-kard-preview").offset();
var offsetX=containerOffset.left;
var offsetY=containerOffset.top;
console.log(offsetX);//455.859375
console.log(offsetY);//218
but I can't seem to do the same thing for the image. When I viewed source code of the web page, I've noticed that the generated html code of the canvas that contains the image is something like this.
<canvas width="320" height="480" style="padding: 0px; margin: 0px; border: 0px; background-color: transparent; width: 320px; height: 480px; position: absolute; background-position: initial initial; background-repeat: initial initial;"></canvas>
How can I get the screen coordinates of the image after it's loaded from client's pc to the canvas? Please help!!! Thank you.
thanks for your answer but it can't seem to get what I need. I just added the link of the screenshot here:
As you can see in the picture, the coordinates of the image are not the same as the coordinates of the stage that contains it. I wrote a mousemove event and calculated
- the distance between the x screen coordinate of the stage (ie. offsetX) and x screen coordinate of the image.
- the distance between the y screen coordinate of the stage (ie. offsetY) and y screen coordinate of the image.
They all have the same number....24 (as shown on the screen). By using the mousemove event, I manually got the values of offsetX, offsetY and the x and y screen coordinates of the image are 455, 218, 479 and 242.
However, my problem is how to get those numbers automatically, especially the screen coordinates of the image, after the image is loaded from my pc. I printed the values of gPos to console.log and got (0,0) values. So when I added offsetX and offsetY to these values, they are the same (455,218), not (479,242). Please let me know what should I do now? Thanks again for your help.
Your Kinetic.Image is at position [0,0] in a draggable Kinetic.Group.
So you can get your image position by adding:
The #kinetic-kard-preview offsets
Plus the current group position: group.position()
[ Added code for KineticJS version 4.5.1 ]
Here is example code for v4.5.1 and a Demo: http://jsfiddle.net/m1erickson/NXH9X/
<!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.5.1.min.js"></script>
<style>
body{padding:20px; background:ivory;}
#kinetic-kard-preview{
margin-top: 10px;
width:350px;
height:350px;
border:1px solid gray;
}
#target{position:absolute;top:200px;left:150px;opacity:0.50;}
</style>
<script>
$(function(){
//
$pos=$("#results");
//
var containerOffset=$("#kinetic-kard-preview").offset();
var offsetX=containerOffset.left;
var offsetY=containerOffset.top;
//
var stage = new Kinetic.Stage({
container: 'kinetic-kard-preview',
width: 350,
height: 350
});
//
photoLayer = new Kinetic.Layer({
drawBorder: true
});
stage.add(photoLayer);
//
photoGroup = new Kinetic.Group({
x : 0,
y : 0,
draggable : true,
id : "photoGroup"
});
photoGroup.on("dragmove",function(){
var gPos=photoGroup.getPosition();
var x=parseInt(offsetX+gPos.x);
var y=parseInt(offsetY+gPos.y);
$pos.text("photoImage: screenX="+x+", screenY="+y);
});
photoLayer.add(photoGroup);
//
var photoObj = new Image();
photoObj.onload = function() {
var photoImage = new Kinetic.Image({
x: 0,
y: 0,
image: photoObj,
width: photoObj.width,
height: photoObj.height,
name: "photo",
id: "photo"
});
photoGroup.add(photoImage);
photoLayer.draw();
}
photoObj.src="https://dl.dropboxusercontent.com/u/139992952/multple/norwayFlag.jpg";
}); // end $(function(){});
</script>
</head>
<body>
<h4>Semi-transparent flag is at screen position 150,200</h4>
<p id=results>Drag the opaque flag and see screen position</p>
<img id=target src='https://dl.dropboxusercontent.com/u/139992952/multple/norwayFlag.jpg'>
<div id="kinetic-kard-preview"></div>
</body>
</html>
I'm working on a simple diagram editor using KineticJS. I would like to use two separate canvases for the palette area (that contains a number of Kinetic.Groups that represent the different nodes of the network I might create), and the diagramming area where I can add nodes from the palette via drag and drop, and then add connections between the various nodes as specific anchor points. I'm having trouble figuring out the drag and drop process from the palette canvas of (stationary) Kinetic.Groups over to the other canvas containing diagramming area. I'm guessing that I need to fire off of the dragstart event for the palette objects (although I don't want these themselves to be draggable), and then do something like create an opague copy of the palette object that can be dragged around, and finally dropped into the diagramming area (with full opacity).
Can groups be dragged outside of a the staging canvases boundaries? Maybe I need to generate an image when I start to drag from the palette, drag that image over, and then create another group when dropping into the diagramming area.
Does any one know of any examples that might point me in the right direction, or who can offer some insight (even code) into the required process. I've searched the KineticJS examples but can't quite find enough to get me going.
Here’s one way to drag nodes from a source palette into a destination group:
A Fiddle: http://jsfiddle.net/m1erickson/xtVyL/
Network nodes are represented by small icons (which are really small kinetic image objects).
The user can drag any icon from the source palette to any destination group.
The groups are just defined areas on the canvas, but could be Kinetc.Groups for more flexibility.
During the dragend event, a new duplicate copy of the dragged icon is created in the destination group.
After the dragend event is complete, the original palette icon is automatically moved from
The newly created duplicate icon can be dragged around the destination group (but not outside that group).
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/xtVyL/
<!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.5.5.min.js"></script>
<style>
#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);
// image loader
var imageURLs=[];
var imagesOK=0;
var imgs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempPC.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempServer.png");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/tempRouter.png");
loadAllImages();
function loadAllImages(callback){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK==imageURLs.length ) {
start();
}
};
img.src = imageURLs[i];
}
}
// top icon positions
var nextIconX=20;
var nextIconY=20;
// define groups
var groups=[];
groups.push({x:0,y:100,w:175,h:250,fill:"skyblue"});
groups.push({x:175,y:100,w:175,h:250,fill:"cornsilk"});
// add boundary info to each group
// draw colored rect to show group area
for(var i=0;i<groups.length;i++){
var g=groups[i];
g.left=g.x;
g.right=g.x+g.w;
g.top=g.y;
g.bottom=g.y+g.h;
var rect=new Kinetic.Rect({
x:g.x,
y:g.y,
width:g.w,
height:g.h,
fill:g.fill,
stroke:"gray"
});
layer.add(rect);
}
// hittest for each group
function groupHit(x,y){
for(var i=0;i<groups.length;i++){
var g=groups[i];
if(x>g.left && x<g.right && y>g.top && y<g.bottom){return(i);}
}
return(-1);
}
function start(){
makePaletteIcon(imgs[0]);
makePaletteIcon(imgs[1]);
makePaletteIcon(imgs[2]);
layer.draw();
}
function makePaletteIcon(img){
// make an icon that stays in the pallette tray
var fixedIcon=newImage(nextIconX,nextIconY,img,false);
layer.add(fixedIcon);
// make an icon that is dragged from the tray to a group
var dragIcon=makeDraggableIcon(nextIconX,nextIconY,img);
layer.add(dragIcon);
// calc the next icon position
nextIconX+=(img.width+20);
}
function makeDraggableIcon(x,y,img){
var i=newImage(x,y,img,true);
//
i.trayX=x;
i.trayY=y;
//
i.setOpacity(0.50);
i.on("dragend",function(){
var x=this.getX();
var y=this.getY();
// if this pallette icon was not dropped in a group
// put the icon back in the tray and return
var hit=groupHit(x,y);
if(hit==-1){
this.setPosition(this.trayX,this.trayY);
return;
}
// add a copy of this icon to the drop group
var component=newImage(x,y,this.getImage(),true);
// set drag limits
var group=groups[hit];
component.maxDragLeft=group.left;
component.maxDragRight=group.right;
component.maxDragTop=group.top;
component.maxDragBottom=group.bottom;
// limit component dragging to inside the assigned group
component.setDragBoundFunc(function(pos) {
var xx=pos.x;
var yy=pos.y;
var w=this.getWidth();
var h=this.getHeight();
if(pos.x<this.maxDragLeft){xx=this.maxDragLeft;}
if(pos.x+w>this.maxDragRight){xx=this.maxDragRight-w;}
if(pos.y<this.maxDragTop){yy=this.maxDragTop;}
if(pos.y+h>this.maxDragBottom){yy=this.maxDragBottom-h;}
return{ x:xx, y:yy };
});
layer.add(component);
// move the dragIcon back into the pallette tray
this.setPosition(this.trayX,this.trayY);
layer.draw();
});
return(i);
}
// make a new Kinetic.Image
function newImage(x,y,img,isDraggable){
var i=new Kinetic.Image({
image:img,
x: x,
y: y,
width: img.width,
height: img.height,
draggable:isDraggable
});
return(i);
}
}); // end $(function(){});
</script>
</head>
<body>
<p>Drag any icon from top into blue or yellow group</p>
<div id="container"></div>
</body>
</html>