I want to make temporary group and add nodes to it, so that they become draggable (because group is).
Then i want to remove those nodes from that group and add other nodes to that group, make them movable and others unmovable.
Group is movableGroup:
var movableGroup= new Kinetic.Group({
draggable: true,
});
I want to add shapes to it.
I want to add new shapes to it and remove shapes that was added before these.
To remove all child nodes of a group:
moveableGroup.removeChildren();
Then you can add some new nodes to the group:
var box = new Kinetic.Rect({
x: 0,
y: 0,
width: width,
height: height,
stroke : 'black',
strokeWidth: 1
});
moveableGroup.add(box);
Related
I have the button which add new group which have square, to layer when clicked very simple code I guess no need to post. But my question is that how can I add transformer to it when on clicked?, I have done it with this mouseleave and mouseenter functions.
group.on('mouseenter', () => {
transformer.borderEnabled(true);
transformer.resizeEnabled(true);
layer.draw();
});
group.on('mouseleave', () => {
transformer.borderEnabled(false);
transformer.resizeEnabled(false);
layer.draw();
});
It is in loop which creates new group named "group", It works fine but in circle when I hover it the transformer appears but then when I go to transformer's boxes to resize it consider as it is mouseleave but this is doing only in circle not in line text.
So can I have solution for active transformer on element which is clicked or for considering hover on transformer boxes as a hover on node? Thanks
The mouseleave() will always fire because the pointer must leave the group to use the transformer handles or spinner.
An alternative approach would be
click to enable the transformer,
leave the transformer in place even when the mouse moves away
wait for a click on some other shape to know you can hide the transformer.
That is the standard GUI approach I believe.
If you need to show hover focus then stick a transparent rectangle the size of the groups clientrect into the group and change its stroke from transparent to some colour in the mouseenter and back in the mouseleave. You will also maybe want to set the rect.listening to false so as it coes not interfere with mouse events on the shapes in the group, but then again it might help in dragging.
Demo below.
// Set up the canvas and shapes
let stage = new Konva.Stage({container: 'container1', width: 300, height: 200});
let layer = new Konva.Layer({draggable: false});
stage.add(layer);
// Add a transformer.
let transFormer1 = new Konva.Transformer();
layer.add(transFormer1);
// Create a sample group
let group1 = new Konva.Group();
layer.add(group1);
group1.add(new Konva.Circle({x: 20, y: 30, radius: 15, fill: 'magenta', stroke: 'black'}))
group1.add(new Konva.Circle({x: 60, y: 40, radius: 15, fill: 'magenta', stroke: 'black'}))
group1.add(new Konva.Rect({x: 90, y: 60, width: 25, height: 25, fill: 'magenta', stroke: 'black'}));
let pos = group1.getClientRect();
let boundRect1 = new Konva.Rect({name: 'boundRect', x: pos.x, y: pos.y, width: pos.width, height: pos.height, fill: 'transparent', stroke: 'transparent'});
group1.add(boundRect1);
// When mouse enters the group show a border
group1.on('mouseenter', function(){
let boundRect = this.find('.boundRect');
boundRect[0].stroke('red');
layer.draw();
})
// and remove border when mouse leaves
group1.on('mouseleave', function(){
let boundRect = this.find('.boundRect');
boundRect[0].stroke('transparent');
layer.draw();
})
// If the group is clicked, enable the transformer on that group.
group1.on('click', function(){
transFormer1.attachTo(this)
layer.batchDraw();
})
// For a more pleasing demo let us have 2 groups.
// Make a copy of group1, offset new group, and change fill on its child shapes except the bound rect
let group2 = group1.clone();
layer.add(group2)
group2.position({x: 120, y: 30});
for (let i = 0, shapes = group2.getChildren(); i < shapes.length; i = i + 1){
shapes[i].fill(shapes[i].fill() !== 'transparent' ? 'cyan' : 'transparent');
}
stage.draw();
<script src="https://unpkg.com/konva#^3/konva.min.js"></script>
<p>Move mouse over the shapes to see the group borders, click a group to apply the transformer.
</p>
<div id='container1' style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;"></div>
Got the answer!, I just create a public transformer and on stage click I am adding nodes to it no transformer to each group just one public transformer which hold one node at a time.
I'm trying to get an SVG Snap element by it's id. First I create a canvas:
var s = Snap("#svgout"), //creates the canvas
Then I cerate a group:
var rect = s.rect(posx, posy, 40, 40, 6).attr({
fill: "none",
stroke: "#F44336",
strokeWidth: 3,
});
var group = s.group(rect).attr({
cursor: "move",
});
and next I get the id of the group that is defaulted by SVG Snap
var currGroupId = group.id;
Now, when I try to reference my group later in my code and get it by it's id,
s.select(currGroupId);
I get null. How do I properly select an element by it's id?
select will use a cssSelector, as in container.queryAll.
So I don't think Snap sets an id as an svg attribute (do correct me if I'm wrong). Which means if you want to use select, you may have to manually set it.
Also I susect s.select(id) wouldn't work, I think it would have to be s.select('#'.id) but I may be wrong. If you can get a fiddle up, it will be easier to test.
SnapSVG doesn't automatically set the ID attribute of the group. Instead it adds a field to the object itself. One way of getting around this limitation is to do the following.
var s = Snap("#svgout");
var rect = s.rect(posx, posy, 40, 40, 6).attr({
fill: "none",
stroke: "#F44336",
strokeWidth: 3,
});
var group = s.group(rect).attr({
cursor: "move",
});
Explicitly set the ID.
group.attr({
id: group.id
});
var currGroupId = group.id;
select uses CSS selectors. So we must add a '#' to the start of the ID.
s.select("#" + currGroupId);
Note: This method has been tested by me using SnapSVG V0.4.1
If this does not work and you are using jQuery. try:
$("#"+currGroupId);
I have a palette and diagram side by side using the same template.
var template = $(go.Node, "Horizontal",
$(go.Shape,
{ width: 15, height: 15, fill: "white" },
new go.Binding("fill", "color")),
$(go.TextBlock,
new go.Binding("text", "color"))
);
I would like to arrange the nodes top down then one it reaches the bottom, it would warp and start top down again next to the previous "column"
Any ideas how I can accomplish this? do I need to change he template or is there some setting to achieve this
Here is a fiddle of what I have: http://jsfiddle.net/loanburger/v61bufs0/
My end goal is to a have a list of emails in the palette then drag them into the diagram for a include list
Thanks,
I have found the solution to this and will answer the question in detail for the benefits of other:
To accomplish what I was after I split my templates for the palette and diagram so each has their own.
On the diagram I did not want the nodes draggable so I set its template movable: false so the user cannot drag the node again.
Then when creating the diagram you can specify a layout. So using a GridLayout I did the following:
var myDiagram = $(go.Diagram, "myDiagramDiv",
{
layout: $(go.GridLayout,
{
cellSize: new go.Size(200, 20),
wrappingColumn: 1
}),
"undoManager.isEnabled": true
});
I specified a single column.
I also set the contentAlighment property to top left:
myDiagram.startTransaction("");
myDiagram.contentAlignment = go.Spot.TopLeft;
myDiagram.commitTransaction("");
Since I did not want the diagram nodes draggable I set the myDiagram.allowDragOut= false; as well so that a node cannot be dragged out of the diagram. I found if I did not do this even though a node was not draggable if it was selected I could drag the selection
For the pallet its the same concept for the layout:
var myPalette = $(go.Palette, "myPaletteDiv",
{
layout: $(go.GridLayout,
{
cellSize: new go.Size(200, 20),
wrappingColumn: 1
})
});
And also for the contentAlighment property:
myPalette.startTransaction("");
myPalette.contentAlignment = go.Spot.TopLeft;
myPalette.commitTransaction("");
The end result can be viewed in this revised JS Fiddle: http://jsfiddle.net/loanburger/v61bufs0/9/
I am trying to create group object that include text,image .
I want to get right position(x,y) when dragging the group object.
Now i get minus value {x:-26,y:-18} like that.
var text2=new Kinetic.Text({
x: 40,
y: 125,
text: 'Time:4:20',
fontFamily: 'Calibri',
fontSize: 12,
padding: 5,
fill: 'red',
draggable: false
});
var group = new Kinetic.Group({
width:94,
height:45,
draggable: true
});
group.on('dragend', function() {
alert("X:"+group.getAbsolutePosition().x+"Y:"+group.getAbsolutePosition().y);
});
group.add(text2);
layer.add(group);
stage.add(layer);
Your code is working normally.
You have a non-draggable text on the draggable group.
This causes the text to act as a "handle" to drag whole group.
(the text does not move relative to the group. Instead the whole group is moved by dragging the text).
So if you drag the text up and left a bit the group will be pulled up and left a bit.
Therefore the group reports negative coordinates.
I wanna be able to click on var textradie text "Show radie" and then add two circles kinGroups[index].add(circle); and kinGroups[index].add(circlered);. Im adding the two circles on my Group kinGroups[index].
All my jsonObjects[i].radie == false, so I dont know why only one object in kinGroups[index] have two circles. All my three objects should have two circles, but only one object have two circles.
var textradius = new Kinetic.Text({
x: 1000,
y: 500,
fontFamily: 'Calibri',
fontSize: 18,
text: 'Show radius',
fill: 'black'
});
kinGroups[index].add(textradie);
textradius.on('click', function() {
for(i=0; i<jsonObjects.length; i++) {
console.log("testing");
if(kinGroups[index].getName() == jsonObjects[i].name) {
if(jsonObjects[i].radie == false) {
kinGroups[index].add(circle);
kinGroups[index].add(circlered);
}
}
}
});
You have to add new circle and circlered objects to the groups.
You could use the clone() method to do this:
kinGroups[index].add(circle.clone());
kinGroups[index].add(circlered.clone());
[ Addition: example code ]
Demo: http://jsfiddle.net/m1erickson/4uAdc/
Assume you have:
A group,
A text element in that group. The text element is named "One".
Other elements in that group. Some of the other elements are named "One".
If you click on the text named "One", here's how to draw a double-circle around the other elements that are also named "One".
// define a circle that can be cloned
var circle=new Kinetic.Circle({
stroke: 'black',
strokeWidth: 2,
});
// get all children with the same name as the clicked text
var children=group.find("."+text.getName());
// iterate those children and add cloned circles
for(var i=0;i<children.length;i++){
// get the x,y of the other elements with the same name as the text
var child=children[i];
var x=child.getX();
var y=child.getY();
// add cloned circles around those other elements
var red =circle.clone({x:x,y:y,radius:10,stroke:"red"});
var blue=circle.clone({x:x,y:y,radius:15,stroke:"blue"});
text.group.add(red);
text.group.add(blue);
}
layer.draw();