how can I free drawing on shapes in konvajs - image

I want to make free drawing on top of shapes at konvajs. like an exp; Can u give me advise about shapes attrs like zindex or smt.
https://ibb.co/jq9pUK

Your question is very broad and you are not showing what you have tried so far. You would get better help faster if you give a clear description and post cut-down sample code for your questions.
Konvajs works on top of the HTML5 canvas. When working with a konvajs you put shapes, lines, images and text on to layers. Layers have a z-order and shapes on a layer have a z-order.
To answer your question, I would follow the pattern:
- create the stage
- create the shape layer
- add the shapes to the shape layer - triangles, rectangles, circles, etc
- add another layer for the freehand drawing
- draw on this layer.
Because of the sequence of adding the components to the canvas the z-order will support what you ask for in your question. If you wanted the drawing to happen 'behind' the shapes you would create the layers in the opposite sequence.
The working snippet below shows how to do the steps that I have listed above, and how to listen for the events you need to make it operate. You can extend from this starter code to handle erasing, selecting line colour, thickness, and stroke style. See the Konvajs drawing tutorial for more information.
Good luck.
// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 300, height: 200});
// Add a layer for the shapes
var layer1 = new Konva.Layer({draggable: false});
s1.add(layer1);
// draw a cirlce
var circle = new Konva.Circle({
x: 80,
y: s1.getHeight() / 2,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4
})
layer1.add(circle)
// draw a wedge.
var wedge = new Konva.Wedge({
x: 200,
y: s1.getHeight() / 2,
radius: 70,
angle: 60,
fill: 'gold',
stroke: 'black',
strokeWidth: 4,
rotation: -120
});
layer1.add(wedge)
// Now add a layer for freehand drawing
var layer2 = new Konva.Layer({draggable: false});
s1.add(layer2);
// Add a rectangle to layer2 to catch events. Make it semi-transparent
var r = new Konva.Rect({x:0, y: 0, width: 300, height: 200, fill: 'blue', opacity: 0.1})
layer2.add(r)
// Everything is ready so draw the canvas objects set up so far.
s1.draw()
var drawingLine = null; // handle to the line we are drawing
var isPaint = false; // flag to indicate we are painting
// Listen for mouse down on the rectangle. When we get one, get a new line and set the initial point
r.on('mousedown touchstart', function () {
isPaint = true;
var pos = s1.getPointerPosition();
drawingLine = newLine(pos.x, pos.y);
drawingLine.points(drawingLine.points().concat(pos.x,pos.y));
layer2.draw();
});
// Listen for mouse up ON THE STAGE, because the mouseup will not fire on the rect because the mouse is actually over the line point we just drew when it is released.
s1.on('mouseup touchend', function () {
isPaint = false;
drawingLine = null;
});
// when the mouse is moved, add the position to the line points and refresh the layer to see the effect.
r.on('mousemove touchmove', function () {
if (!isPaint) {
return;
}
var pos = s1.getPointerPosition();
drawingLine.points(drawingLine.points().concat(pos.x,pos.y));
layer2.draw();
})
// Function to add and return a line object. We will extend this line to give the appearance of drawing.
function newLine(x,y){
var line = new Konva.Line({
points: [x,y,x,y],
stroke: 'limegreen',
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round'
});
layer2.add(line)
return line;
}
p
{
padding: 4px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>Click & drag on the canvas to draw a line over the shapes.
</p>
<div id='container1' style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;"></div>

Related

How to modify the shape of a control widget in FabricJS?

I'm using FabricJS in my web application. As I draw shapes, I notice that the control widget for all the objects are rectangular. Can the shape of a control widget be modified to fit the actual shape of the object? Say, a circle with a circular control widget.
I went through the Controls Customization demo. But there is no option to modify the shape of a control widget.
I need to modify the shape of the control widgets for the following purpose:
In my application whenever an object is clicked, its fill colour is toggled between black and white. In this case(refer the image below), because the circle has a rectangular control widget, clicking the pointed pixel selects the circle instead of the rectangle. I also hide the control widget from appearing by using hasControls property. So, the user will not know anything about the control widget. So, is the shape of the control widget editable?
I don't think there is an easy way to do that with fabric.js without writing a whole bunch of extra code. Fabric.js always draws a rectangle bounding box and uses it for selection controls. However, since you're planning on hiding the controls anyway, it sounds like you might be better off using perPixelTargetFind.
When true, object detection happens on per-pixel basis rather than on
per-bounding-box
Here's a quick demo:
const canvas = new fabric.Canvas('c', {
preserveObjectStacking: true,
perPixelTargetFind: true
})
const circle = new fabric.Circle({
radius: 50,
left: 50,
top: 50,
stroke:'green',
fill: 'white',
hasControls: false,
hasBorders: false
})
const rect = new fabric.Rect({
width: 200,
height: 150,
left: 50,
top: 25,
stroke: 'green',
fill: 'black',
hasControls: false,
hasBorders: false
})
canvas.on('mouse:down', (e) => {
const obj = e.target
if (obj) {
obj.set({
fill: obj.fill === 'white' ? 'black' : 'white'
})
canvas.requestRenderAll()
}
})
canvas.add(circle, rect)
circle.bringToFront()
canvas.requestRenderAll()
body {
background: ivory;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.4.0/fabric.min.js"></script>
<canvas id="c" width="300" height="200"></canvas>

How to draw an inverted element on a layer in KonvaJS

is there any way to add a shape in KonvaJS which draws outside of it's boundries? Basically a "hole" in the layer, so that I can highlight a spot in the canvas by making everything around a circle darker (black with low opacity).
Any help is much appreciated!
Cheers
Edit:
Here is an image of what I mean (I'm not allowed to embed it yet):
https://i.imgur.com/gvTqgN0.jpg
I was hoping there might be something like this:
Konva.Circle({
x: 100,
y: 100,
radius: 50,
opacity: 0.3,
fill: 'black',
inverted: true
})
and this would then in turn "not draw" a circle, but everything around it would then take the given attributes. In this case it would all be darkend a bit besides the circle.
You can do this with a custom shape:
const shape = new Konva.Shape({
width: stage.width(),
height: stage.height(),
// what is color of background ?
fill: 'rgba(0,0,0,0.2)',
sceneFunc: (ctx, shape) => {
// draw background
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(shape.width(), 0);
ctx.lineTo(shape.width(), shape.height());
ctx.lineTo(0, shape.height());
ctx.lineTo(0, 0);
// now cut circle from the background
// we can do this by useing arc
const x = 200;
const y = 200;
const radius = 10;
// but it must be counter-clockwise
// so the last argument true is very important here
ctx.arc(200, 200, 100, 0, Math.PI * 2, true);
ctx.fillStrokeShape(shape);
},
// remove shape from hit graph, so it is not visible for events
listening: false
});
Demo: https://jsbin.com/tevejujafi/3/edit?html,js,output

Kineticjs: Avoid a shape receives any mouse event

In the following example I have two shapes, a rectangle and a semitransparent circle:
http://jsfiddle.net/cequiel/zZ22s/
var stage = new Kinetic.Stage({
container: 'canvas',
width: 800,
height: 600
});
var layer = new Kinetic.Layer();
// adds a rectangle
var rect = new Kinetic.Rect({
x: 100,
y: 50,
width: 200,
height: 150,
fill: 'yellow',
stroke: 'black'
});
rect.on('mousedown', function() {
$('#text').text('mouse down');
}).on('mouseup', function() {
$('#text').text('mouse up');
}).on('mouseenter', function() {
$('body').css('cursor', 'pointer');
$('#text').text('mouse enter');
}).on('mouseleave', function() {
$('body').css('cursor', 'default');
$('#text').text('mouse leave');
});
layer.add(rect);
// adds a semitransparent circle
var circ = new Kinetic.Circle({
x: 300,
y: 125,
radius: 60,
fill: 'green',
stroke: 'black',
opacity: 0.2,
locked: true
});
layer.add(circ);
stage.add(layer);
The rectangle captures the mouse down, up, enter and leave events. But when the mouse is over the circle, the rectangle doesn't receive any event. And this is fine. But, how could I avoid this? I mean, how could I make the circle "invisible" to the mouse events? I'm looking for something similar to the 'mouseEnabled' property defined in AS3:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html#mouseEnabled
Thanks.
You can instruct any shape to temporarily stop listening for events like this:
myShape.setListening(false);

paint application with kinetic js

I have made a drag and drop application in HTML5 canvas with kinetic js. Can we also add the paint brush functionality to the same canvas using kinetic js? If yes, please share the link for one such application, and also the code, if possible.
You can use mouse events to let the user create a sketch on the canvas.
Here's how to let the user create a Kinetic polyline.
On mousedown:
Set a mousedown flag to true (indicating that the user is sketching)
Create a new Kinetic Line object
On mousemove:
Add the current mouse position to the points in the line object
Redraw the line that now includes the latest mouse position
On mouseup:
Clear the mousedown flag.
Repeat every time the user sketches a new polyline.
To let the user draw other Kinetic shapes (rect,circle,etc.) you have many options:
Have the user select which shape they want to create. Use mousedown + mouseup to get the bounds of the shape they want. Then add that kinetic shape with those bounds to the stage.
OR
Have the user select which shape they want to create. Create a generic version of that shape and put it on the stage. Let the user drag the generic shape to their desired position. Let the user customize that generic shape by dragging the bounds anchors.
OR
Have the user select which shape they want to create and have them text input the bounds. Create a generic version of that shape and put it on the stage. Let the user drag the generic shape to their desired position.
Really, there are so many options that the design is up to you.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/WW3sK/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://www.html5canvastutorials.com/libraries/kinetic-v4.3.3-beta.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
}
</style>
<script>
$(function(){
// create a stage and a layer
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 400
});
var layer = new Kinetic.Layer();
stage.add(layer);
// an empty stage does not emit mouse-events
// so fill the stage with a background rectangle
// that can emit mouse-events
var background = new Kinetic.Rect({
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
fill: 'white',
stroke: 'black',
strokeWidth: 1,
})
layer.add(background);
layer.draw();
// a flag we use to see if we're dragging the mouse
var isMouseDown=false;
// a reference to the line we are currently drawing
var newline;
// a reference to the array of points making newline
var points=[];
// on the background
// listen for mousedown, mouseup and mousemove events
background.on('mousedown', function(){onMousedown();});
background.on('mouseup', function(){onMouseup();});
background.on('mousemove', function(){onMousemove();});
// On mousedown
// Set the isMouseDown flag to true
// Create a new line,
// Clear the points array for new points
// set newline reference to the newly created line
function onMousedown(event) {
isMouseDown = true;
points=[];
points.push(stage.getMousePosition());
var line = new Kinetic.Line({
points: points,
stroke: "green",
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
newline=line;
}
// on mouseup end the line by clearing the isMouseDown flag
function onMouseup(event) {
isMouseDown=false;
}
// on mousemove
// Add the current mouse position to the points[] array
// Update newline to include all points in points[]
// and redraw the layer
function onMousemove(event) {
if(!isMouseDown){return;};
points.push(stage.getMousePosition());
newline.setPoints(points);
layer.drawScene();
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="container"></div>
</body>
</html>
I have done something some weeks before. I don't know if it can help you.
http://jsfiddle.net/F3zwW/10/
var x;
var y;
var entry;
var isFinished = false;
circle.on('dragstart', function(evt) {
entry = new Kinetic.Circle({
x: evt.x,
y: evt.y,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth: 2
});
group.add(entry);
layer.add(group);
entry.moveToTop();
});
circle.on('dragmove', function(evt) {
if (isFinished) return;
if (x != undefined && y != undefined) {
var line = new Kinetic.Line({
points: [x, y, evt.x, evt.y],
stroke: 'red',
strokeWidth: 20,
lineCap: 'round',
lineJoin: 'round'
});
length += Math.sqrt(Math.pow(evt.x - x, 2) + Math.pow(evt.y - y, 2));
group.add(line);
}
x = evt.x;
y = evt.y;
layer.add(group);
circle.moveToTop();
entry.moveToTop();
layer.draw();
if (length > 120) circle.fire('dragend');
});
circle.on('dragend', function(evt) {
if (isFinished) return;
var exit = new Kinetic.Circle({
x: x,
y: y,
radius: 10,
fill: 'red',
stroke: 'black',
strokeWidth: 2
});
group.add(exit);
layer.add(group);
circle.hide();
layer.draw();
isFinished = true;
});
Is that the behavior you are looking for ?
Here I wanted for some reasons to limit the length but you can easily remove this restriction.

Showing image inside hexagon with html5 and kineticjs

I want to draw a hexagon and show an image inside that using html5.
I have tried it out but I am not getting image as the result.
I want to use kineticjs only for this.
Here is the code:
function hexagon(){
var stage = new Kinetic.Stage({
container: "container"
});
var layer = new Kinetic.Layer();
var hexagon = new Kinetic.RegularPolygon({
x: 100,
y: 100,
sides: 6,
radius: 100,
fill: {image: "css/images/logo.png"},
stroke: "royalblue",
strokeWidth: 2
});
// add the shape to the layer
layer.add(hexagon);
// add the layer to the stage
stage.add(layer);
}
fill takes an image object. Try the following:
var layer = new Kinetic.Layer();
logo = new Image();
logo.src = "css/images/logo.png";
var hexagon = new Kinetic.RegularPolygon({
x: 100,
y: 100,
sides: 6,
radius: 100,
fill: {image: logo},
stroke: "royalblue",
strokeWidth: 2
});
// add the shape to the layer
layer.add(hexagon);
// add the layer to the stage
stage.add(layer);
}
The author of KinectJS has written some really great tutorials. In this one he draws an image in a pentagon, as well as a few other things. Should be enough to help you.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-set-fill-with-kineticjs/
I have got the solution.
Posting it late (better late than never)
It should be:
fill: {image: "css/images/logo.png", offset: [0, 0]}

Resources