I have tried using jCanvas to make seats on my avatar system. Previously in the process i do draw an image (the background for the canvas).
The fields should be placed over the canvas, it does when i run it, but when i click the "layer" below, it turn the previously set background to BLACK?
g.addLayer({
method: 'drawRect',
x: left_px, y: top_px,
width: client.constants.ROOM_GRID_WIDTH, height: client.constants.ROOM_GRID_HEIGHT,
// Event bindings
mousedown: function(params) {
alert("clicked!");
}}).drawLayers();
Drawing background:
$("canvas").drawImage({
source: "http://xxxx.dk/framework/gfxs/rooms/"+callback[1],
x: 0, y: 0,
width: 760,
height: 552,
fromCenter: false
});
Related
Firstly, I'm very grateful for this excellent library.
I will do my best to explain this but I think the demo will explain it best.
I have a class that extends konva group because it needs other properties. One of those other properties can be called accessories, which is another konva group. (I don't want accessories to simply be a 'child' of the main group as I need to perform other operations on that array).
When I click the main groups children, I want it to drag the accessories, however, it also drags the accessories when I just click the main group.
I can't bind the startDrag() to the "dragstart" event because that only fires when the mouse is down AND the mouse moves, meaning there's an x,y offset to the accessories after they have moved.
constructor() {
super({
x: 0,
y: 0,
draggable: true,
});
this.accessories = new Konva.Group({
x : this.attrs.x,
y : this.attrs.y,
draggable: true,
});
layer.add(this);
layer.add(this.accessories);
this.on("mousedown", () => {
this.accessories.startDrag();
});
this.on("mouseup", () => {
this.accessories.stopDrag();
});
this.on("click", () => {
this.accessories.stopDrag();
})
}
}
let newgroup = new supergroup();
newgroup.add(new Konva.Rect({
x: 0,
y: 0,
width: 50,
height: 50,
fill: "black",
}));
newgroup.children[0].on("click", () => {
console.log("Rect Clicked");
});
newgroup.children[0].on("dragstart", () => {
console.log("Group Drag Started");
this.accessories.startDrag();
})
newgroup.accessories.add(new Konva.Rect({
x: 55,
y: 55,
width: 50,
height: 50,
fill: "red",
}));
stage.add(layer);
layer.draw();
I have made a simple demo here:
https://jsfiddle.net/9ajvwn8h/17/
If you click the grey background, it shifts the screen as intended. If you drag the black square, it drags the red one with it as expected. If you drag the red square, it only drags the red square as expected.
However, if you just click the black square, it begins dragging the red square, this is not what I want. It seems like the mouseup event doesn't fire.
I need the red square drag to NOT be initiated when I click the black square.
Any advice would be greatly appreciated.
Thank you
I have some Konva Text node, whose fill attribute is set to black and stroke is set to some other color.
In my canvas it looks as expected. The problem happens when I convert the canvas to base64 image to download it as an image file - in that case the downloaded image looks like in the screenshot below:
(the canvas is on the left side, the right one is the downloaded image)
As you can see, the stroke color is applied to the text's own color as well.
I created a Codesandbox example with a Text node that has the same attributes as in my environment, here is how that node is created:
const text = new Konva.Text({
x: 26.330053300533024,
y: 128,
text: "Add a body text",
defaultText: "Add a body text",
fontSize: 22,
fontFamily: "Montserrat",
draggable: true,
name: "text",
fontStyle: "300",
id: "textkgrsl68w",
is_settings: true,
wrap: "word",
padding: 5,
fill: "black",
opacity: 1,
isPremium: false,
width: 183.5,
visible: true,
rotation: 0,
scaleX: 1,
scaleY: 1,
offsetX: 0,
offsetY: 0,
skewX: 0,
skewY: 0,
stroke: "rgba(255,0,0,1)",
strokeWidth: 3.75
});
As you can see, it has the same (incorrect) look - without the inline color. I played with fontSize in Codesandbox and when I set it to very big value (like 100), the text's inline color became visible.
I assumed it can be some ratio problem, but as we see on the screenshot, the text's size is similar in both canvas and downloaded image.
How can this be fixed, maybe there is some extra attribute that should also be set?
konva: 7.1.4
react-konva: 16.12.0-0
UPDATED:
You can use text.fillAfterStrokeEnabled(true); to draw fill over stroke.
Old answer:
By default Konva is drawing fill first then stroke. So it will be a text itself and then stroke around it (that goes overfill part).
Probably one-day Konva will support a different order, but at the current moment konva#7.1.4 can't do that.
As a workaround just use two Konva.Text instances. First for stroke, second for fill.
https://codesandbox.io/s/download-konva-text-node-with-stroke-as-base-64-image-forked-w0z4v
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 building a game similar to Tetris, but with blocks that move smoothly (pixel by pixel).
At the moment I create a separate Konva Image object for each new block:
let block = new Konva.Image({
x: 200,
y: 0,
transformsEnabled: 'position',
listening: false,
image: images.tiles,
crop: {
x: colorindex * 128,
y: shapeindex * 128,
width: 128,
height: 128
},
width: 128,
height: 128,
colorindex: colorindex,
shapeindex: shapeindex,
falling: true,
fallingspeed: 1,
});
that.blocks.push(block);
that.blocklayer.add(block);
With a lots of blocks on the screen I notice a slight slowdown in the animations.
Now I want to try and put all fixed blocks into 1 big Image object to see if this is faster.
Is it possible with Konva to copy a part of an image to another image ?
The simplest solution is to just move several blocks into a group, and then just cache it:
group.cache();
Demo: https://konvajs.org/docs/performance/Shape_Caching.html
My original size of the canvas is 800X700.
I am using clipTo to work in a selected portion of a canvas:
var rect = new fabric.Rect({
left: 100,
top: 50,
fill: '#fff',
width: 376,
height: 602,
strokeWidth: 0,
selectable: false
});
rect.set({
clipFor: 'mainCanvas',
});
I make sure all the images and text fall within this portion of the canvas.
What I want to Do:
I want to scale up this portion of canvas to a width and height of 1500X2400 so that it can be used for printing
I am using the below toDataURL function with multiplier as 3
var imgData= canvas.toDataURL({
format: 'png',
width: 376,
height: 602,
top: 50,
left: 100,
multiplier: 3
});
But I am getting only top most portion of the image. Any solution?
Update: More info about the problem
I am using Ubuntu 16.04 and Fabric.js-1.6.2
Demonstrating the problem on JsFiddle
When I click on the enhance image button, only the top left portion of the image is displayed.