Phaser: how to group polygons in layers? - javascript

I want to have two polygons, one stationary and one that moves and changes its shape. When they overlap, I want the stationary polygon to stay in top.
This is my approach:
(function() {
"use strict";
var SIZE_X = 400;
var SIZE_Y = 300;
var CENTER_COLOR = 0xFF33FF;
var ALT_COLOR = 0xFFFF33;
var moving_graphics;
var tick = 0;
var LayerTest = {
preload: function() {},
create: function() {
game.world.setBounds(-SIZE_X / 2, -SIZE_Y / 2, SIZE_X / 2, SIZE_Y / 2);
var center_group = game.add.group();
center_group.z = 1;
var center_graphics = new Phaser.Graphics(game, 0, 0);
center_graphics.beginFill(CENTER_COLOR);
center_graphics.drawPolygon(new Phaser.Polygon([
new Phaser.Point(-30, -30),
new Phaser.Point(-30, 30),
new Phaser.Point(30, 30),
new Phaser.Point(30, -30)
]));
center_graphics.endFill();
center_group.add(center_graphics);
var moving_group = game.add.group();
moving_group.z = 0;
moving_graphics = new Phaser.Graphics(game, 0, 0);
moving_group.add(moving_graphics);
},
update: function() {
moving_graphics.clear();
moving_graphics.beginFill(ALT_COLOR);
moving_graphics.drawPolygon(new Phaser.Polygon([
new Phaser.Point(-SIZE_X / 2 + tick - tick % 40, -10),
new Phaser.Point(-SIZE_X / 2 + tick - tick % 40, 10),
new Phaser.Point(20 - SIZE_X / 2 + tick, 10),
new Phaser.Point(20 - SIZE_X / 2 + tick, -10)
]));
moving_graphics.endFill();
tick++;
}
};
var game = new Phaser.Game(SIZE_X, SIZE_Y, Phaser.AUTO, '', LayerTest);
})();
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/phaser/2.4.4/phaser.js"></script>
</head>
<body>
</body>
</html>
I'm creating a pink square in the center and then a yellow rectangle that starts in the left side of the screen and then moves towards the center. However, even though I've added them to groups and the center one has a higher z-index, the moving group is always set on top. If I don't use groups and set the z-index directly for each graphics object, the final result is the same.
I want the moving group (the yellow rectangle) to remain behind the other one.

Add the moving group before you add the center group.
(function() {
"use strict";
var SIZE_X = 400;
var SIZE_Y = 300;
var CENTER_COLOR = 0xFF33FF;
var ALT_COLOR = 0xFFFF33;
var moving_graphics;
var tick = 0;
var LayerTest = {
preload: function() {},
create: function() {
game.world.setBounds(-SIZE_X / 2, -SIZE_Y / 2, SIZE_X / 2, SIZE_Y / 2);
var moving_group = game.add.group();
moving_graphics = new Phaser.Graphics(game, 0, 0);
moving_group.add(moving_graphics);
var center_group = game.add.group();
var center_graphics = new Phaser.Graphics(game, 0, 0);
center_graphics.beginFill(CENTER_COLOR);
center_graphics.drawPolygon(new Phaser.Polygon([
new Phaser.Point(-30, -30),
new Phaser.Point(-30, 30),
new Phaser.Point(30, 30),
new Phaser.Point(30, -30)
]));
center_graphics.endFill();
center_group.add(center_graphics);
},
update: function() {
moving_graphics.clear();
moving_graphics.beginFill(ALT_COLOR);
moving_graphics.drawPolygon(new Phaser.Polygon([
new Phaser.Point(-SIZE_X / 2 + tick - tick % 40, -10),
new Phaser.Point(-SIZE_X / 2 + tick - tick % 40, 10),
new Phaser.Point(20 - SIZE_X / 2 + tick, 10),
new Phaser.Point(20 - SIZE_X / 2 + tick, -10)
]));
moving_graphics.endFill();
tick++;
}
};
var game = new Phaser.Game(SIZE_X, SIZE_Y, Phaser.AUTO, '', LayerTest);
})();
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/phaser/2.4.4/phaser.js"></script>
</head>
<body>
</body>
</html>

