How to retrieve clipping region's dataURL? - konvajs

I am trying to retrieve a clipping region's dataURL, but whenever rects are outside of the region, the resulting image has a margin (I guess that it is trying to include the rects).
Here is an example of the behavior: https://codesandbox.io/embed/clip-area-x24ci
(Click on the "export" button or move the black rectangle outside of the clipping region)
Is is possible to retrieve just the clipping region's content?

You can set x, y, width and height for node.toDataURL() function:
const clipArea = {
x: 100,
y: 100,
height: 200,
width: 200
};
const dataURL = node.toDataURL({
pixelRatio: 2,
...clipArea
});

Related

How to create a resizable konva shape when user hovers

I am working on konva js. I am working on an app that lets users create custom shapes. and after creation they can resize it by mouse, connect two shapes by a line. So far the feature drawing custom shape and their connecting by line is complete.
Now I want to show dots around the custom shape when user hovers on the custom shape just like this
P.S I have seen this from https://app.diagrams.net/. I want to build drawing app same like it.If someone can navigate me to the resources from where I can build drawing app like this, it would be really helpful.
You can use mouseenter and mouseleave events to show/hide anchors for the shape.
It is up to you to choose how to implement anchors. It can be custom anchors like in https://konvajs.org/docs/sandbox/Modify_Curves_with_Anchor_Points.htm or it can be Konva.Transformer https://konvajs.org/docs/select_and_transform/Basic_demo.html.
On mouseenter you can show anchors. Hiding anchors is a bit tricker for the demo I will hide anchors when mouse is too far away from the shape. We can't use mouseleave as is here, because it will trigger hide when we simply hover Konva.Transformer.
In the demo, try to hover the circle.
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
const layer = new Konva.Layer();
stage.add(layer);
const shape = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 50,
fill: 'green'
});
layer.add(shape);
const tr = new Konva.Transformer();
layer.add(tr);
// from https://stackoverflow.com/questions/5254838/calculating-distance-between-a-point-and-a-rectangular-box-nearest-point
function getDistance(rect, p) {
var dx = Math.max(rect.x - p.x, 0, p.x - (rect.x + rect.width));
var dy = Math.max(rect.y - p.y, 0, p.y - (rect.y + rect.height));
return Math.sqrt(dx*dx + dy*dy);
}
shape.on('mouseenter', () => {
tr.nodes([shape]);
});
stage.on('mousemove', () => {
if (!tr.nodes().length) {
return;
}
if (tr.isTransforming()) {
return;
}
const rect = shape.getClientRect();
const dist = getDistance(rect, stage.getPointerPosition());
if (dist > 60) {
tr.nodes([]);
}
});
layer.draw();
<script src="https://unpkg.com/konva#^8/konva.min.js"></script>
<div id="container"></div>

Konvajs - how to take a screenshot without transparency

