Parallel lines separator in Konva - javascript

I'm trying to draw a separator with 2 lines for my road. I already tried to make it with just 2 parallels lines, but when I made my road curve, it doesn't look very good. Like this:
Small curve:
Big curve:
Because of it now I am just drawing one line with white background behind the line with black background. But sometimes my main road is not black. How can I make space between these lines transparent?
Examples:
Normal work:
Work with road with different background:
You can drag separator in the example below
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var line = new Konva.Line({
points: [100, 100, 200, 200],
strokeWidth: 100,
stroke: 'black',
draggable: true,
});
var line_2 = new Konva.Line({
points: [400, 100, 500, 200],
strokeWidth: 100,
stroke: 'red',
draggable: true,
});
const group_sep = new Konva.Group({
draggable: true,
});
var sep_1 = new Konva.Line({
points: [100, 100, 200, 200],
strokeWidth: 20,
stroke: 'green',
});
var sep_2 = new Konva.Line({
points: [100, 100, 200, 200],
strokeWidth: 10,
stroke: '#000000',
});
group_sep.add(sep_1);
group_sep.add(sep_2);
layer.add(line);
layer.add(line_2);
layer.add(group_sep);
stage.add(layer);
layer.draw();
<script src="https://unpkg.com/konva#4.0.16/konva.min.js"></script>
<div id="container"></div>

You can use blend mode via globalCompositeOperation to "cut" one line from another.
const group_sep = new Konva.Group({
draggable: true,
});
var sep_1 = new Konva.Line({
points: [100, 100, 200, 200],
strokeWidth: 20,
stroke: 'green',
});
// destination-out will cut line from previous drawings
var sep_2 = new Konva.Line({
points: [100, 100, 200, 200],
strokeWidth: 10,
stroke: '#000000',
globalCompositeOperation: 'destination-out'
});
But you should know that destination-out will cut your line from ALL previous drawings on the canvas. It means it may cut the background too. To fix the issues you can move your group with the lines into another Konva.Layer or just cache the group:
group_sep.cache();
Note: remember to recache to group every time you change the lines.
Demo: https://jsbin.com/ravodomigi/3/edit?html,js,output

Related

deleting a line after selecting the desired line on clicking a button kinetic js

var line = new Kinetic.Line({ points: [415, 115,617,234], stroke: 'gray', tension: 2});
line.addEventListener('click',function(e){
debugger;
// alert(e.x+'.'+ e.y);
// popup;
});
On clicking the line it should be selected.on clicking other place expect line it should be deselected.after selecting the line if i pressed a delete button the line should get destroyed how to do it.
Not exact as your requirement, but you double click on line, line will be removed from layer
here is demo.
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var redLine = new Kinetic.Line({
points: [73, 70, 340, 23, 450, 60, 500, 20],
stroke: 'red',
strokeWidth: 15,
lineCap: 'round',
lineJoin: 'round'
});
redLine.on("dblclick",function(){
this.destroy();
layer.draw();
});
layer.add(redLine);
stage.add(layer);

How to pass an event on to the nodes below in kinetics