Related

In jsxgraph, why doesn't a parabola get drawn through five points on a same plane?

In a related question I was looking for a way to draw points in 3D space so that the points will move according to slider values. Now that is working, but the conic section (a parabola in this case) I am trying to draw through these points, is not drawn.
I thought that the constructor for the element "conic" might be picky about how the given points are defined, so I ended up adding as attributes "sub-objects" that are points that can be referred to when drawing the conic.
In my code below, the constructor function PPoint creates objects that have their respective attributes pcoord, which is a geometric object of type "point" created using the native jsxgraph constructor for points. pcoord is assigned when the method "draw" is called to the draw the points I_1-I-4 and p_1.
In the last lines of the code, the parabola should be drawn by referring to the pcoords of objects I_1-I_4 and p_1, but for some reason the parabola is not drawn.
How could this be fixed? Link to jsfiddle. The code is executed without error notifications when debugging.
HTML
<div id="jxgbox" class="jxgbox" style="width:500px; height:500px">
</div>
JS
const board = JXG.JSXGraph.initBoard('jxgbox', {
boundingbox: [-10, 10, 10, -10],
axis: true,
showCopyright: true,
showNavigation: true,
pan: false,
grid: false,
zoom: {
factorX: 1.25,
factorY: 1.25,
wheel: false
}
});
//create z axis
var zAxis = board.create('axis', [
[0, 0],
[-1, -1]
], {
ticks: {
majorHeight: 10,
drawLabels: false
}
});
//create direction of view for projections
var cam = [4, 4, 30]; // [x,y,z]
var r = 6.0;
var origin = [0, 0, 0];
// Function for parallel projection
var project = function(crd, cam) {
var d = -crd[2] / cam[2];
return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};
//create slider for rotating the parabola
var sRadius = board.create('slider', [
[1, -8.5],
[6, -8.5],
[-10, 0, 10]
], {
name: 'angle',
needsRegularUpdate: true
//snapWidth: 1
});
//create slider for adjusting the angular speed
var sOmega = board.create('slider', [
[1, -7.5],
[6, -7.5],
[0, 0, 10]
], {
name: 'Omega',
needsRegularUpdate: true
//snapWidth: 1,
});
//fix parameters
const g = 9.81 //gravitational acceleration
const h0 = 5 //initial height of the water surface
//define radius from the y-axis for I3 and I4
const R34 = Math.sqrt(2);
// Function for parallel projection
var project = function(crd, cam) {
var d = -crd[2] / cam[2];
return [1, crd[0] + d * cam[0], crd[1] + d * cam[1]];
};
//function creates points for drawing conic sections
function PPoint(radius, sign, namep, fixval) {
this.R = radius;
this.S = sign;
this.Namep = namep;
this.Fixval = fixval;
this.pcoord = undefined; //Cartesian coordinates of the point, stored as a point
}
//method for drawing each Point
PPoint.prototype.draw = function(pp) {
board.create('point', [function() {
var K1 = sOmega.Value() * sOmega.Value() / g,
KK = 1 / 4 * sOmega.Value() * sOmega.Value() / g,
v = sRadius.Value() * Math.PI * 0.5 / 10.0,
c = [pp.S * pp.R * Math.sin(v), K1 / 2 * pp.R * pp.R - KK + h0, pp.S * pp.R * Math.cos(v)];
//store the dynamically assigned coordinates of the point for drawing the parabola
pp.pcoord = board.create('point', [function() {
return project(c, cam);
}], {
visible: false
}); //end storing pp.coord
return project(c, cam);
}], {
fixed: this.Fixval,
name: this.Namep,
visible: true
})
}
//create and draw points
var p_1 = new PPoint(0, -1, 'p_1', 'false');
var I_1 = new PPoint(r, 1, 'I_1', 'false');
var I_2 = new PPoint(r, -1, 'I_2', 'false');
var I_3 = new PPoint(R34, 1, 'I_3', 'false');
var I_4 = new PPoint(R34, -1, 'I_4', 'false');
p_1.draw(p_1)
I_1.draw(I_1)
I_2.draw(I_2)
I_3.draw(I_3)
I_4.draw(I_4)
//draw the rotating parabola
var prbl = board.create('conic', [I_1.pcoord, I_2.pcoord, I_3.pcoord, I_4.pcoord, p_1.pcoord], {
strokeColor: '#CA7291',
strokeWidth: 2,
trace :true
});
//debugger
There are two issues with this code:
1) In PPoint.draw the reference two the JSXGraph point does not work: in each update an new JSXGraph point is created. This makes the code slow and - moreover - does not influence the initial points supplied to the conic section. I would propose to change draw to this:
PPoint.prototype.draw = function(pp) {
pp.pcoord = board.create('point', [function() {
var K1 = sOmega.Value() * sOmega.Value() / g,
KK = 1 / 4 * sOmega.Value() * sOmega.Value() / g,
v = sRadius.Value() * Math.PI * 0.5 / 10.0,
c = [pp.S * pp.R * Math.sin(v),
K1 / 2 * pp.R * pp.R - KK + h0,
pp.S * pp.R * Math.cos(v)];
return project(c, cam);
}], {
fixed: this.Fixval,
name: this.Namep,
visible: true});
2) The second problem is that JSXGraph fails to plot degenerated conics through five points and suffers in precision if the conic is close to be degenerated (there are numerical issues with general parabolas). This is the case here for the start value omega = 0.
Here is a working example: https://jsfiddle.net/L2d4zt8q/

