Adding Width to a Curved Path in Three.js - javascript

I created a racetrack shaped curve in three.js with the following code:
var path = new THREE.Path();
path.moveTo(150,50);
path.lineTo(150,150);
path.quadraticCurveTo(150,175,100,175);
path.quadraticCurveTo(50,175,50,150);
path.lineTo(50,50);
path.quadraticCurveTo(50,25,100,25);
path.quadraticCurveTo(150,25,150,50);
var pathPoints = path.getPoints();
var pathGeometry = new THREE.BufferGeometry().setFromPoints(pathPoints);
var pathMaterial = new THREE.LineBasicMaterial({color:0xFF1493});
var raceTrack = new THREE.Line(pathGeometry,pathMaterial);
scene.add(raceTrack);
}
Right now, the track is just a single line, and I wanted to know if it was possible to make the track into a geometry with a width (still 2D) so that I can add a texture to it.
Currently, the path looks something like this:
What I'd like is to be able to draw the same shape, but just increase the width of the line:

With R91, three.js added support for triangulated lines. This approach enables line width greater than 1px in a reliable way.
Demo: https://threejs.org/examples/webgl_lines_fat.html
There are no textures applied on the example but uv-coordinates are generated for the underlying geometry.

With regular Line-objects, there is no way to achieve this.
Here are a few options you can try:
create your complete "race-track" as a geometry, including both the inner and the outer line. I have no idea what you need this for, but this is probably the most "correct" way to do something like this (using this approach, the race-track can have different width at different points, you have control over how bends and turns behave and so on). A quick example:
const shape = new THREE.Shape();
shape.moveTo(150, 50);
shape.lineTo(150, 150);
shape.quadraticCurveTo(150, 175, 100, 175);
shape.quadraticCurveTo(50, 175, 50, 150);
shape.lineTo(50, 50);
shape.quadraticCurveTo(50, 25, 100, 25);
shape.quadraticCurveTo(150, 25, 150, 50);
const innerShape = new THREE.Path();
innerShape.moveTo(140, 40);
innerShape.lineTo(140, 140);
innerShape.quadraticCurveTo(140, 165, 90, 165);
innerShape.quadraticCurveTo(60, 165, 60, 140);
innerShape.lineTo(60, 50);
innerShape.quadraticCurveTo(60, 35, 110, 35);
innerShape.quadraticCurveTo(140, 35, 140, 60);
shape.holes.push(innerShape);
var raceTrack = new THREE.Mesh(
new THREE.ShapeGeometry(shape),
new THREE.MeshBasicMaterial({ color: 0xff1493 })
);
full code here: https://codepen.io/usefulthink/pen/eMBgmE
alternatively, you can use the new fat-lines implementation shown here: https://threejs.org/examples/?q=line#webgl_lines_fat or the MeshLine implementation from here: https://github.com/spite/THREE.MeshLine, but I have the feeling those do not what you are looking for...

Related

Set position for object while adding it to canvas in Fabric.js

