moving more than two arrow lines on canvas - javascript

This is my code using kinetic.js
I draw three lines and move using mouse.
$(document).ready(function(){
var y1=50;
var stage = new Kinetic.Stage({
container: "container",
width: 578,
height: 200
});
var layer = new Kinetic.Layer();
var group=new Kinetic.Group({
draggable: true,
dragConstraint : 'horizontal'
});
var lineme =function(pts){
var line1 = new Kinetic.Line({
points: pts,
stroke: "black",
strokeWidth: 4,
lineCap: 'round',
lineJoin: 'round',
});
group.add(line1);
}
for(a=0;a<=2;a++)
{
var points1 = [{
x: 73,
y: y1
}, {
x: 300,
y: y1
}];
lineme(points1);
y1=y1+50;
}
group.on("mouseover", function(){
document.body.style.cursor = "pointer";
});
group.on("mouseout", function() {
document.body.style.cursor = "default";
});
// add the shape to the layer
layer.add(group);
// add the layer to the stage
stage.add(layer);
});
I want to draw arrow line I tried more time but I cant find out the proper solution. Is their any arrow function in kinetic js can anyone help me

You have to create a group and add both lines to the group.
Check the following example:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-a-group-with-kineticjs/
Hope it helps!

var line2 = .....
// add another line to the layer before adding it to the stage
layer.add(line2);
surely?

Related

Line width in Konva js

