Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am developing canvas using jquery and i am able to take only one kind of image from toolbox to actual canvas(i.e. drag, drop of one image from toolbox to canvas). I want to add more inputs in toolbox like door,table,chair etc. And want to use same for drag drop operation.
This is my Current Code which takes only one input in toolbar. i want multiple options in toolbar and same for drag drop functionality in the canvas.
// 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://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>
Related
I'm new to Web WorldWind and forgive me if this is a simple question, but I haven't found a solution in the documentation or elsewhere. I have the following:
<div style="position: absolute; top: 5px; left: 5px;">
<!-- Create a canvas for Web WorldWind. -->
<canvas id="canvasOne" width="1040" height="630">
Your browser does not support HTML5 Canvas.
</canvas>
</div>
<script>
var wwd;
window.addEventListener("load", eventWindowLoaded, false);
// Define the event listener to initialize Web WorldWind.
function eventWindowLoaded() {
// Create a WorldWindow for the canvas.
wwd = new WorldWind.WorldWindow("canvasOne");
// Add some image layers to the WorldWindow's globe
//wwd.addLayer(new WorldWind.BingAerialWithLabelsLayer());.
wwd.addLayer(new WorldWind.BingRoadsLayer());
// Add a compass, a coordinates display and some view controls to the WorldWindow.
wwd.addLayer(new WorldWind.CompassLayer());
wwd.addLayer(new WorldWind.CoordinatesDisplayLayer(wwd));
wwd.addLayer(new WorldWind.ViewControlsLayer(wwd));
}
</script>
When the map is displaying, I'd like to add a toggle to switch between the roads layer and the high resolution aerial window. Any help is appreciated.
Set the boolean enabled property to show/hide an individual layer.
// Create the roads and aerial imagery layers and set the initial visability
var aerialLayer = new WorldWind.BingAerialWithLabelsLayer(),
roadsLayer = new WorldWind.BingRoadsLayer();
aerialLayer.enabled = true;
roadsLayer.enabled = false;
// Add the layers to the WorldWindow (globe)
wwd.addLayer(aerialLayer);
wwd.addLayer(roadsLayer);
// Toggles the display of the roads and aerial imagery layers
function toggleLayers() {
aerialLayer.enabled = !aerialLayer.enabled;
roadsLayer.enabled = !roadsLayer.enabled;
}
FYI: The WorldWindow (wwd) object has a layers array property where you can access the layers.
See: WorldWind.Layer
See also: layers in WorldWind.WorldWindow
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();
$(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.
I still stuck and need your help my canvas project. I got the idea of a template, what I want to see there and I want to insert a content now there. From my last question about I have this working canvas template: jsfiddle.net/AbdiasSoftware/LmCwZ/2/ Here is the idea of what I want to have at my first tab. Hopefully with your help creating first main tab, I will carry on expanding example and working by myself. First tab example: http://i.imgur.com/5Anzfny.png
How I can do this for my first tab? Some of the text content should be automatically update by application. Thank you in advance.
As #Ken suggests in his answer to your last question, layout of complex content is usually done with HTML+CSS. A nice tool to give you tabs is jqueryUI's tab control: https://jqueryui.com/tabs/ A production application would use HTML+CSS.
But since you're coding a project for learning purposes, here is how you can create "templates" for your tab content.
JavaScript has a variable called an object. Objects are kind of like arrays because that one object can hold multiple pieces of information. Each piece of information in an object is labeled.
An object that holds info about text you want to include in your template might look like this:
var myTextObject1 = { text:"Hello", x:100, y:20 };
var myTextObject2 = { text:"World", x:100, y:35 };
To make your template, create a contents array and save your objects in that array
var contents=[];
contents.push(myTextObject1);
contents.push(myTextObject2);
Then when you activate this tab you can use the objects to draw content on your tab
for(var i=0;i<contents.length;i++){
drawTextContent( contents[i] );
}
function drawTextContent(text){
ctx.fillText(text.text,text.x,text.y);
}
Of course you will need to create different kinds of objects:
an object that defines text.
an object that defines an image.
an object that defines a background rectangle.
an object that defines a captioned image (image+text).
Here's starting example code and a Demo: http://jsfiddle.net/m1erickson/WNaLn/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
// get a reference to the canvas and context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// the contents[] array will hold individual content objects
// the content objects will be used to later draw the content to the tab
var contents=[];
// load a test image
var house=new Image();
house.onload=start;
house.src="houseIcon.png";
function start(){
// create some test contents
// tab background
addBackgroundRect(0,0,275,275,"red");
// left panel example
addBackgroundRect(10,10,100,250,"lavender");
addImageContent(house,50,15,20,20);
addImageContent(house,75,65,20,20);
addImageContent(house,50,110,20,20);
addImageContent(house,15,65,20,20);
addImageContent(house,40,65,30,30);
// right panel example
addBackgroundRect(110,10,150,100,"white");
addTextContent("Text1",115,20,"red");
addTextContent("Text2",115,40,"red");
addTextContent("Text3",115,60,"red");
addTextContent("Text4",115,80,"red");
addTextImageContent("Caption",house,175,20,60,60);
drawContents(contents);
}
// draw all content in the contents array
function drawContents(contents){
for(var i=0;i<contents.length;i++){
var content=contents[i];
//
switch (content.type){
case "background":
drawBackgroundRect(content);
break;
case "text":
drawTextContent(content);
break;
case "image":
drawImageContent(content);
break;
case "textImage":
drawTextImageContent(content);
break;
default:
break;
}
}
}
// draw contents based on a content object
function drawBackgroundRect(bk){
ctx.fillStyle=bk.color;
ctx.fillRect(bk.x,bk.y,bk.width,bk.height);
}
//
function drawTextContent(text){
ctx.fillStyle=text.color;
ctx.fillText(text.text,text.x,text.y);
}
//
function drawImageContent(img){
ctx.drawImage(img.image,img.x,img.y,img.width,img.height);
}
//
function drawTextImageContent(tImg){
ctx.drawImage(tImg.image,tImg.x,tImg.y,tImg.width,tImg.height);
ctx.fillStyle="black";
ctx.fillRect(tImg.x,tImg.y+tImg.height-15,tImg.width,15);
ctx.fillStyle="white";
ctx.fillText(tImg.text,tImg.x+5,tImg.y+tImg.height-4);
}
// create content objects
function addBackgroundRect(x,y,width,height,color){
contents.push({
type:"background",
x:x,
y:y,
width:width,
height:height,
color:color
});
}
//
function addTextContent(text,x,y,color){
contents.push({
type:"text",
text:text,
x:x,
y:y,
color:color
});
}
//
function addImageContent(imgObject,x,y,width,height){
contents.push({
type:"image",
image:imgObject,
x:x,
y:y,
width:width,
height:height
});
}
//
function addTextImageContent(text,imgObject,x,y,width,height){
contents.push({
type:"textImage",
text:text,
image:imgObject,
x:x,
y:y,
width:width,
height:height
});
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</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>