I feel I am being incredible stupid but for some reason am blind to being able to fix this issue.
I want 3 individual layers, each that can have multiple object/shapes on them and then on click I want the visible layer to be removed or hid and the next layer to appear.
I think my issue is dying in the logic and calling the function. Here is the function and the jsfiddle:
var version = 0;
function layerVersion() {
if (version === 1) {
stage.add(layerBlue);
layerBlue.on('click', function() {
layerOrange.hide;
version = 2;
});
} else if (version === 2) {
stage.add(layerOrange);
} else {
stage.add(layerPink);
layerpink.on('click', function() {
layerPink.hide;
version = 1;
});
}
}
Here is the jsFiddle link: http://jsfiddle.net/TJ96r/2/
Any help would be much appreciate I feel so dumb for not being able to figure it out.
Check this out.
http://jsfiddle.net/TJ96r/3/
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layerPink = new Kinetic.Layer();
layerPink.hide();
var layerBlue = new Kinetic.Layer();
var layerOrange = new Kinetic.Layer();
layerOrange.hide();
// pink box
var pink = new Kinetic.Rect({
x: 50,
y: 50,
width: 100,
height: 100,
fill: 'pink',
stroke: 'black',
strokeWidth: 2
});
// blue box
var blue = new Kinetic.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
fill: 'blue',
stroke: 'black',
strokeWidth: 2
});
// orange box
var orange = new Kinetic.Rect({
x: 150,
y: 150,
width: 100,
height: 100,
fill: 'orange',
stroke: 'black',
strokeWidth: 2
});
layerPink.add(pink);
layerBlue.add(blue);
layerOrange.add(orange);
var version = 0;
stage.add(layerBlue);
stage.add(layerOrange);
stage.add(layerPink);
layerBlue.on('click', function() {
layerBlue.hide();
layerOrange.show();
layerPink.hide();
stage.draw();
});
layerOrange.on('click', function() {
layerBlue.hide();
layerOrange.hide();
layerPink.show();
stage.draw();
});
layerPink.on('click', function() {
layerPink.hide();
layerOrange.hide();
layerBlue.show();
stage.draw();
});
Related
The following snippet has a green square above a red square
Select both squares by dragging over them.
Click the bring forward button
After clicking bring forward the squares have switched order. It is my understanding that the items should stay in the same order, but be moved increasingly above other non-selected items as the button is further clicked.
If you deselect, and repeat the experiment you will see that they switch again.
Any ideas?
var canvas = new fabric.Canvas('c',
{
preserveObjectStacking : true
});
var rect = new fabric.Rect({
left: 10, top: 10,
fill: 'red',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect);
var rect2 = new fabric.Rect({
left: 40, top: 40,
fill: 'green',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect2);
$("#bringForward").click(function()
{
var items = canvas.getActiveObject() || canvas.getActiveGroup();
if(items)
items.bringForward();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>
<canvas id="c" width="640" height="480"></canvas>
This can be considered a bug or not, depending on what do you expect the function to do.
The documentation for the feature says:
Moves an object or a selection up in stack of drawn objects
And is actually doing so.
The object on top cannot go more on top, the one under can and goes.
Still for a dev this can look like a weird behaviour, to me not really. But guess is personal.
Here is your widget with a modified snippet to try a better solution.
var removeFromArray = fabric.util.removeFromArray;
// modified function to avoid snapping
fabric.StaticCanvas.prototype.bringForward = function (object, intersecting) {
if (!object) {
return this;
}
var activeGroup = this._activeGroup,
i, obj, idx, newIdx, objs, latestIndex;
if (object === activeGroup) {
objs = activeGroup._objects;
latestIndex = this._objects.length;
for (i = objs.length; i--;) {
obj = objs[i];
idx = this._objects.indexOf(obj);
if (idx !== this._objects.length - 1 && idx < latestIndex - 1) {
newIdx = idx + 1;
latestIndex = newIdx;
removeFromArray(this._objects, obj);
this._objects.splice(newIdx, 0, obj);
} else {
latestIndex = idx;
}
}
}
else {
idx = this._objects.indexOf(object);
if (idx !== this._objects.length - 1) {
// if object is not on top of stack (last item in an array)
newIdx = this._findNewUpperIndex(object, idx, intersecting);
removeFromArray(this._objects, object);
this._objects.splice(newIdx, 0, object);
}
}
this.renderAll && this.renderAll();
return this;
};
var canvas = new fabric.Canvas('c',
{
preserveObjectStacking : true
});
var rect = new fabric.Rect({
left: 10, top: 10,
fill: 'red',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect);
var rect2 = new fabric.Rect({
left: 40, top: 40,
fill: 'green',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect2);
var rect3 = new fabric.Rect({
left: 70, top: 70,
fill: 'blue',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect3);
var rect4 = new fabric.Rect({
left: 100, top: 100,
fill: 'orange',
width: 100, height: 100,
hasControls: true
});
canvas.add(rect4);
$("#bringForward").click(function()
{
var items = canvas.getActiveObject() || canvas.getActiveGroup();
if(items)
items.bringForward();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.6/fabric.min.js"></script>
<button id="bringForward">Bring Forward</button>
<canvas id="c" width="640" height="480"></canvas>
I am inspired with KonvaJS tutorial Modify Curves with Anchor Points to make my own example which is to create multiple custom arrows.
on click on the selectionBox create an anchor.
on the creation of the third anchor create the curved arrow.
on the fourth click reset all variables in order to draw a new curved arrow.
var width = window.innerWidth;
var height = window.innerHeight;
// globals
var selectionBoxLayer, curveLayer, lineLayer, anchorLayer, quad, bezier;
function updateDottedLines() {
var q = quad;
var quadLine = lineLayer.get('#quadLine')[0];
quadLine.setPoints([q.start.attrs.x, q.start.attrs.y, q.control.attrs.x, q.control.attrs.y, q.end.attrs.x, q.end.attrs.y]);
lineLayer.draw();
}
function buildAnchor(x, y) {
var anchor = new Konva.Circle({
x: x,
y: y,
radius: 20,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
draggable: true
});
// add hover styling
anchor.on('mouseover', function() {
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
anchorLayer.draw();
});
anchor.on('mouseout', function() {
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
anchorLayer.draw();
});
anchor.on('dragend', function() {
drawCurves();
updateDottedLines();
});
anchorLayer.add(anchor);
anchorLayer.draw();
return anchor;
}
function drawCurves() {
var context = curveLayer.getContext();
var arrowLine = new Konva.Shape({
sceneFunc: function(context){
debugger;
// draw quad
context.beginPath();
context.moveTo(quad.start.attrs.x, quad.start.attrs.y);
context.quadraticCurveTo(quad.control.attrs.x, quad.control.attrs.y, quad.end.attrs.x, quad.end.attrs.y);
//Draw Arrow Head
var headlen = 10; // length of head in pixels
var angle = Math.atan2(quad.end.attrs.y - quad.control.attrs.y, quad.end.attrs.x - quad.control.attrs.x);
context.lineTo(quad.end.attrs.x-headlen*Math.cos(angle-Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle-Math.PI/6));
context.moveTo(quad.end.attrs.x, quad.end.attrs.y);
context.lineTo(quad.end.attrs.x- headlen*Math.cos(angle+Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle+Math.PI/6));
context.fillStrokeShape(this);
},
stroke: 'black',
strokeWidth: 4
});
curveLayer.add(arrowLine);
curveLayer.draw();
}
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
selectionBoxLayer = new Konva.Layer();
anchorLayer = new Konva.Layer();
lineLayer = new Konva.Layer();
// curveLayer just contains a canvas which is drawn
// onto with the existing canvas API
curveLayer = new Konva.Layer();
var quadLine = new Konva.Line({
dash: [10, 10, 0, 10],
strokeWidth: 3,
stroke: 'black',
lineCap: 'round',
id: 'quadLine',
opacity: 0.3,
points: [0, 0]
});
// add dotted line connectors
lineLayer.add(quadLine);
quad = {};
// keep curves insync with the lines
anchorLayer.on('beforeDraw', function() {
if(quad.start && quad.control && quad.end){
drawCurves();
updateDottedLines();
}
});
var selectionBoxBackground = new Konva.Rect({
x: 0,
y: 0,
height:stage.height(),
width: stage.width(),
fill: 'transparent',
draggable: false,
name: 'selectionBoxBackground'
});
selectionBoxLayer.add(selectionBoxBackground);
var clickCounter = 0;
selectionBoxBackground.on("click", function(){
clickCounter +=1;
var mousePos = {};
switch(clickCounter){
case 1:
mousePos = stage.getPointerPosition();
quad.start = buildAnchor(mousePos.x, mousePos.y);
break;
case 2:
mousePos = stage.getPointerPosition();
quad.control = buildAnchor(mousePos.x, mousePos.y);
break;
case 3:
mousePos = stage.getPointerPosition();
quad.end = buildAnchor(mousePos.x, mousePos.y);
drawCurves();
updateDottedLines();
break;
default:
clickCounter = 0;
quad = {};
anchorLayer.destroyChildren();
anchorLayer.draw();
}
});
stage.add(curveLayer);
stage.add(lineLayer);
stage.add(selectionBoxLayer);
stage.add(anchorLayer);
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
<script src="https://cdn.rawgit.com/konvajs/konva/0.11.1/konva.min.js"></script>
<body>
<div id="container"></div>
</body>
P.S Please note when I write in the browser console curveLayer.children, it will bring all created curved arrows.
Hint: I think on the creation of new Shape() the values of all created shapes will be changed to the new one.
I don't know what I am missing.
I need to create a kind of container to manage dynamic actions with KineticJS.
I have a simple object from which we will be able to add a circle by using a function.
Here's my code:
function Stage() {
var self = this;
self.stage = new Kinetic.Stage({
container: "museumMapContainer",
width: 500,
height: 500
});
self.layer = new Kinetic.Layer();
self.addCircle = function (x,y) {
var circle = new Kinetic.Circle({
x: x,
y: y,
radius: 40,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
self.layer.add(circle);
}
self.stage.add(self.layer);
}
stage = new Stage();
stage.addCircle(250,250);
Normally, if I don't put the code inside a function, I can easily create a circle without any problems. However, this code doesn't work and I really don't know why.
Here's a Plunker: http://plnkr.co/edit/E1fbCFMeZwGNAKhsArhm?p=preview
There are no errors in the console and nothing is showing and I don't know why...
Make sure you do layer.draw after creating your new circles:
<!DOCTYPE html>
<html>
<head>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v5.0.1.min.js"></script>
</head>
<body>
<h1>Hello Plunker!</h1>
<div id="museumMapContainer" style="width:500px;height:500px;border:1px solid black;"></div>
<script defer="defer">
function Stage() {
var self = this;
self.stage = new Kinetic.Stage({
container: "museumMapContainer",
width: 500,
height: 500
});
self.layer = new Kinetic.Layer();
self.stage.add(self.layer);
self.addCircle = function (x,y) {
var circle = new Kinetic.Circle({
x: x,
y: y,
radius: 40,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
circle.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
circle.on('mouseout', function() {
document.body.style.cursor = 'default';
});
self.layer.add(circle);
self.layer.draw();
}
}
stage = new Stage();
stage.addCircle(250,250);
</script>
</body>
</html>
i'm working on a drag&drop-function for images. I've oriented myself on this example here:
http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/
The JS framework KineticJS is used there.
In this example the properties (x,y,width,height) of Kinetic.Group and Kinetic.Image are set with 'normal' number values.
my problem is that i need this properties as variables, because my uploaded images have different values for height, width etc.
I've tried to change the code from the example for my own drag&drop web application, but it doesn't work as i want...
I can load and display images correctly, but i can't move or resize them. With number values for x,y,width,height it works all.
Here is the code of the changed method "initStage()" (the other methods are unchanged):
function initStage(images) {
stage = new Kinetic.Stage({
container: 'wb_dropzone',
width: 500,
height: 400
});
var imageGroups = new Array();
var imageInstances = new Array();
var layer = new Kinetic.Layer();
for(var i=0; i<Object.size(images); i++)
{
imageGroups[i] = new Kinetic.Group({
x: fileInfos[i][2][0]/*0*/,
y: fileInfos[i][2][1]/*0*/,
draggable: true
});
layer.add(imageGroups[i]);
imageInstances[i] = new Kinetic.Image({
x: 0/*fileInfos[i][2][0]*/,
y: 0/*fileInfos[i][2][1]*/,
image: images[i],
width: fileInfos[i][1][0],
height: fileInfos[i][1][1],
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
imageGroups[i].add(imageInstances[i]);
addAnchor(imageGroups[i], 0, 0, 'topLeft');
addAnchor(imageGroups[i], fileInfos[i][1][0], 0, 'topRight');
addAnchor(imageGroups[i], fileInfos[i][1][0], fileInfos[i][1][1], 'bottomRight');
addAnchor(imageGroups[i], 0, fileInfos[i][1][1], 'bottomLeft');
imageGroups[i].on('dragstart', function() {
this.moveToTop();
});
}
stage.add(layer);
stage.draw();
}
More informations about "fileInfos":
[imagePath, [width, height], [X-pos., Y-pos.]]
(all dropped images are uploaded in a folder. The properties of each image are saved in a database.
Default x- and y-position is "0".)
Does anybody have an idea, how i can solve this problem?
I'm grateful for any help!
How to create draggable/resizable images that are loaded from your fileInfos
Call a function that creates the group+image+anchors based on your fileInfos[i]:
// pull info supplied by fileInfos for this “i”
var imgWidth=fileInfos[i][1][0];
var imgHeight=fileInfos[i][1][1];
var groupX=fileInfos[i][2][0];
var groupY=fileInfos[i][2][1];
// call a function that creates the draggable/resizable group
addImageGroup( images[i], imgWidth,imgHeight, groupX,groupY );
Here’s that function that creates the draggable/resizable group element:
function addImageGroup(image,imageWidth,imageHeight,groupX,groupY){
// width and height are based on the images width/height
var w=imageWidth;
var h=imageHeight;
var kGroup = new Kinetic.Group({
x:groupX,
y:groupY,
width:w+20, // must allow 10+10=20 for anchors
height:h+20,
draggable:true
});
layer.add(kGroup);
kGroup.on('dragstart', function() {
this.moveToTop();
});
var kImage = new Kinetic.Image({
x: 0,
y: 0,
image: image,
width: w,
height: h,
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
kGroup.add(kImage);
addAnchor(kGroup, 0, 0, 'topLeft');
addAnchor(kGroup, w, 0, 'topRight');
addAnchor(kGroup, w, h, 'bottomRight');
addAnchor(kGroup, 0, h, 'bottomLeft');
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/buCzH/
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
#container{
border:1px solid red;
width:350px;
height:350px;
}
</style>
</head>
<body onmousedown="return false;">
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.2.min.js"></script>
<script>
// create the stage
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer=new Kinetic.Layer();
stage.add(layer);
// build a test fileInfos array
// width/height will be gotten from actual images, so leave width/height==0
var fileInfos=[];
function addFile(x,y,w,h,imgURL){
fileInfos.push([imgURL,[w,h],[x,y]]);
}
addFile(30,100,102,102,"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg");
addFile(200,100,102,102,"https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg");
// load all the images
var images=[];
loadAllImages();
function loadAllImages(){
var imagesOK=0;
for (var i = 0; i < fileInfos.length; i++) {
var img = new Image();
images.push(img);
img.onload = function(){
if (++imagesOK==fileInfos.length ) {
// all images are loaded, so build the groups
for(var i=0;i<fileInfos.length;i++){
var imgWidth=fileInfos[i][1][0];
var imgHeight=fileInfos[i][1][1];
var groupX=fileInfos[i][2][0];
var groupY=fileInfos[i][2][1];
addImageGroup( images[i], imgWidth,imgHeight, groupX,groupY );
}
layer.draw();
}
};
img.src = fileInfos[i][0];
}
}
function addImageGroup(image,imageWidth,imageHeight,groupX,groupY){
// width and height are based on the images width/height
var w=imageWidth;
var h=imageHeight;
var kGroup = new Kinetic.Group({
x:groupX,
y:groupY,
width:w+20, // must allow 10+10=20 for anchors
height:h+20,
draggable:true
});
layer.add(kGroup);
kGroup.on('dragstart', function() {
this.moveToTop();
});
var kImage = new Kinetic.Image({
x: 0,
y: 0,
image: image,
width: w,
height: h,
name: 'image',
stroke: 'black',
strokeWidth: 2,
dashArray: [10, 2]
});
kGroup.add(kImage);
addAnchor(kGroup, 0, 0, 'topLeft');
addAnchor(kGroup, w, 0, 'topRight');
addAnchor(kGroup, w, h, 'bottomRight');
addAnchor(kGroup, 0, h, 'bottomLeft');
}
function update(activeAnchor) {
var group = activeAnchor.getParent();
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var image = group.get('.image')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
// update anchor positions
switch (activeAnchor.getName()) {
case 'topLeft':
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
image.setPosition(topLeft.getPosition());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
image.setSize(width, height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
</script>
</body>
</html>
I am new with HTML5.
I have to implement such a functionality that I want images to be dropped within a canvas from outside, then there are visible boundaries within canvas and the images can be moved from one boundary to another. It is the same as in the following link,
http://custom.case-mate.com/diy?bypassLandingPage=true
As, in the site, user selects the pattern and drags images into that. Then he can drag the images between the boundaries. please give some solution for implementing such a functionality.
Here is what I have tried,
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
canvas {position:relative;
left:150%;
border: 10px solid #9C9898;
background-color: grey;
}
</style>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v3.10.0.js"></script>
<script>
window.onload = function() {
var stage = new Kinetic.Stage({
container: "container",
width: 300,
height: 400,
});
var layer = new Kinetic.Layer();
var redLine = new Kinetic.Line({
points: [150, 0, 150, 400],
stroke: "white",
strokeWidth: 2,
});
var blueLine = new Kinetic.Line({
points: [150, 0, 150, 120, 300, 120],
stroke: "white",
strokeWidth: 2,
});
var thirdLine = new Kinetic.Line({
points: [300, 120, 150, 120, 150, 400],
stroke: "white",
strokeWidth: 2,
});
var imageObj = new Image();
imageObj.onload = function() {
var image = new Kinetic.Image({
x: stage.getWidth() / 2 - 50,
y: stage.getHeight() / 2 - 60,
image: imageObj,
width: 100,
height: 120,
});
image.draggable(true);
layer.add(image);
// add the layer to the stage
stage.add(layer);
};
imageObj.src = "images/212.png";
layer.add(redLine);
layer.add(blueLine);
layer.add(thirdLine);
stage.add(layer);
};
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
Here's a nice tutorial on HTML5 native drag'n'drop:
http://www.html5rocks.com/en/tutorials/dnd/basics/
Basically you can declare an item as draggable in HTML5 with the draggable attribute
<div class="draggable" draggable="true">A</div>
<div class="draggable" draggable="true">B</div>
...and then use Javascript to handle some events like:
var items = document.querySelectorAll('.draggable');
[].forEach.call(items, function(item) {
item.addEventListener('dragstart', function(){ /*handle drag start*/ }, false);
item.addEventListener('dragenter', function(){ /*handle drag enter*/ }, false)
item.addEventListener('dragover', function(){ /*handle drag over*/ }, false);
item.addEventListener('dragleave', function(){ /*handle drag leave*/ }, false);
item.addEventListener('drop', function(){ /*handle drop*/ }, false);
item.addEventListener('dragend', function(){ /*handle drag end*/ }, false);
});