Im just trying to let my user take a screenshot using the toDataUrl() function.
but, without a background rectangle, all pixel are transparent , and appear black .
so the solution is to dynamicly add a rectangle, generate the image, destroy the rectangle
saveImage(){
const stage=this.$parent.$refs.stage.getStage()
var stageRect = new Konva.Rect({
x:0,
y:0,
width: stage.attrs.width,
height: stage.attrs.height,
fill: 'green',
})
console.log(stage)
const backg=new Konva.Layer();
backg.add(stageRect)
stage.add(backg)
backg.setZIndex(0)
const dataURL = stage.toDataURL({ pixelRatio: 1, mimeType:"image/png" });
backg.destroy();
this.downloadURI(dataURL, 'stage.png');
},
it works (rectangle is created before all other layer) but... i can't get the size of the stage, i mean, the viewport because the user can zoom/dezoom the stage ....
any idea ?
Just use a scale to calculate background properties:
var stageRect = new Konva.Rect({({
x: -stage.x()/ stage.scaleX(),
y: -stage.y()/ stage.scaleY(),
width: stage.width() / stage.scaleX(),
height: stage.height() / stage.scaleY(),
fill: 'green',
});
Demo: https://jsbin.com/lehasitaje/2/edit?html,js,output

Konvajs custom shapes and transformers

What I am trying to achieve is showing the transformer around the custom shape itself. I took the code directly from the API docs for creating the custom shape and adding the transformer. The transformer works great for rectangles, circles, etc but for custom shapes, it doesn't seem to appear properly.
Here is a link to a demo app with the issue with custom shapes and transformer:
https://jsfiddle.net/5zpua740/
var stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
var layer = new Konva.Layer();
/*
* create a triangle shape by defining a
* drawing function which draws a triangle
*/
var triangle = new Konva.Shape({
sceneFunc: function (context) {
context.beginPath();
context.moveTo(120, 150);
context.lineTo(320, 180);
context.quadraticCurveTo(250, 200, 360, 270);
context.closePath();
// Konva specific method
context.fillStrokeShape(this);
},
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
// add the triangle shape to the layer
layer.add(triangle);
// add the layer to the stage
stage.add(layer);
stage.on('click', function (e) {
// if click on empty area - remove all transformers
if (e.target === stage) {
stage.find('Transformer').destroy();
layer.draw();
return;
}
// remove old transformers
// TODO: we can skip it if current rect is already selected
stage.find('Transformer').destroy();
// create new transformer
var tr = new Konva.Transformer();
layer.add(tr);
tr.attachTo(e.target);
layer.draw();
})
In this sample, you can see that if you click on the object, the transformer appears in the corner. You can still use it to manipulate the object but it's not around the object itself.
Any help appreciated! Thanks in advance.
Konva can't detect bounding box of a custom shape. But we can simply help it. We just need to define a method getSelfRect.
The method should return bounding box of a shape without transforming applied (like the shape has no rotation, no scaling and placed in x =0, y=0).
We can do this by just looking at sceneFunc:
triangle.getSelfRect = function() {
return {
// sceneFunc started from moving to 120, 150 point
// so it is our top left point
x: 120,
y: 150,
// the bottom right point finished with quadraticCurveTo
// I will use the coordinates to calculate size of the shape
width: 360 - 120,
height: 270 - 150
};
}
Demo: http://jsbin.com/lazuhowezi/2/edit?js,output

Proper way to transform image in google slides api with dynamic height

I'm trying to translate an image of dynamic height and fixed width to an absolute position on a google slide, maintaining a 1:1 aspect ratio.
For example, my original images could be (in pixels):
200x150
or
200x220
I want to move it so they are both offset by x: 100, y:200, keep the original aspect ratio, and make sure the width is always fixed to the same size in PX but height is variable.
I am struggling to calculate the correct transform to make the correct translation.
{
'createImage': {
objectId,
url,
elementProperties: {
pageObjectId,
size: {
width: {
magnitude: (7/9)*originalWidthPx, //pixel to PT conversion
unit: 'PT',
},
height: {
magnitude: (7/9)*originalHeightPx, //pixel to PT conversion
unit: 'PT',
},
},
transform: {
scaleX: 1, // I believe i'll need to scale the image based on Height, keeping the original aspect ratio
scaleY: 1,
translateX: 100, // i dont believe this needs to be dynamic based on w/h
translateY: 200,
unit: 'PT',
},
},
},
}

Set stretching parameters for images programmatically in swift for iOS

So if we want to stretch only parts of an image, be it a regular image or a background image, we use the following settings in layout editor:
How do you set those programmatically?
I'm using Xcode 7.2.1
Specifying the cap insets of your image
You can set the stretch specifics by making use of the UIImage method .resizableImageWithCapInsets(_:UIEdgeInsets, resizingMode: UIImageResizingMode).
Declaration
func resizableImageWithCapInsets(capInsets: UIEdgeInsets, resizingMode: UIImageResizingMode) -> UIImage
Description
Creates and returns a new image object with the specified cap insets
and options.
A new image object with the specified cap insets and resizing mode.
Parameters
capInsets: The values to use for the cap insets.
resizingMode: The mode with which the interior of the image is
resized.
Example: custom stretching using the specified cap insets
As an example, let's try to---programmatically---stretch my (current) profile picture along its width, precisely at my right leg (left side from viewing point of view), and leave the rest of the image with its original proportions. This could be comparable to stretching the width of some button texture to the size of its content.
First, let's load our original image foo.png as an UIImage object:
let foo = UIImage(named: "foo.png") // 328 x 328
Now, using .resizableImageWithCapInsets(_:UIEdgeInsets, resizingMode: UIImageResizingMode), we'll define another UIImage instance, with specified cap insets (to the middle of my right leg), and set resizing mode to .Stretch:
/* middle of right leg at ~ |-> 0.48: LEG :0.52 <-| along
image width (for width normalized to 1.0) */
let fooWidth = foo?.size.width ?? 0
let leftCapInset = 0.48*fooWidth
let rightCapInset = fooWidth-leftCapInset // = 0.52*fooWidth
let bar = UIEdgeInsets(top: 0, left: leftCapInset, bottom: 0, right: rightCapInset)
let fooWithInsets = foo?.resizableImageWithCapInsets(bar, resizingMode: .Stretch) ?? UIImage()
Note that 0.48 literal above corresponds to the value you enter for X in the interface builder, as shown in the image in your question above (or as described in detail in the link provided by matt).
Moving on, we finally place the image with cap insets in an UIImageView, and let the width of this image view be larger than the width of the image
/* put 'fooWithInsets' in an imageView.
as per default, frame will cover 'foo.png' size */
let imageView = UIImageView(image: fooWithInsets)
/* expand frame width, 328 -> 600 */
imageView.frame = CGRect(x: 0, y: 0, width: 600, height: 328)
The resulting view stretches the original image as specified, yielding an unproportionally long leg.
Now, as long as the frame of the image has 1:1 width:height proportions (328:328), stretching will be uniform, as if only fitting any image to a smaller/larger frame. For any frame with width values larger than the height (a:1, ratio, a>1), the leg will begin to stretch unproportionally.
Extension to match the X, width, Y and height stretching properties in the Interface Builder
Finally, to thoroughly actually answer your question (which we've really only done implicitly above), we can make use of the detailed explanation of the X, width, Y and height Interface Builder stretching properties in the link provided by matt, to construct our own UIImage extension using (apparently) the same properties, translated to cap insets in the extension:
extension UIImage {
func resizableImageWithStretchingProperties(
X X: CGFloat, width widthProportion: CGFloat,
Y: CGFloat, height heightProportion: CGFloat) -> UIImage {
let selfWidth = self.size.width
let selfHeight = self.size.height
// insets along width
let leftCapInset = X*selfWidth*(1-widthProportion)
let rightCapInset = (1-X)*selfWidth*(1-widthProportion)
// insets along height
let topCapInset = Y*selfHeight*(1-heightProportion)
let bottomCapInset = (1-Y)*selfHeight*(1-heightProportion)
return self.resizableImageWithCapInsets(
UIEdgeInsets(top: topCapInset, left: leftCapInset,
bottom: bottomCapInset, right: rightCapInset),
resizingMode: .Stretch)
}
}
Using this extension, we can achieve the same horizontal stretching of foo.png as above, as follows:
let foo = UIImage(named: "foo.png") // 328 x 328
let fooWithInsets = foo?.resizableImageWithStretchingProperties(
X: 0.48, width: 0, Y: 0, height: 0) ?? UIImage()
let imageView = UIImageView(image: fooWithInsets)
imageView.frame = CGRect(x: 0, y: 0, width: 600, height: 328)
Extending our example: stretching width as well as height
Now, say we want to stretch my right leg as above (along width), but in addition also my hands and left leg along the height of the image. We control this by using the Y property in the extension above:
let foo = UIImage(named: "foo.png") // 328 x 328
let fooWithInsets = foo?.resizableImageWithStretchingProperties(
X: 0.48, width: 0, Y: 0.45, height: 0) ?? UIImage()
let imageView = UIImageView(image: fooWithInsets)
imageView.frame = CGRect(x: 0, y: 0, width: 500, height: 500)
Yielding the following stretched image:
The extension obviously allows for a more versatile use of the cap inset stretching (comparable versatility as using the Interface Builder), but note that the extension, in its current form, does not include any user input validation, so it's up to the caller to use arguments in the correct ranges.
Finally, a relevant note for any operations covering images and their coordinates:
Note: Image coordinate axes x (width) and y (height) run as
x (width): left to right (as expected)
y (height): top to bottom (don't miss this!)

Resources