Some part of my code here:
var stage = new Kinetic.Stage({
container: "canvas",
width: 300,
height: 200
});
var layer = new Kinetic.Layer({
});
var line = new Kinetic.Polygon({
id: 'wall',
points: [50, 50, 100, 50, 100, 100, 50, 100],
stroke: "black",
strokeWidth: 4,
draggable: true
});
line.on('dragmove', function(mouseEvent) {
line.getPoints()[2] = {x:mouseEvent.x, y:mouseEvent.y};
layer.draw();
});
stage.add(layer);
layer.add(line);
layer.draw();
The task is to drag polygon by one of the corners (in example by right-bottom). But actually result is not that I expected. What is wrong in my code? or what is correct way of moving elemten by one of the points?
Check out this post iOS6 pull/drag border on circle
The effects are similar, I think, to what you're looking for. You could animate the drag on any of your corners by detecting the click/touch location.
Let me know if you need another example.
Related
Consider having a large (2000x1000) stage with some text in it. The stage gets downscaled to 1000x500 making the text unreadable. Then we try to enlarge the text by zooming it in.
Expected: the text should become readable again at some point.
Actual: the text remains unreadable (blurred) no matter how much we zoom in.
Try zooming the page in (with native browser zoom on desktop) after running the snippet:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.scale({x: 0.5, y: 0.5});
stage.setAttrs({width: 1000, height: 500});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
The quality loss can be avoided by downscaling with CSS only, like this:
const stage = new Konva.Stage({
container: 'container',
width: 2000,
height: 1000,
});
const layer = new Konva.Layer();
stage.add(layer);
const rect = new Konva.Text({
x : 50, y : 50, width: 100, height: 100,
fontSize: 12,
text: "This text should be readable when the viewport gets downscaled"
});
layer.add(rect).draw();
stage.getChildren().forEach(function(layer) {
layer.canvas._canvas.style.width = "1000px";
layer.canvas._canvas.style.height = "500px";
layer.hitCanvas.setSize(1000, 500);
layer.hitCanvas.context.scale(0.5, 0.5);
});
stage.draw();
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.6.0/konva.js"></script>
<div id="container"></div>
Note how text becomes readable at a certain level of zooming.
The workaround breaks Konvajs abstraction. What problems it can potentially cause? Is there a better way, which uses only public methods exposed by Konvajs?
In fabric.js it can be done like this (complete example here):
canvas.setDimensions({width: '1000px', height: '500px'}, {cssOnly: true});
Konva is a canvas framework. Canvas is a bitmap image unlike vector elements like SVG. So that "blur" should be expected. Technically to fix the issue you can redraw stage with higher pixelRatio on zoom event:
Konva.pixelRatio = 4
stage.draw();
That code will generate more pixels for canvas element. But the page may be very heavy in RAM in this case because Konva will have to produce very large canvas. In most of the mobile apps, you don't need native zooming and you can use responsive design. For zooming the stage, you can use Konva methods.
A little bit frustrated here. I am trying to get dynamic patterns work as it shown on demo here http://fabricjs.com/dynamic-patterns.
I wrote function but it won't change pattern size once t is created.
I tried to assign img object to window array and change sizes and even inserted rescale operation at the end of the function, but my pattern still won't change its size.
I know i'm doing something wrong, but i cannot figure what.
Maybe it is Fabric.js version or canvas.requestRenderAll();
Please, let me know if you have any idea on how to deal with this problem.
Here is the code.
'setBackgroundItem':function(){
fabric.Image.fromURL(arr.image, function(img) {
var patternSourceCanvas = new fabric.StaticCanvas();
var to_set_width = canvas.getActiveObject().width; // avtorkoda
img.set({opacity: 0.9});
img.scaleToWidth(to_set_width);
w.fills.push(img);
patternSourceCanvas.add(img);
patternSourceCanvas.setDimensions({
width: to_set_width,// на ноуте клиента работает с этим. у меня без может)
height: Math.floor(to_set_width)
});
var texture = patternSourceCanvas.getElement();
var pattern = new fabric.Pattern({
source: texture,
repeat: 'no-repeat',
offsetX: 0,
offsetY: 0
});
var activeObject = canvas.getActiveObject();
var activeGroup = canvas.getActiveGroup();
activeObject.setFill(pattern);
img.scaleToHeight(40);
canvas.renderAll();
});
},
Thanks in advance.
A bit late to the party:
The documentation doesn't specify this, but in order to change the pattern width after you've applied it, you must disable caching on the object that the pattern was applied upon.
In your case:
activeObject.set('objectCaching', false);
Another place where it can be observed (from FabricJS's own example here):
canvas.add(new fabric.Polygon([
{x: 185, y: 0},
{x: 250, y: 100},
{x: 385, y: 170},
{x: 0, y: 245} ], {
left: 0,
top: 200,
angle: -30,
fill: pattern,
objectCaching: false
}));
You either do it like this, or you can make objectCaching false as a default for all the objects (not recommeded for heavy projects)
I've pulled out most of my hair trying to find a solution to no avail.
I know this must be easy but being a javascript neophyte I can't seem to wrap my head around it and am hoping someone can help me out!!!
I'm trying to create a simple canvas element that has an image with text (with wrapping) on top of it. The text will come from a text field outside of the canvas (nothing fancy). I've seen where the canvas populates with the text as it is input into the text field which is what I'm looking for (no submit button). Eventually, I will need to add 2 additional text fields with different information, doing the same thing but for right now I'd be happy to get one to work!
The kinetic text tutorial found here (http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-text-tutorial/ - code below) would be perfect if I could only figure out how to get the "complex text" to be pulled from a regular text input field instead of being hard coded!
Any help would be greatly appreciated!
Working code without input text field:
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<div id="container"></div>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.4.min.js"></script>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 220
});
var layer = new Kinetic.Layer();
var simpleText = new Kinetic.Text({
x: stage.getWidth() / 2,
y: 15,
text: 'Simple Text',
fontSize: 30,
fontFamily: 'Calibri',
fill: 'green'
});
// to align text in the middle of the screen, we can set the
// shape offset to the center of the text shape after instantiating it
simpleText.setOffset({
x: simpleText.getWidth() / 2
});
// since this text is inside of a defined area, we can center it using
// align: 'center'
var complexText = new Kinetic.Text({
x: 100,
y: 60,
text: 'COMPLEX TEXT\n\nAll the world\'s a stage, and all the men and women merely players. They have their exits and their entrances.',
fontSize: 18,
fontFamily: 'Calibri',
fill: '#555',
width: 380,
padding: 20,
align: 'center'
});
var rect = new Kinetic.Rect({
x: 100,
y: 60,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 380,
height: complexText.getHeight(),
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: [10, 10],
shadowOpacity: 0.2,
cornerRadius: 10
});
// add the shapes to the layer
layer.add(simpleText);
layer.add(rect);
layer.add(complexText);
stage.add(layer);
</script>
</body>
</html>
Possible solution: to add one input field, set up event listener which fire on change of its value and then start drawing.
<body>
<div id="container"></div>
<input type="text" id='complexText' size="20"/>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.7.4.min.js"></script>
<script defer="defer">
var inputField = document.getElementById('complexText');
inputField.addEventListener('change', function() {
var inputText = this.value;
showText(inputText);
}, false);
function showText(inputText) {
*** here goes all your 'Kinetic' code ***
}
See example at jsBin.
I'm working with kineticjs where I have a stage with one layer in it. This layer has multiple shapes on it who react on a mouseover event (they show a tooltip)
besides these shapes I also have some text nodes on a higher ZIndex (so they are above the shapes).
This all works fine with one exception, when a text is on top of a shape, the shape doesn't show a tooltip I assume it's because the textnode uses the event, rather than 'forward' it, eventhough I haven't bound anything to the text node.
How can I propagate events to nodes on a lower ZIndex?
Personally I'd create a separate layer to put anything you dont want to register mouse events on and when you create the layer set its listening property to false.
You could also set the this property for the individual elements.
Here's an example using layers...
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var normalLayer = new Kinetic.Layer();
var textLayer = new Kinetic.Layer({listening :false});
var rect = new Kinetic.Rect({
x: 20,
y: 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
rect.on('click', function(evt) {
this.setFill('blue');
normalLayer.draw();
});
normalLayer.add(rect);
var simpleText = new Kinetic.Text({
x: 40,
y: 40,
text: 'Simple Text',
fontSize: 30,
fontFamily: 'Calibri',
textFill: 'yellow'
});
textLayer.add(simpleText);
stage.add(normalLayer);
stage.add(textLayer);
http://jsfiddle.net/MT435/
Remember the listening property can be set for individual elements aswell.
I have an Image() object, which I need to resize. I am using it to fill a shape in canvas.
If I try to change it like image.width = 300, it doesn't resize. If I console.log it, it shows that only the html attribute has been changed.
Is there a way to edit the Image() size directly?
You can do this using the setting the fill.scale object with the properties fill.scale.x and fill.scale.y that you wish to apply to your image.
In the example, this could be done, for example like:
var patternPentagon = new Kinetic.RegularPolygon({
x: 220,
y: stage.getHeight() / 2,
sides: 5,
radius: 70,
fill: {
scale: { x:0.5, y:0.5 },
image: images.darthVader,
offset: [-220, -70]
},
stroke: 'black',
strokeWidth: 4,
draggable: true
});
You can see an example of this working here