Invert Y axis in Konva - konvajs

I have to do a lot of drawing stuff with angles and I'm afraid of messing it up with the y axis going toward bottom. And I want the Y axis going upward.
I know that in normal canvas you can invert Y axis with a simple transform:
var stage = document.getElementById("stage");
const layer=stage.getContext("2d");
layer.transform(1, 0, 0, -1, 0, 3000);
But I do not know if I can do that in Konva. Is that possible?

You just need to apply a negative scale -1 and move a container to make it visible.
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight,
y: window.innerHeight,
scaleY: -1
});
demo: https://jsbin.com/vuhuzuroca/1/edit?html,js,output

Related

Draw rects inside Konva layer bound by a region with uniform distribution

I am using Konva.js to render some colourful boxes.
I have a Stage with some set size and regions within that Stage, bound by points (e.g. rectangles, but they can be any polygons).
I then need to add some number of smaller rects inside this area such that they look nice and are uniformly distributed.
E.g.
// these numbers are an example only, irrelevant
let width = 500 * 1.936402653140851;
let height = 500;
// setup stage, boilerplate
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
// region layer - boundaries
var regionLayer = new Konva.Layer({
scale: {x: width/4963, y: height/2563} // these numbers are an example only, irrelevant
});
stage.add(regionLayer);
// for this example, a single region, L-shaped on it's side
let box = new Konva.Line({
name: 'region-1',
points: [1067, 681,
3337, 681,
3337, 987,
3037, 987,
3037, 787,
1067, 787],
closed: true,
fill: 'blue',
opacity: 0.5
});
regionLayer.add(box);
regionLayer.draw();
// layer to draw rects in
let rectsLayer = new Konva.Layer({
scale: {x: width/4963, y: height/2563} // these numbers are an example only, irrelevant
});
for (let i = 0; i < 90; i++) { // e.g. some number up to X
let rect = new Konva.Rect({
width: 20,
height: 20,
fill: 'red',
x: 1067 + 40 * (i + 1),
y: 681 + 20
});
rectsLayer.add(rect);
}
stage.add(rectsLayer);
rectsLayer.draw();
The result of the above is something like this
What I'd like to have, is those boxes filling free area within the boundaries of my polygon only.
I read a whole heap about Delauney triangulation, Voronoi diagrams and sequencing for normal distribution to make it happen, but sadly I came up with zilch on practical approach of doing this.
https://jsfiddle.net/x4aksz1y/2/

How to drag a group in Konva JS only from an inner shape and not from other areas of the group?

I want to drag the entire group from the center red square, (see fiddle)
but restrict dragging from the outer rectangle, while maintaining the inner rectangle's position inside the group.
Possibly when mouse is down I want the crosshair cursor to be dead in the center of the inner red rectangle.
Any help would be appreciated, thanks.
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
let layer = new Konva.Layer();
let group = new Konva.Group({
draggable: true,
height:50,
width: 50
});
const containerRect = new Konva.Rect({
width:50,
height: 50,
fill: 'yellow'
});
const rect = new Konva.Rect({
x: 15,
y: 15,
width: 20,
height: 20,
fill: 'red'
});
stage.add(layer);
group.add(containerRect);
group.add(rect);
layer.add(group);
layer.draw();
I suggest making the red rectangle draggable. Once you start a drag, you can stop it and start dragging of the group:
rect.on('dragstart', () => {
// stop rect dragging
rect.stopDrag();
// move group to the center
const size = group.getClientRect();
const pos = stage.getPointerPosition();
group.setAttrs({
x: pos.x - size.width / 2,
y: pos.y - size.height / 2,
});
group.startDrag();
});
https://jsfiddle.net/0cdw3ya7/21/

How to make a text appear from 0 to 100% (fold out effect) in KonvaJs

In KonvaJS how to make a text appear from 0 to 100% (fold out effect)
i want to create same effect as in below video, but with text
https://www.youtube.com/watch?v=HO6mco2MGH0
i tried giving width 0 to the node and then increased the width to 100% in the tween. But it is not giving me the desired effect. Text is appear character by character.
TIA
For that case, you can use group clipping.
const group = new Konva.Group({
clipX: 100,
clipY: 0,
clipWidth: 100,
clipHeight: 100
});
layer.add(group);
const circle = new Konva.Circle({
x: 0,
y: 50,
radius: 50,
fill: 'green'
});
group.add(circle);
circle.to({
x: 150,
duration: 1
});
Demo: http://jsbin.com/miketotuvo/1/edit?html,js,output

Konvajs layer positions not being set as expected