I am adding an object to my fabric.js canvas using JavaScript (in a React.JS project), but I don't want it to be rendered in the top left corner every time. I want it so that when I use the canvas.add() function, I can specify the x, y co-ordinates at which I can render the object.
Something like this maybe -
const addObject = (canvas) => {
img = fabric.Image(img);
canvas.add(img, 20, 15) //(20,15) represent the x,y co-ordinates of where I want to render img
I just want it so that my object is added to the specified position automatically on calling the addObject() function.
You can try using the LEFT and TOP.
For example, locating can be done this way. This could be an example for you.
var circle = new fabric.Circle({
left: 20,
top: 15,
radius: 25,
fill: randomColor(),
hasRotatingPoint: true
});
canvas.add(circle)
If you want it to be random, you can use it as follows.
var circle = new fabric.Circle({
left: fabric.util.getRandomInt(25, canvas.width - 25),
top: fabric.util.getRandomInt(25, canvas.height - 25),
radius: 25,
fill: randomColor(),
hasRotatingPoint: true
});
canvas.add(circle);
Hopefully it benefits your business.

Javascript getmouse

I found a neat plugin named "isomer master". This allows you to make an isometric landscape using coordinates and colors. What im trying to do currently is make a placement grid in which you hover your mouse over an area to place a block. The syntax is as follows:
var Shape = Isomer.Shape;
var Point = Isomer.Point;
var Color = Isomer.Color;
var red = new Color(160, 60, 50);
var blue = new Color(226, 99, 0);
iso.add(Shape.Prism(Point.ORIGIN, 3, 3, 1));
iso.add(Shape.Pyramid(Point(0, 2, 1)), red);
I figured it out, I was using incorrect syntax in getting the mouse's position.

How do you animate a line using EaselJS and TweenJS

My goal is to have a line animate from point A to point B using the Tween function.
The drawing library I am using is EaselJS and for Tweening I am using TweenJS.
Is this possible using the moveTo function to animate a straight line from point A to point B?
My current setup is as follows:
var line = new createjs.Shape();
line.beginStroke('cyan');
line.setStrokeStyle(3);
line.moveTo(100, 100);
My goal is to animate this path from x100 y100 to x0 y0.
Animation Example:
I have tried this using the following and nothing happens:
var line = new createjs.Shape();
line.beginStroke('cyan');
line.setStrokeStyle(3);
line.moveTo(100, 100);
createjs.Tween.get(line).to({x: 0, y: 0}, 1000, createjs.Ease.sineInOut);
Nothing happens.
Draw Example:
However if I use this I get the line as expected but it is not animated:
var line = new createjs.Shape();
line.beginStroke('cyan');
line.setStrokeStyle(3);
line.moveTo(100, 100);
line.lineTo(0, 0);
This draws a line as expected.
Is there some way to use the lineTo method with the tweening method I am missing? I have checked the documentation of both Easel and TweenJS and can't find an example or any clear instructions on how to do this or if this is not possible.
Any help is appreciated.
The easiest approach is to use a Graphics command. The .command property returns the last created graphics command, which you can then manipulate with a tween:
var cmd = line.graphics.lineTo(100,100).command;
createjs.Tween.get(cmd).to({x:0}, 1000);
Here's a working example: https://jsfiddle.net/gskinner/17Lk8a9s/1/
Demo: http://jsfiddle.net/thpbr1vt/3/
Attention! Performance.
var stage = new createjs.Stage("canvas");
var vpoint = new createjs.Point( 100, 100);
var line = new createjs.Graphics();
line.beginStroke( 'cyan' );
line.moveTo( vpoint.x, vpoint.y );
var s = new createjs.Shape(line);
stage.addChild(s);
createjs.Tween.get(vpoint).to({x: 0, y: 0}, 1000, createjs.Ease.sineInOut);
createjs.Ticker.addEventListener("tick", tick);
function tick() {
line.lineTo( vpoint.x, vpoint.y );
stage.update();
}

Positioning A Set in Raphael Paper

Is there any way to group bunch of elements of paper in one set and only position that set in the paper?
For example At This Example I was trying to put some circles in side a rectangle and just position the rectangle in each part of the paper. Can you please let me know how to do it?
var paper = Raphael('my-canvas', 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var st = paper.set();
st.push(
rect.circle(10, 10, 5),
rect.circle(30, 10, 5));
You can do this via a transform on the set (you could also do it with another attribute like x,y but only if the elements use that specific attribute).
Its worth noting, that although you can apply a transform to the set, it is in effect applying the transform to each element in the set. Ie there is no specific 'set' or 'group' element in Raphael (there is in Snap.svg which is its updated brother, but doesn't quite have the same backwards compatibility). So there is no true hierarchy of groups, where they could have separate transforms which cascade down.
var paper = Raphael('my-canvas', 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var st = paper.set();
st.push(
paper.rect(5, 5, 100, 100),
paper.circle(10, 10, 5).attr({ fill: 'blue' }),
paper.circle(30, 10, 5).attr({ fill: 'green' })
);
st.transform('t20,20');
st.animate({ transform: 't100,100' }, 2000);
Its worth looking at the Raphael docs for transforms if not sure here
jsfiddle
Instead of using a set, you can create a new div, add a new paper element to this div and then change the position of the div.
If you are using jquery, it could look something like this:
$(".body").append('<div id="setContainer"></div>');
paper = new Raphael(document.getElementById("setContainer"), 500, 300);
paper.canvas.style.backgroundColor = '#F00';
var rect = paper.rect(5, 5, 100, 100);
var circle = paper.circle(10, 10, 5);
var circle2 = paper.circle(30, 10, 5);
// then you can adjust the position of the div, for example to 100,100
$("#setContainer").css("top", 100);
$("#setContainer").css("left", 100);
The advantage of using this approach rather than a set is that it gives you more flexibility for the way you want to manipulate the elements you are grouping together.
You can even wrap a function around this code in order to define the id of the container programatically if you wanted to create several instances of the same group of elements.

How can I change individual object's attributes in the Raphael SET?

Let's consider I have a circle and a rectangle in ss Raphael Set:
<script type="text/javascript">
var paper = Raphael("canvas", 500, 500),
r = paper.rect(100, 100, 140, 80),
c = paper.circle(100, 100, 80);
c.attr({fill: 'red', stroke: 'black'});
r.attr({fill: 'black', stroke: 'red'});
var ss = paper.set(r, c);
</script>
Now at some point in the program, I need to change say Circle's fill: 'white'.
I know that it is possible to change Set's attribute as follows: ss.attr({fill: 'white'}), but this applies to all of its elements. I still want to keep the color of rectangle unchanged. I have tried ss.c.attr(), but no result.
Any idea how can I achieve this. Thanks
I had the same problem a while ago. Then I found out that you can access SET individual objects just like in array.
For exp.; ss[0] returns your r rectangle object; i.e. ss[0].attr({'//here'})

Categories

Resources