just need to create line with image background. I found this opportunity in official documentation here (https://konvajs.org/api/Konva.Line.html). For the start I just need to create line with tension, color fill and width, but the width property dont work(or I dont know how to do it).
My code and output:
let line2 = new Konva.Line({
x: 100,
y: 50,
points: [75, 75, 100, 200, 300, 140],
fill: "red",
tension: 0.5,
width: 50,
strokeWidth: 1,
stroke: 'green'
});
As mentioned in another answer, Konva#4.0.12 doesn't support pattern for strokes. But it is possible to do with 2d native canvas API
So you have to:
1 - Draw a custom shape and make a stroke manually
2 - Or you can use Blend mode to mix a line and an image:
const group = new Konva.Group();
layer.add(group);
// draw line
const line = new Konva.Line({
x: 100,
y: 50,
points: [75, 75, 100, 200, 300, 140],
fill: "red",
tension: 0.5,
strokeWidth: 1,
stroke: 'green'
});
group.add(line);
// "fill" line with globalCompositeOperation: 'source-in' rectangle
var lineClientRect = line.getClientRect();
var fillRect = new Konva.Rect({
x: lineClientRect.x,
y: lineClientRect.y,
width: lineClientRect.width,
height: lineClientRect.height,
fillPatternImage: img,
globalCompositeOperation: 'source-in'
});
layer.add(fillRect);
group.cache();
layer.draw();
It may be a bit tricky, because globalCompositeOperation may effect all the shapes around your line. To fix that we can add the line and the "fill" rectangle into the group and cache it.
Demo: https://jsbin.com/zodojezuma/2/edit?html,js,output
It is not possible with Konva current version (4.0.12) to apply a pattern to the stroke of a line object. The snippet below uses a closed line with image fill pattern, but I don't think this is what you area after, but I created it to see what was possible and so will post it here in case useful in the future.
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
// add the layer to the stage
stage.add(layer);
var layer2 = new Konva.Layer();
var rect1 = new Konva.Rect({width:10, height:10, fill: 'magenta'})
var rect2 = new Konva.Rect({width:5, height:5, fill: 'cyan'})
var rect3 = new Konva.Rect({x: 5, y:5, width:5, height:5, fill: 'cyan'})
stage.add(layer2);
layer2.add(rect1);
layer2.add(rect2);
layer2.add(rect3);
stage.draw();
// make an image out of layer2
// Note - be sure to include width & height when using toImage() otherwise uses size of stage and fillpatternrepeat will seem to fail.
var image = layer2.toImage({
width: 10, height: 10,
callback(img) {
// do stuff with img
var blob = new Konva.Line({
points: [23, 20, 23, 160, 70, 93, 150, 109, 290, 139, 270, 93],
fill: '#00D2FF',
fillPriority: 'pattern',
stroke: 'black',
strokeWidth: 5,
closed: true,
tension: 0.3
});
// add the shape to the layer
layer.add(blob);
stage.draw();
var imageObj = new Image();
imageObj.onload = function() {
blob.fillPatternImage(imageObj);
layer2.remove(); // no longer needed.
blob.fillPatternImage(imageObj)
layer.draw();
stage.draw();
};
imageObj.src = img.src;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/4.0.12/konva.min.js"></script>
<div id="container"></div>
<img id='theImg' style='width:100px; height: 100px; border:"2px solid lime"; z-index: 10 '></img>

Kineticjs 'mouseover' tween is working but 'mouseout' tween is not

I am currently trying to make it so a grid of triangles will expand and move to the 'top' layer when you mouse over them, but then shrink back down to original size and move back to the original layer when you mouse out of them. However right now only the mouse over function is working correctly.
Here is the current code Im working with:
var stage = new Kinetic.Stage({
container: 'container',
width: 300,
height: 300
});
var layer = new Kinetic.Layer();
var secondLayer = new Kinetic.Layer();
var tri = new Kinetic.RegularPolygon({
x: stage.width()/2,
y: stage.height()/2,
sides: 3,
radius: 30,
fill: '#111111',
closed: true,
shadowColor: '#5febff',
shadowBlur: 5,
shadowOpacity: 0.18,
});
layer.add(tri);
stage.add(layer);
stage.add(secondLayer);
// bind stage handlers
layer.on('mouseover', function(evt) {
var shape = evt.targetNode;
shape.moveTo(secondLayer);
stage.draw()
var tween = new Kinetic.Tween({
node: shape,
duration: 0.05,
scaleX: 1.5,
scaleY: 1.5
});
tween.play()
});
secondLayer.on('mouseout', function(evt) {
var shape = evt.targetNode;
var tween = new Kinetic.Tween({
node: shape,
duration: 0.05,
scaleX: 1.5,
scaleY: 1.5
});
tween.reverse()
shape.moveTo(layer);
stage.draw();
});
And here is a jsfiddle: http://jsfiddle.net/y2C3Z/1/
You can use tween.reverse() only after tween.play(). So you can just change scale attributes to original values.
Don't move shape between layers while shape under a tween. You can move shape after tween is done.
http://jsfiddle.net/y2C3Z/3/

KineticJS Arrow drawing rotating misaligned

I'm making an interactive diagram website and I'm trying to easily draw arrows in kineticJS relative to the stagesize, i've got the following:
http://jsfiddle.net/K5Zhg/17/
But as you can see the rotated arrow is not matching the intended start and ending point. I tried offset, but that messes up the correct (not rotated) arrow. Also don't know why jsfiddle show's my arrows this messy (missing bottom line), on my own machine it seems to be working fine (using v5.1.0), see also here http://tomzooi.com/dump/ip/ (using kineticjs and binding bootstrap to it, working nice so far)
code:
var stage = new Kinetic.Stage({
container: 'container',
width: 1140,
height: 500
});
var layer = new Kinetic.Layer();
var border = new Kinetic.Rect( {
x: 0,
y: 0,
width: stage.getWidth(),
height: stage.getHeight(),
stroke: ' red',
strokeWidth: 1
});
layer.add(border);
var dot = new Kinetic.Circle({
x: 0.1*stage.getWidth(),
y: 0.1*stage.getHeight(),
radius: 10,
fill: 'red'
});
var dot2 = new Kinetic.Circle({
x: 0.5*stage.getWidth(),
y: 0.1*stage.getHeight(),
radius: 10,
fill: 'red'
});
var dot3 = new Kinetic.Circle({
x: 0.5*stage.getWidth(),
y: 0.5*stage.getHeight(),
radius: 10,
fill: 'red'
});
layer.add(dot);
layer.add(dot2);
layer.add(dot3);
var arrow1 = arrow(0.1,0.1,0.5,0.1,10);
var arrow2 = arrow(0.1,0.2,0.5,0.5,10);
layer.add(arrow1);
layer.add(arrow2);
// add the layer to the stage
stage.add(layer);
function arrow(psx, psy, pex, pey, pw) {
var w = stage.getWidth();
var h = stage.getHeight();
var sx = psx*w;
var ex = pex*w;
var sy = psy*h;
var ey = pey*h;
var pr = (Math.atan2(ey-sy, ex-sx)/(Math.PI/180));
var pl = Math.sqrt(Math.pow((ex-sx),2)+Math.pow((ey-sy),2));
ex = sx+pl;
ey = sy;
var poly = new Kinetic.Line({
points: [sx,sy+pw, sx,sy-pw, ex-3*pw,ey-pw, ex-3*pw,ey-2*pw, ex,ey, ex-3*pw,ey+2*pw, ex-3*pw, sy+pw],
fill: '#EDECEB',
stroke: '#AFACA9',
strokeWidth: 2,
closed: true,
rotation: pr,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x:2,y:2},
shadowOpacity: 0.5
});
return poly;
}
Here is a solution: http://jsfiddle.net/K5Zhg/20/
The problem was that when you rotate the arrow shape, it rotates around x=0 and y=0. However your point was drawn on x=sx and y=sy (in your example case x=60 and y=50).
To fix this draw the points around x=0 and y=0 (and translating the other points in the array using the correct variables) and then setting the x and y property of the Kinetic.Line to sx and sy in order set the position back to its intended location. I.e.
function arrow(psx, psy, pex, pey, pw) {
var w = stage.getWidth();
var h = stage.getHeight();
var sx = psx*w;
var ex = pex*w;
var sy = psy*h;
var ey = pey*h;
// console.log(sx);
var pr = (Math.atan2(ey-sy, ex-sx)/(Math.PI/180));
var pl = Math.sqrt(Math.pow((ex-sx),2)+Math.pow((ey-sy),2));
ex = sx+pl;
ey = sy;
var poly = new Kinetic.Line({
points: [0,0+pw,
0,0-pw, ex-sx-3*pw,ey-sy-pw, ex-sx-3*pw,ey-sy-2*pw, ex-sx,ey-sy, ex-sx-3*pw,ey-sy+2*pw, ex-sx-3*pw, 0+pw],
fill: 'blue',
stroke: 'black',
strokeWidth: 2,
closed: true,
rotation: pr,
x: sx,
y: sy,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: {x:2,y:2},
shadowOpacity: 0.5
});
return poly;
}
I also changed the y value to 0.1 instead of the 0.2 such that the start of the second arrow connects with the red dot.
Oh and I updated the Fiddle to uses v5.0.1.

get position of canvas element after drag relative to canvas

I double click on a canvas to create an element, and the user can do this n times. Each element is draggable.
For each element, if I drag it to within a certain rectangle of x/y coordinates, I want to then clearRect() within that rectangle, effectively deleting the dragged element.
How implement this?
Current:
var stage = new Kinetic.Stage({
container: 'container',
width: 662,
height: 983
});
var layer = new Kinetic.Layer();
stage.add(layer);
$(stage.getContent()).on('dblclick', function (event) {
var pos = stage.getMousePosition();
var mouseX = parseInt(pos.x);
var mouseY = parseInt(pos.y);
var text = new Kinetic.Text({
x: mouseX,
y: mouseY,
text: cc,
fill: "blue",
draggable: true,
});
layer.add(text);
layer.draw();
}
You can use yourElement.on("dragend",handler) to test if the element is inside the deletion rectangle.
If it is inside you can use yourElement.destroy() to destroy that element.
Example code and a Demo: http://jsfiddle.net/m1erickson/jqPhe/
var stage = new Kinetic.Stage({
container: 'container',
width: 350,
height: 350
});
var layer = new Kinetic.Layer();
stage.add(layer);
// define the boundaries of the deletion box
var dx=200;
var dy=40;
var dw=100;
var dh=100;
// create the deletion box
var deleteMe=new Kinetic.Rect({
x:dx,
y:dy,
width:dw,
height:dh,
stroke:"red"
});
layer.add(deleteMe);
var label=new Kinetic.Text({
x:dx,
y:10,
text:"Drag here to delete\n(Must be fully inside)",
fill:"black"
});
layer.add(label);
// create a circle element for testing purposes
var circle1 = new Kinetic.Circle({
x:100,
y:100,
radius: 30,
fill: 'red',
stroke: 'black',
strokeWidth: 4,
draggable: true
});
// on dragend: test if this circle is inside the deletion rectangle. If yes, delete this circle.
circle1.on("dragend",function(){
var x=this.getX();
var y=this.getY();
if(x>=dx && x<=dx+dw && y>=dy && y<=dy+dh){
this.destroy();
layer.draw();
}
});
layer.add(circle1);
layer.draw();

HTML5 Canvas: Draw lines from a centered DIV, connecting to other DIVs around it? (Spiderweb effect) Kinetic JS

My question is: How do I draw lines coming from a specific DIV, & having them connect to the other DIVs on the page? (Spiderweb effect)
So far, I got - jsFiddle: http://jsfiddle.net/audnB/3/
But what I'm trying to do is...
Have all the lines be coming from the mother div, as shown below:
Below is the code that I am currently using (the same as the one in my JsFiddle):
I am actually using <a> (links) for this & not DIVs, but you know what I mean...
var lineCoords = new Array();
var stage;
var globalTimer = null;
$(window).resize(function() {
clearTimeout(globalTimer);
globalTimer = setTimeout(doneResize, 100);
});
function doneResize(){
drawLines();
}
function drawLines(){
lineCoords = new Array();
$('div#container > a').each(function(){
if ($(this).attr('data-action-properties').length>0){
var actionProperties = $.parseJSON($(this).attr('data-action-properties'));
}
var dx = $(this).css('left').replace('px','');
var dy = $(this).css('top').replace('px','');
var wd = ($(this).css('width').replace('px','') /2);
var hi = ($(this).css('height').replace('px','') /2);
var position = $(this).offset();
lineCoords.push(parseInt(dx)+(wd));
lineCoords.push(parseInt(dy)+(hi));
});
var layer = new Kinetic.Layer();
var redLine = new Kinetic.Line({
points: lineCoords,
stroke: '#000',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
dashArray: '0 30 0 30'
});
layer.add(redLine);
stage.add(layer);
}
$(document).ready(function() {
stage = new Kinetic.Stage({
container: "container",
width: $('#container').width(),
height: $(window).height()
});
setTimeout(drawLines,100);
});
$(window).resize(function(e){
stage.clear();
});
function imageresize() {
var contentwidth = $('body').width();
if ((contentwidth) < '700'){
$('.fluidimage').attr('src','little.jpg');
} else {
$('.fluidimage').attr('src','big.jpg');
}
}
imageresize();// Triggers when document first loads
$(window).bind("resize", function(){ // Adjusts image when browser resized
imageresize();
});
Thank you so much for your help, I greatly appreciate it!
When you are declaring redLine as below
var redLine = new Kinetic.Line({
points: lineCoords,
stroke: '#000',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
dashArray: '0 30 0 30'
});
using points: lineCoords essentially draw lines between consecutive points, so you have 2 options,
1. Starting from coordinates of point 2 onwards, after every point add coordinates of point 1 (Mother) assuming Mother is always the first.
points: [lineCoords[0],lineCoords[1],lineCoords[2],lineCoords[3],lineCoords[0],lineCoords[1],lineCoords[4],lineCoords[5]]
OR
2. make a for loop where you draw each line separately wherein assign point as: point: [lineCoords[0],lineCoords[1],lineCoords[2*i],lineCoords[2*i+1]], essentially the start and end point of the line where i = 1,2
This is close to what you're looking for: http://jsfiddle.net/audnB/9/
basically similar to what Ani said.
All your lines need to be from your 0,1 to 2i,2i+1 so that the coordinates match. And in a loop.
var layer = new Kinetic.Layer();
for (var i=0; i<lineCoords.length / 2; i++){
var redLine = new Kinetic.Line({
points: [lineCoords[0], lineCoords[1], lineCoords[2*i],lineCoords[2*i+1]],
stroke: '#000',
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
dashArray: '0 30 0 30'
});
layer.add(redLine);
};
stage.add(layer);

Categories