I have an app where I am panning and zooming multiple layers.
However, when I set the position of the layers they are being updated to the wrong values.
For instance, after calling:
layer.position({
x: 12,
y: 233,
});
I would expect
layer.getClientRect();
to return
{
x: 12,
y: 233,
}
Instead it returns
{
x: -22,
y: 220,
}
Is there any known reason this is happening?
I realised I wasn't taking into account all the offsets. The x position of a circle is set from the centre while getClientRect() returns the width and height including negatives. So getClientRect() on a circle with a radius of 50 and x of 0 will actually return {x: -25, y: -25, width: 50, height: 50}.
Seems to work for me as advertised in this cut down test. Did you move the stage or something ?
In the snippet below I draw a layer with 4 'corner' rects, display its value from grtClientRect() in 'Layer pos #1' which gives (0, 0), then move the stage to 12, 233 and display its value from grtClientRect() in 'Layer pos #2' which shows (12, 233). I move the layer back up to (12, 23) just for fun thereafter.
var stage = new Konva.Stage({
container: 'container',
width: 1600,
height: 400
});
// add a layer
var layer = new Konva.Layer();
stage.add(layer);
// add 4 corner rects - code I happened to have to hand
var rectCorner = [];
for (i=0;i<4;i=i+1){
rectCorner[i] = new Konva.Rect({
x: 0,
y: 0,
width: 50,
height: 50,
fill: 'red',
opacity: 0.5,
strokeWidth: 0})
layer.add(rectCorner[i]);
}
// put the rects in the corners to give a known layer space
rectCorner[1].position({x:500, y: 0});
rectCorner[2].position({x:500, y: 150});
rectCorner[3].position({x:0, y: 150});
layer.draw();
// get the client rect now
var p = layer.getClientRect();
$('#info1').html('Layer pos #1=' + p.x + ', ' + p.y);
// move the layer...
layer.position({
x: 12,
y: 233,
});
// get the client rect now
var p = layer.getClientRect();
$('#info2').html('Layer pos #2=' + p.x + ', ' + p.y);
// move the layer back to the top...
layer.position({
x: 12,
y: 23,
});
stage.draw();
p
{
padding: 4px;
}
#container
{
background-color: silver;
overflow: hidden;
}
<div id='info1'></div>
<div id='info2'></div>
<div id="container"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.7.6/konva.min.js"></script>
<script type="text/javascript" src="test.js"></script>

Image must be added to group before group added to layer?

I'm finding a potential bug in KonvaJS. Or I'm not sure about the capabilities...
1) Create a layer and add it to stage
2) Create a group and add it to layer
3) Create an Image node and add it to group (Note my images are loaded using Konva.Image.fromURL which waits for the image to load then adds it to the group.)
Result: Image does not appear.
But if you add the image to the group then add the group to the layer, the image appears. This is going to cause problems if I want to attach an image to a group dynamical if it just disappears.
I'm trying to create the concept of a tray or plate. Where the user can place items onto the plate. If the user drags the plate it creates a group with all the intersecting nodes and moves them all together. At drag end it releases all the objects back to the user.
EDIT: The problem I was experiencing had to do with group coordinates as I mentioned in my comment bellow.
"I think I misunderstood, for the longest time how positioning works with groups. Read the comments: jsfiddle.net/jusatx6s"
LL: Make sure you're checking the position of the nodes your are rendering and that they do appear on screen.
I have created a plunkr and followed steps which you have mentioned. Everything is working fine. Here's my code.
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
// 1. created layer added it to stage.
var layer = new Konva.Layer();
stage.add(layer);
// 2. created group added it to layer
var group = new Konva.Group({
x: 120,
y: 40,
rotation: 20
});
layer.add(group);
var src = 'https://konvajs.github.io/assets/yoda.jpg';
// 3. Create an Image node and add it to group
Konva.Image.fromURL(src, function(yoda) {
console.log(yoda);
yoda.setAttrs({
x: 50,
y: 50,
width: 106,
height: 118
});
// 4. Add it to group.
group.add(yoda);
layer.batchDraw(); // It's required to draw changes.
});
Here's the plnkr to play around. Please let me know if I have missed anything.
Edited in light of OP's edit re confusion over co-ordinates.
Principles:
layers use the same co-ordinate system as the stage. So setting a shape position to {X: 10, y: 20} is at 10,20 in relation to the top left of the stage.
Adding a shape to a group is different, but you will not notice this if you do not set the group x & y position. For shapes that are added to the group, the shape positions are ADDED to the parent group positions.
Here is an example using a layer and a group. The gold rect is on the layer only. The group is illustrated by the green rect and has been set to position (60, 50). The red rect is a copy of the gold rect except the color. It has the same x & y position as red, BUT it is added to the group. And so its position (5, 5) is added to the group position (60, 50) to give its absolute position on the stage as (65, 55).
// add a stage
var s = new Konva.Stage({
container: 'container',
width: 400,
height: 400
});
// add a layer
var l = new Konva.Layer();
s.add(l);
// Add a gold rect to the LAYER
var gold = new Konva.Rect({stroke: 'gold', width: 40, height: 50, x: 5, y: 5});
l.add(gold);
// add a group
var g = new Konva.Group({x:60, y:50});
l.add(g);
// Add a green rect to the LAYER then add to the group
var green = new Konva.Rect({stroke: 'lime', width:100, height: 100, x: 0, y: 0});
g.add(green);
// Add a red rect, same apparent co-ords as red, but this time to the group
var red = new Konva.Rect({stroke: 'red', width: 40, height: 50, x: 5, y: 5});
g.add(red);
var abspos = red.getAbsolutePosition();
var pos = red.position();
console.log('Abs position of red is (' + abspos.x + ', ' + abspos.y + ') but its co-ords are ' + '(' + pos.x + ', ' + pos.y + ')');
l.draw(); // redraw the layer it all sits on.
#container {
border: 1px solid #ccc;
}
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.2/konva.min.js"></script>
<body>
<div id="container"></div>
</body>

Resources