I have a little tool that draws up a grid of circles(representing holes) that allows the user to add text and lines to these circles. Right now I have it set up so if the user clicks on any of the holes then wherever the hole is moved so is every other element on the Paper object. What I am trying to implement next is the ability to rotate everything as one object. I realize that for this to work that I need to know the central point of all the objects, which I can easily get.
What I want to know is should I draw everything on another object. This object will act as another Paper object of sorts, but will only serve for movement and rotation. Any click events on the holes drawn on the object will be passed on to the parent (i.e. the pseudo-paper object everything is drawn on). Is this possible? If so how would I draw everything onto say, a rectangle? And if not what would be the best way to go implementing it?
What you need is a Set. You create it, push objects to it, and then treat it as an entire group, in your case by applying transformations.
Example:
var elements = paper.set();
if (!view.text) {
view.text = App.R.text(0, 0, this.value);
view.text.attr({
'font-size': font_size,
});
elements.push(view.text);
}
elements.transform('something');
Note that you can also bind events to this entire set.
Related
So, I want to create a finite state machine-visualizer/editor with the help of kineticjs and i'm stumbling with the following scenario:
I have two "nodes", let's say circle-objects (grouped with a label) which are draggable on my stage. Now I wan't to click on one circle, hold the mouse and move it and add a connection (an arrow, for simplicities sake) between the two shapes.
So it would be great to have any hints on how to accomplish this for I haven't found a solution yet.
To specify it: The nodes themselves should stay draggable. My thought was: Add a black circle and a white circle with a slightly smaller radius, group them. then on dragstart white circle -> drag node, on dragstart black circle -> draw arrow.
The Problem is how to draw an arrow starting from one shape and following the mouse to it's target (which can be another nodegroup => connection to this group or a blank point of the stage => an overlay opens which lets the user choose another node to draw or cancel the drawing).
I hope this is somewhat clear to understand. For more information please feel free to ask me.
Best regards,
Dominik
p.s.: The behaviour seems to be exactly like the behaviour lucidchart (dot com) uses when creating diagrams, so maybe you understand what I want to achieve better looking at their demo here: https://www.lucidchart.com/demo .
First off, for simplicity's sake here is a fiddle on how to draw a basic Line with your mouse and KineticJS: http://jsfiddle.net/projeqht/fF3hh/
Let's say you already have two circles on the stage, and you need to draw a line to connect them.
We can use e.targetNode to select the nodes on each event (mousedown, mouseup), for example:
layer.on("mousedown", function (e) {
var nodeDown = e.targetNode;
}
layer.on("mouseup", function (e) {
var nodeUp = e.targetNode;
}
We need to check if the parent of nodeDown is a Kinetic.Group or something else.
If the target node nodeDown has a Kinetic.Group for a parent, we can use this Group to store the new line, and the 2nd target node nodeUp.
If the target node nodeUp does not have a Kinetic.Group for a parent, we need to see if nodeUp has a Group for a parent. If nodeUp has a Kinetic.Group for a parent, then we can use that Group to store the new line, and the first target node nodeDown.
If neither nodeDown or nodeUp have a group for a parent, then we will need to create a new group for them and add all 3 shapes (2 circles and a line) to that new group.
Use this tutorial to learn how to move shapes from 1 group to another: http://www.html5canvastutorials.com/kineticjs/html5-canvas-move-shape-to-another-container-with-kineticjs/
Also, if you move a shape from one group to another, you may want to remove() or destroy() the extra group if it is no longer needed.
While drawing a Line, you will have to disable dragging the shapes, so that you can drag and draw with a mouse. You can do that by doing something similar to this:
function stopDrag() {
for (var i=0; i<layer.children.length; i++) {
layer.children[i].setDraggable(false);
}
}
function startDrag() {
for (var i=0; i<layer.children.length; i++) {
layer.children[i].setDraggable(true);
}
}
This will make all the children of layer draggable and undraggable, but you might want to limit that by being more specific than select layer.children. A nice trick I liked to use here was to name all groups that were draggable as "draggable_shapes" and then use var draggableArray = stage.get('.draggable_shapes') to select all the groups that are allowed to be dragged, then you could loop through that array and setDraggable().
Another point to note is that the X and Y coordinates of the Line will be a bit tricky to calculate, depending on if it has a Group as a parent or a Layer. If the Line is grouped, line's coordinates will be relative to the Group position, or else the Line's coordinates will be relative to the Stage (top left corner).
This will get you started on connecting a line with two different circles. It's up to you to do the coordinate logic if you want the lines to only connect on the outer rim of the circles.
Maybe you might want to add a transparent rectangle (attribute opacity: 0) behind each circle, so that on mousedown with the rectangle, you will call drawLine() to start drawing a line. Or else if the user clicks the circle, it will drag the group. At least that has similar functionality to the lucid charts application.
Custom Hit Function (http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-custom-hit-function-tutorial/) would probably be a cleaner way to do this but I'm not 100% on using Custom Hit Functions, someone else might know better.
Let me know if you need further help. Good luck!
I the speech bubbles to be next to the person who says them but how do I change the position? I don't want to have any more animations for that, is it possible?
link: http://www.tlu.ee/~kristo93/Eritamine%20-%20puhas/p6hi.html
for example the next tere would be positioned next to the students.
There is always an X-Y co-ordinate of any group or element you create using the kinetic.js
You just need to manipulate X-Y property of the group containing your speech cloud.
suppose your reference to that cloud group is called cloudGroup then set the X and Y property using the method as follows:
cloudGroup.setX(100);
cloudGroup.setY(100);
So just insert anything instead of 100, which suits the position you desire.
I have an isometric map that has selectable tiles. The map is formed by a matrix such as $('div').gameMap({map:[[{"tile":"tile_0","object":"anObjectOnTile"},{"tile":"tile_3","object":""}], [{...}]],mapsize:3}); If the tile has something within the object:"", then that tile has that object (in my case, an image of an oil derrick) on top of that tile.
There is a Place button which when clicked should place an oil derrick object on top of the currently selected tile.
However, I have run into two problems:
Knowing which tile is currently selected
Adding a single oil derrick
At first I wanted to figure a way to modify the map's matrix to insert the object's name (oilDerrick) into the tile's object parameter, but now I think the better solution would be to append the oilDerrick to the tile. I can't figure out how to append to the particular tile and not every tile.
I've got the code set up to look at and play with: http://jsfiddle.net/briz/jdhPW/13/
There's an oilDerrick object set up in the map's matrix for you to view, which can be removed by deleting the word oilDerrick in the matrix
I played with $(".tile").append($('.oilDerrick')); though I knew that would append to every tile. But I simply do not know enough about appending yet to figure out how to limit it to a single instance.
Each tile has a unique ID. I also tried this in order to add an oilDerrick to a certain tile:
$("#placeButton").click(function()
{
for (var y in config.map)
{
for (var x in config.map[y])
{
document.getElementById(obj.attr('id') + '_tile_' + x + '_' +y).appendChild(".oilDerrick");
}
}
}
But this came to no avail as well. I think I'm heading in the right direction though? Can anyone help?
I did some modifications.
There a little mess in your code. For example, your using jquery but there is a lot of direct DOM manipulation.
.style.background = ...
// should be
.css("background",...)
And the most important:
document.getElementById(...)
// should be
$("#...")
Easier, don't you think? Then, the problem is simple solved by creating a var currentTile and when the user select one tile, it save it. When click in 'place', $(currentTile).append($('.oilDerrick')); And the oil derrick move to where to selected tile.
Anyway, more details you can see in the link.
Hi I am playing around with shapes and canvas and I have a question:
So say I have this code that draws a nice rectangle on the canvas:
$("#create_rectangle").bind("click", function() {
if(canvas[0].getContext){
var ctx = canvas[0].getContext('2d');
ctx.strokeRect(50,50,50,50);
}
});
Now I say I want to store a reference to that rectangle so that I can make alteration to it at a later stage. The stokeRect() method does not seem to return any value. How do I reference that particular rectangle that was created?
Well you can't reference it, but you can include it in a draw function which depending your arguments allow you to move/rotate hide etc.
It very depend on what you want to do with this shape.
This tutorial can be helpfull to understand manipulation of shape.
http://simonsarris.com/blog/140-canvas-moving-selectable-shapes
You can't.
Canvas is basically just a canvas. You throw some paint at it, it dries and you're done. You can't take your paint and move it somewhere elseābut you can paint over it.
What you may want is SVG. It keeps track of shapes and other assorted things so that you can change them, deal with interactions much more precisely, et cetera.
I wish to create a click-able object on a tag with javascript/jQuery.
This obviously dosen't work.
var cow = new Object();
cow = ctx.drawImage(tile,cursorH,cursorV);
$(cow).click{function(){
alert('You clicked a cow!');
});
The solution is simple, but requires some groundwork be laid. First, you'll need to keep track of the "objects" you draw on the canvas. Perhaps create your own object class that keeps track of position and size. Secondly you override the onclick event for the canvas and perform a hit test on all your visible objects. The ones that are located under your cursor at the time of the click were clicked upon.
I don't think you can do it "right out of the box." Check out Fabric.js (demo) though, I believe it has support for drawing selectable objects to the canvas.