question that is very similar but answer doesn't work in my situation
I have a circle and I want to pass the click event to any objects that are underneath it.
I have tried:
setting cancelbubble to false.
setting the cirle layer to listening= false doesn't work for me because the circle is then no longer draggable.
I have made a fiddle here
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 400
});
var layer = new Kinetic.Layer();
var background = new Kinetic.Layer();
var colorPentagon = new Kinetic.RegularPolygon({
x: 80,
y: stage.getHeight() / 2,
sides: 5,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
colorPentagon.on('click', function(evt){ alert("pentagon");});
var linearGradPentagon = new Kinetic.RegularPolygon({
x: 360,
y: stage.height()/2,
sides: 5,
radius: 70,
fillLinearGradientStartPoint: {x:-50, y:-50},
fillLinearGradientEndPoint: {x:50,y:50},
fillLinearGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'black',
strokeWidth: 4,
draggable: true
});
linearGradPentagon.on('click', function(evt){ alert("pentagon");});
var radialGradPentagon = new Kinetic.RegularPolygon({
x: 500,
y: stage.height()/2,
sides: 5,
radius: 70,
fillRadialGradientEndRadius: 70,
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'blue'],
stroke: 'black',
strokeWidth: 4,
draggable: true
});
radialGradPentagon.on('click', function(evt){ alert("pentagon");});
background.add(colorPentagon);
//background.add(patternPentagon);
background.add(linearGradPentagon);
background.add(radialGradPentagon);
stage.add(background);
var hideCircle = new Kinetic.Circle({
x: stage.width()/2,
y: stage.height()/2,
radius: 650,
stroke: 'black',
strokeWidth: 1000,
draggable:true
});
hideCircle.on('click', function(evt){ alert("click");});
// add the shape to the layer
layer.add(hideCircle);
// add the layer to the stage
stage.add(layer);
Currently to get it to work I have to take the click coordinates and do my own detection. It works but I was hoping for something more elegant.
Here's how to pass your click event to the bottom layer nodes:
You can listen for clicks on the stage
Determine if the click is inside any node on the bottom layer
If the click was inside a node, fire the click event on that node.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/sFX8y/
stage.on('contentClick',function(e){
// get the mouse position
var pos=stage.getPointerPosition();
// fetch the node on the bottom layer that is under the mouse, if any.
var hitThisNode=background.getIntersection(pos);
// if a node was hit, fire the click event on that node
if(hitThisNode){
hitThisNode.fire("click",e,true);
}
});

Drag while in background in KineticJs

I have two layers generally representing a large background and some content on top of it.
I have made the background draggable but when dragged, it covers the content of the other layer.
Is it possible to keep it in the background while dragging it?
I have tried binding the drag events with .moveToBottom() for the background group (later added to backgroundLayer) like that:
groupBackground.on('dragstart',function(){
groupBackground.moveToBottom();
});
groupBackground.on('dragmove',function(){
groupBackground.moveToBottom();
});
groupBackground.on('dragend',function(){
groupBackground.moveToBottom();
});
but to no result.
You can “draw under” by using the canvas “.globalCompositeOperation”
This will allow your user to drag the background under the foreground.
And you can apply it to KineticJs like this:
layer.getContext().globalCompositeOperation = "destination-over";
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/2GFSE/
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
stage.add(layer);
var background = new Kinetic.Rect({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
width: 250,
height: 250,
fill: 'black',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
var foreground = new Kinetic.Ellipse({
x: stage.getWidth() / 3,
y: stage.getHeight() / 3,
radius: {
x: 50,
y: 30
},
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
// add the background and foreground to the layer
layer.add(foreground);
layer.draw();
layer.getContext().globalCompositeOperation = "destination-over";
layer.add(background);
layer.draw();

KineticJS / Javascript dynamic creation and immediate dragging

What I want do is dynamically create a shape on mousedown, and then immediately have it (the shape) follow the mouse cursor until mouseup sets it in place.
Here is what I have so far and it's not working for me.
addNegativeButton.on('mousedown', function(){
var userPos = stage.getUserPosition();
shapesLayer.add(new Kinetic.Image({
image: imageObj,
x: userPos.x,
y: userPos.y,
height: 25,
width: 25,
rotation: 1,
draggable: true,
offset: 12
}));
var last = shapesLayer.getChildren()[shapesLayer.getChildren().length -1];
stage.on("mouseup", function(){
last.setAbsolutePosition(stage.getUserPosition());
stage.off("mouseup");
});
To reiterate:
What I have is an 'addNegativeButton' which when clicked creates a shape.
But I want it to follow the mouse cursor until the click is released.
http://jsfiddle.net/CPrEe/37/
Any suggestions?
Turns out its rather simple ;)
After you add the element/shape, all you have to do is use the simulate function to simulate mouse down and it drags....
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var rect = new Kinetic.Rect({
x: 20,
y: 20,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
//What I really want here is to start dragging the circle until the
//user releases the mouse, which would then place the circle.
rect.on('mousedown', function(evt) {
var userPos = stage.getUserPosition();
var latestElement = new Kinetic.Circle({
x: userPos.x,
y: userPos.y,
radius: 20,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
})
layer.add(latestElement);
// Here's the bit you want. After adding the circle (with draggable:true) simulate the mousedown event on it which will initiate the drag
latestElement.simulate('mousedown');
layer.draw();
});
layer.add(rect);
stage.add(layer);​
http://jsfiddle.net/CPrEe/38/
http://kineticjs.com/docs/symbols/Kinetic.Node.php#simulate

kineticjs rect fillText

I have KineticJS rect already fill with 'blue' color, I want to show Text on this rect box. But my below code not showing anything. Also I need to assign this label text on button click, the code for the same is also below.
drawShape = new Kinetic.Rect({
id: shapeId,
name: shapeName,
x: 0,
y: 0,
width: 150,
height: 40,
fill: "#00D2FF",
stroke: "black",
strokeWidth: 3,
fillText: "Step" + stepNumber
});
function OnApplyPropertiesClick(){
drawShape.fillText(document.getElementById("txtLabel").value);
}
any help on this?? please.
Thanks
Biru
I don't think you can add text to a rectangle object, only a fill type of:
[color, linear gradient, radial gradient, or pattern]
To solve this i created a group, then added a rectangle and text object to it, when i wanted to create a rectangle with text on it:
var group = new Kinetic.Group({
});
var rectangle = new Kinetic.Rect({
x: 5,
y: 5,
width: 80,
height: 35,
fill: "green",
stroke: "black",
strokeWidth: 2
});
var rectangleText = new Kinetic.Text({
x: 15,
y: 10,
text: 'test',
fontSize: 20,
fontFamily: 'Calibri',
textFill: 'black'
});
group.add(rectangle);
group.add(rectangleText);
layer.add(group);
You should be able to adapt your listener to then apply it to this.
I've done a jsfiddle to show what i mean:
http://jsfiddle.net/B85Ff/
Have you added drawShape to any layer yet? Doesn't appear in the snippet you posted.
Also, you need to draw the layer (like a refresh) at the end of your OnApplyPropertiesClick() function.

Categories

Resources