unlimited stack of tile(object/sprite) in que after dragging the first to toppest one in phaser

i am making a game using phaser and i want to make unlimited no of tiles can think like stacked tiles. When the user drags the topmost tile and places it in the drop area, the same tile below it should appear and should be draggable.
My present code:- `
var greenTile = this.add.sprite(250,500,'greenTile');
greenTile.inputEnabled=true;
greenTile.input.enableDrag();
greenTile.events.onDragStart.add(onDragStart, this);
greenTile.events.onDragStop.add(onDragStop, this);`
the total code is of my game state is :-
`
var patternsRatio = patternsRatio || {};
var x = 50;
var y = 100;
var canvas;
var canvasBG;
var canvasGrid;
var canvasSprite;
var canvasZoom = 32;
var spriteWidth = 8;
var spriteHeight = 8;
patternsRatio.game1 = function () {};
patternsRatio.game1.prototype = {
preload: function () {
this.load.image('greenTile','assets/images/greentile.png')
this.load.image('redTile','assets/images/redtile.png')
},
create: function () {
this.game.stage.setBackgroundColor(0x2d2d2d);
var question_l1 = "Puzzle 1: Enlarge this pattern by a factor of 2."
var style_l1 = {font: "25px Comic Sans MS Bold", fill: "#fff", align:"center"};
var quet_l1=this.game.add.text(this.game.world.centerX,this.game.height-600, question_l1, style_l1)
quet_l1.anchor.setTo(0.5)
this.placetiles()
var greenTile = this.add.sprite(250,500,'greenTile');
greenTile.inputEnabled=true;
greenTile.input.enableDrag();
greenTile.events.onDragStart.add(onDragStart, this);
greenTile.events.onDragStop.add(onDragStop, this);
var redTile = this.add.sprite(100,500,'redTile');
redTile.inputEnabled=true;
redTile.input.enableDrag();
redTile.events.onDragStart.add(onDragStart, this);
redTile.events.onDragStop.add(onDragStop, this);
},
update: function () {
},
placetiles: function () {
this.game.create.grid('drawingGrid', 16 * canvasZoom, 16 * canvasZoom, canvasZoom, canvasZoom, 'rgba(0,191,243,0.8)');
canvas = this.game.make.bitmapData(spriteWidth * canvasZoom, spriteHeight * canvasZoom);
canvasBG = this.game.make.bitmapData(canvas.width + 2, canvas.height + 2);
canvasBG.rect(0, 0, canvasBG.width, canvasBG.height, '#fff');
canvasBG.rect(1, 1, canvasBG.width - 2, canvasBG.height - 2, '#3f5c67');
var x = 80;
var y = 64;
canvasBG.addToWorld(x, y);
canvasSprite = canvas.addToWorld( x + 1, y + 1); canvasZoom,canvasZoom
canvasGrid = this.game.add.sprite(x + 1, y + 1, 'drawingGrid');
canvasGrid.crop(new Phaser.Rectangle(0, 0, spriteWidth * canvasZoom, spriteHeight * canvasZoom));
}
};
`
I am also facing problem when i am adding a input.enable code below the "greenTile" variable then the redTile vanishes of can any tell why this happens.
In the image below as we can see both red and green tile are appearing.
In this image as we can i had added input enable and the red Tile stopped appearing, Secondly as have dragged the green tile to the grid, i want on the original place their should be again the greenTile should come.(this is in reference to the stack able unlimited tile question)
I could figure this out by just adding a function and calling it on the drag start event as below:-
The function that i added is :-
addGreenTiles: function(){
this.greenTile1 = this.add.sprite(250,500,'greenTile');
this.greenTile1.inputEnabled=true;
this.greenTile1.input.enableSnap(canvasZoom, canvasZoom, false, true);
this.greenTile1.input.enableDrag();
this.greenTile1.originalPosition = this.greenTile1.position.clone();
this.greenTile1.events.onDragStart.add(this.addGreenTiles, this);
this.greenTile1.events.onDragStop.add(function(currentSprite){
this.stopDrag(currentSprite, this.greenTile1);
}, this);
Then i called this function at :
this.greenTile1.events.onDragStart.add(this.addGreenTiles, this);

Simple Clock with Raphael 2.1.4

Newbie here, I have a simple clock with Raphael 2.1.4 based on a tutorial everything renders on the page fine but the handles are not rotating. However it does seem to work on Raphael 1.5.X.
Can you tell me what I am doing wrong?
Code pen page attached
http://codepen.io/scorpion_rain/pen/dGrmQj
Code JS:
window.onload = function() {
var cWidth = 800, cHeight = 600;
var paper = new Raphael(document.getElementById('canvas_container'), cWidth, cHeight);
var clockBgX = 200, clockBgY = 300, clockBgRadius = 100;
var cBgCol = '#f5f5f5', cBgStrokeCol = '#444444', cBgStrokeWidth = '5';
var centerDialX = clockBgX, centerDialY = clockBgY;
var hourHandStrokeCol = "#444444", hourHandStrokeWidth = "5";
var minuteHandStrokeCol = "#444444", minuteHandStrokeWidth = "3";
var secondsHandStrokeCol = "#444444", secondsHandStrokeWidth = "2";
var pinDotX = clockBgX, pinDotY = clockBgY, pinDotRadius = 5, pinDotFill = "#000000";
// main clock background and number display
function mainClockBg(){
var clockBg = paper.circle(clockBgX, clockBgY, clockBgRadius); // outer circle
clockBg.attr({ "fill": cBgCol, // inner background
"stroke": cBgStrokeCol,
"stroke-width": cBgStrokeWidth })
var radius = Math.PI / 180; // converting from degrees to radian
var cx = centerDialX; // center of dial - horizontal
var cy = centerDialY; // center of dial - vertical
var r = 90; // radius distance
var startA = -90; // start of numbers
var angle = 30; // distance between numbers | 12/360 = 12 stops
var x; // circle distance inner marker
var y; // circle distance outer marker
var endA; // end of text
// adding numbers to the dial
for(i = 1; i < 13; i++){
endA = startA + angle;
x = cx + r * Math.cos( endA * radius );
y = cy + r * Math.sin( endA * radius );
paper.text( x, y, i + "" );
startA = endA;
}
}
function dialsDisplay(){
var hourHand = paper.path("M200, 300L200, 230");
hourHand.attr({
"stroke": hourHandStrokeCol,
"stroke-width": hourHandStrokeWidth
});
var minuteHand = paper.path("M200, 300L200, 220");
minuteHand.attr({
"stroke": minuteHandStrokeCol,
"stroke-width": minuteHandStrokeWidth
})
var secondsHand = paper.path("M200, 300L200, 216");
secondsHand.attr({
"stroke": secondsHandStrokeCol,
"stroke-width": secondsHandStrokeWidth
})
var pinDot = paper.circle(pinDotX, pinDotY, pinDotRadius);
pinDot.attr({
"fill": pinDotFill
});
updateClock();
setInterval("updateClock()", 1000);
}
function updateClock(){
var time = new Date();
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
hourHand.rotate( 30 * hours + (minutes / 2.5), 200, 300 );
minuteHand.rotate( 6 * minutes, 200, 300 );
secondsHand.rotete(6 * seconds, 200, 300);
}
mainClockBg();
dialsDisplay();
}
in the console of the browser i get the error 'cant find variable hourHand'
Any help appreciated
Cheers.
You are defining a variable with 'var' in one function, and then referencing it in another, this sets where the scope is.
Javascript has functional scope, so one function won't know about a variable unless its defined in a scope it can access. So move the hourHand, minuteHand, secondsHand outside of the function. Then the updateClock method will be able to access those variables.
// THIS WONT WORK
function func1() {
var hand = 1;
}
function func2() {
var test = hand; //hand was declared in other function, so not available here
}
So try this form instead
var hand;
function func1() {
hand = 1;
}
function func2() {
var test = hand;
}
Also you will want
setInterval(updateClock, 1000);
rather than
setInterval("updateClock()", 1000);
as setInterval wants a function to call, rather than a string to execute.
Then I'm guessing there is some issue with the movement of the hands you will need to adjust :).
codepen

Animating multiple items in Paper.js while anchored to a path

I have five rectangles placed at different points along a circle like this - http://imgur.com/uVYkwl7.
Upon clicking any rectangle i want the circle to move to the left of the screen, gradually scaling down it's radius until the circle's center reaches x=0. I'd like the five rectangles to move along with the circle while its being scaled down and also adjust their own positions and scale on the circle so that they are within the view's bounds, like this - http://imgur.com/acDG0Aw
I'd appreciate any help on how to go about doing this. Heres my code for getting to the 1st image and animating the circle:
var radius = 300;
var center = view.center;
var circle = new Path.Circle({
center: view.center,
radius: radius,
strokeColor: 'black',
name: 'circle'
});
var path = new Path.Rectangle({
size: [230, 100],
fillColor: '#1565C0'
});
var rectText = ['Text 1',
'Text 2',
'Text 3',
'Text 4',
'Text 5'
];
var symbol = new Symbol(path);
var corners = [
new Point(center.x, center.y - radius),
new Point(center.x - radius, center.y - radius / 2),
new Point(center.x + radius, center.y - radius / 2),
new Point(center.x - radius, center.y + radius / 2),
new Point(center.x + radius, center.y + radius / 2)
];
var rectClicked = false;
var clickedRect = null;
var rectClick = function(event) {
rectClicked = true;
clickedRect = this;
};
function onFrame(event) {
// Your animation code goes in here
if (rectClicked) {
for (var i = 0; i < 1; i++) {
var item = project.activeLayer.children[i];
if (item.name == 'circle') {
if (item.position.x < 0) {
rectClicked = false;
} else {
item.position.x -= 10;
item.scale(1/1.01);
}
}
}
}
}
// Place the instances of the symbol:
for (var i = 0; i < corners.length; i++) {
var placedSymbol = symbol.place(corners[i]);
placedSymbol.onMouseDown = rectClick;
var rText = new PointText({
point: placedSymbol.bounds.topLeft + 20,
content: rectText[i],
fontSize: '20',
fillColor: 'white'
});
}
Paper.js provides rotations around a pivot out of the box.
var pivotPoint = new Point(10, 5);
circle.rotate(30,pivotPoint);
Here is the docs reference for this behaviour and here is a very basic Sketch example to illustrate this
The above snippet will rotate a circle(you can change this to rectangle in your case) by 30 degrees around a pivot point at coordinates 10,5 on the x/y axis.
Thus what you describe is certainly doable as long as the path that your elements will follow is always circular.
Bear in mind that in order for the pivot rotation to work the way you want them to you need to update the pivotPoint and reinitiate the rotation again.
Note: In case you want to move along an arbitrary shape instead of circular path, you should search for Paper.js animation-along-a-path which is something that I've seen been done before without much difficulty - e.g this simple Sketch by the creator of Paper.js himself.
The sketch I provided above is a basic example of rotation around a pivot point.
I'm dumping the Sketch code here in case the link goes dead:
//Create a center point
var centerCircle = new Path.Circle(paper.view.center, 100);
centerCircle.strokeColor = 'black';
centerCircle.dashArray = [10, 12];
//Create the circles
var circle1Radius = 30;
var circle1 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle1Radius, circle1Radius);
circle1.fillColor = '#2196F3';
var circle2Radius = 40;
var circle2 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle2.fillColor = '#E91E63';
var circle3Radius = 40;
var circle3 = new Path.Circle((centerCircle.position-centerCircle.bounds.width/2)+circle2Radius, circle2Radius);
circle3.fillColor = '#009688';
var i=0;
var animationGap = 125; //how long to move before animating the next circle
var rotationSpeed = 2;
function onFrame(event) {
circle1.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap)
circle2.rotate(rotationSpeed,centerCircle.position);
if(i>animationGap*2)
circle3.rotate(rotationSpeed,centerCircle.position);
i++;
}

Draw line with arrow cap

I am trying to draw a line with arrow at the tip of the line. But i am unable to complete it. Can any one help me.
I tried adding triangle with line but unfortunately it wont work while dynamically drawing. This is what i tried along with line.
var myPath;
function onMouseDown(event) {
myPath = new Path();
myPath.strokeColor = 'black';
}
function onMouseDrag(event) {
myPath.add(event.point);
}
function onMouseUp(event) {
var myCircle = new Path.RegularPolygon(event.point, 3, 10);
myCircle.strokeColor = 'black';
myCircle.fillColor = 'white';
}
you draw line with arrow with this code ,
paper.Shape.ArrowLine = function (sx, sy, ex, ey, isDouble) {
function calcArrow(px0, py0, px, py) {
var points = [];
var l = Math.sqrt(Math.pow((px - px0), 2) + Math.pow((py - py0), 2));
points[0] = (px - ((px - px0) * Math.cos(0.5) - (py - py0) * Math.sin(0.5)) * 10 / l);
points[1] = (py - ((py - py0) * Math.cos(0.5) + (px - px0) * Math.sin(0.5)) * 10 / l);
points[2] = (px - ((px - px0) * Math.cos(0.5) + (py - py0) * Math.sin(0.5)) * 10 / l);
points[3] = (py - ((py - py0) * Math.cos(0.5) - (px - px0) * Math.sin(0.5)) * 10 / l);
return points;
}
var endPoints = calcArrow(sx, sy, ex, ey);
var startPoints = calcArrow(ex, ey, sx, sy);
var e0 = endPoints[0],
e1 = endPoints[1],
e2 = endPoints[2],
e3 = endPoints[3],
s0 = startPoints[0],
s1 = startPoints[1],
s2 = startPoints[2],
s3 = startPoints[3];
var line = new paper.Path({
segments: [
new paper.Point(sx, sy),
new paper.Point(ex, ey)
],
strokeWidth: 1
});
var arrow1 = new paper.Path({
segments: [
new paper.Point(e0, e1),
new paper.Point(ex, ey),
new paper.Point(e2, e3)
]
});
var compoundPath = new paper.CompoundPath([line, arrow1]);
if (isDouble === true) {
var arrow2 = new paper.Path({
segments: [
new paper.Point(s0, s1),
new paper.Point(sx, sy),
new paper.Point(s2, s3)
]
});
compoundPath.addChild(arrow2);
}
return compoundPath;};
use
tool.onMouseDrag = function (event) { this.item = new paper.Shape.ArrowLine(event.downPoint.x, event.downPoint.y, event.point.x, event.point.y);
this.item.removeOnDrag();}
There is an example code in paperjs refrence which draws an arrow at the end of a vector.
Have a look at: http://paperjs.org/tutorials/geometry/vector-geometry/ (scroll all the way down to the end of the page)
A simple approach is to create a group that consists of the vector itself (the line) and the arrow head. lineStart and lineEnd are the points where the line of the arrow starts and ends.
// parameters
headLength = 10;
headAngle = 150;
lineStart = new Point(200, 200);
lineEnd = new Point (250, 250);
tailLine = new Path.Line(lineStart, lineEnd);
tailVector = lineEnd - lineStart;
headLine = tailVector.normalize(headLength);
arrow = new Group([
new Path([lineStart, lineEnd]),
new Path([
lineEnd + headLine.rotate(headAngle),
lineEnd,
lineEnd + headLine.rotate(-headAngle)
])
]);
arrow.strokeColor = 'black';
And, as previously mentioned, if you want to recreate it each time then you can make the previous code a function, something like:
// parameters
var headLength = 10;
var headAngle = 150;
var arrowColor = 'black';
// the arrow
var arrow = null;
function drawArrow(start, end) {
var tailLine = new Path.Line(start, end);
var tailVector = end - start;
var headLine = tailVector.normalize(headLength);
arrow = new Group([
new Path([start, end]),
new Path([
end + headLine.rotate(headAngle),
end,
end + headLine.rotate(-headAngle)
])
]);
arrow.strokeColor = arrowColor;
}
tool.onMouseDrag = function(e) {
if (arrow) {
arrow.remove();
}
drawArrow(e.downPoint, e.point);
}
Here is a sketch of the previous code sketch.paperjs.org
Here's an example, where I extend paper.Group.
In my example I avoid redrawing the arrow on each mousedrag. I create once on mousedown and then transform the line and the arrow parts to the appropriate position/rotation on each mousedrag.
Note: I'm fairly certain the following code can be improved a lot.
Drawing via mouse events
'use strict'
/* Arrow Class extends Group */
const Arrow = paper.Group.extend({
initialize: function (args) {
paper.Group.call(this, args)
this._class = 'Arrow'
this._serializeFields = Object.assign(this._serializeFields, {
from: null,
to: null,
headSize: null
})
this.from = args.from
this.to = args.to || args.from
this.headSize = args.headSize
// #NOTE
// `paper.project.importJSON()` passes the deserialized children
// (the arrow parts) to the `Group` superclass so there's no need to
// create them again.
if (this.children.length)
return
this.addChildren([
new paper.Path({
...args,
segments: [
this.from,
this.from
]
}),
new paper.Path({
...args,
segments: [
this.from,
this.from
]
}),
new paper.Path({
...args,
segments: [
this.from,
this.from
]
})
])
this.update(this.to)
},
update: function (point) {
const angle = this.from.subtract(point).angle - 90
this.children[0].lastSegment.point = point
this.children[1].firstSegment.point = point
this.children[1].lastSegment.point = point.add(
this.headSize,
this.headSize
)
this.children[2].firstSegment.point = point
this.children[2].lastSegment.point = point.add(
-this.headSize,
this.headSize
)
this.children[1].rotate(angle, point)
this.children[2].rotate(angle, point)
return this
}
})
paper.Base.exports.Arrow = Arrow
/* Usage */
paper.setup(document.querySelector('canvas'))
const tool = new paper.Tool()
let arrow
tool.onMouseDown = e => {
arrow = new Arrow({
from: e.point,
headSize: 10,
strokeWidth: 1,
strokeColor: '#555',
strokeCap: 'round'
})
}
tool.onMouseDrag = e => {
arrow.update(e.point)
}
canvas {
display: block;
width: 100%;
height: 100%;
margin: 0;
background: #fafafa;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.11.5/paper-core.min.js"></script>
<canvas resize="true"></canvas>
... or just draw to a static position
If you want to just draw the arrow (without using mouse events), just do the following:
const arrow = new Arrow({
from: new paper.Point(100, 100),
to: new paper.Point(200, 200),
headSize: 10,
strokeWidth: 1,
strokeColor: '#555',
strokeCap: 'round'
})

Categories