Random names instead of patterns in particle.js - javascript

Before anything, I have no idea what I'm doing but I was wondering if it was possible to use vincentgarreaus' particles with names instead of patterns?
I managed to edit particle.js and add a function that randomly picks a name and it replaces the circles for the names but my problem is that while moving the names change too fast in the same particle. If I set it to static it works as intended but I want them moving.
Is it possible?
What I did is going to VG website > inspect element > ctrl P > particle.js > Line 426 and pasted this "code" > ctrl S to save
function PlayerSelector1() {
var word = ['player1', 'player2', 'player3', 'player4', 'player5', 'player6'];
var random = word[Math.floor(Math.random() * word.length)];
return random;
}
switch(p.shape){
case "circle":
var context = pJS.canvas.ctx.canvas.getContext("2d");
var xtxx = PlayerSelector1();
context.beginPath();
context.fillStyle = "black";
context.fillText(xtxx, p.x, p.y);
context.fill();
break;
I have nothing to offer for your help but you will have my eternal gratitude

You can't create text particles using particles.js natively, but you can use tsParticles instead which support text particles.
This is how you can achieve it:
// keeping your function, it's fine
function PlayerSelector1() {
var word = ["player1", "player2", "player3", "player4", "player5", "player6"];
var random = word[Math.floor(Math.random() * word.length)];
return random;
}
// basic particles configuration, used for example
tsParticles.load("tsparticles", {
background: {
color: "#000"
},
particles: {
number: {
value: 10
},
move: {
enable: true
},
size: {
value: 30
},
shape: {
type: "text",
options: {
text: {
value: PlayerSelector1()
}
}
}
}
});
For using tsParticles you can read the instructions on the GitHub repository
This is your working demo on CodePen, using the config shown above: https://codepen.io/matteobruni/pen/oNymXmy?editors=0010
Every time you call the tsParticles.load function, the player will change.

Related

Phaser 3 - Check group collision with world bounds

In my scenario, i create a ship according to player's preferences. The ship consists of the flag and the hull.
An example view
PROBLEM-1
Ship is an Arcade.Group and i want to prevent this group from going outside the borders of the world.
create(){
// Create a group for ship
this.shipGroup = this.physics.add.group()
// Add hull to shipGroup
this.shipGroup.create(400, 500, "1021")
// Add flag to shipGroup
const mainFlag = this.shipGroup.create(400, 500, "FA1")
mainFlag.setOrigin(0.5, 0.8)
// Set collision property to true of every object in shipGroup
this.shipGroup.children.each((item: any) =>
item.setCollideWorldBounds(true)
)
}
update(t: number, dt: number){
if (this.cursor.up.isDown) {
this.shipGroup.setVelocity(...)
}
else {
this.shipGroup.setVelocity(0, 0)
}
}
With this approach every object in group calculated seperately. After hitting the world boundary, the position of the objects is distorted.
PROBLEM-2
To avoid this i tried another approach. I add bounding box to group. Instead of check collision for every object, i will only check collision for bounding box.
create(){
// Create a group for ship
this.shipGroup = this.physics.add.group()
// Add bounding box for shipGroup
this.shipBox = this.shipGroup.create(400, 500, "bbox")
this.shipBox.setCollideWorldBounds(true)
this.shipBox.body.onWorldBounds = true
// Add hull to shipGroup
this.shipGroup.create(400, 500, "1021")
// Add flag to shipGroup
const mainFlag = this.shipGroup.create(400, 500, "FA1")
mainFlag.setOrigin(0.5, 0.8)
/*this.shipGroup.children.each((item: any) =>
item.setCollideWorldBounds(true)
)*/
}
update(t: number, dt: number){
if (this.cursor.up.isDown && !this.shipBox.body.checkWorldBounds()) {
this.shipGroup.setVelocity(...)
}
else {
this.shipGroup.setVelocity(0, 0)
}
}
The problem is checkWorldBounds() returns false even if shipBox hits world boundaries. But collision for shipBox is work.
checkWorldBounds()
Description: Checks for collisions between this Body and the world
boundary and separates them.
Returns: True if this Body is colliding with the world boundary.
How can i implement collision for group and world boundary?
P.S. : phaser version is 3.55.2
There are a few ways to solve/work around this issue, I personally would just use only one image why one physics-body (hull and flag combined) and just move that single image/texture, and switch the image, when needed.
That said, if you need to use the separate images, the easy way is to use a phaser container. (link to the documentation)
create a container
add the images to the container
set the size for the container (default size is width=0 height=0)
create a physics body for the container
done
A short demo:
document.body.style = 'margin:0;';
var config = {
type: Phaser.AUTO,
width: 536,
height: 183,
physics: {
default: 'arcade',
arcade: {
gravity:{ y: 0 },
debug: true
}
},
scene: {
create
},
banner: false
};
function create () {
this.add.text(10,10, 'Ship with physics')
.setScale(1.5)
.setOrigin(0)
.setStyle({fontStyle: 'bold', fontFamily: 'Arial'});
let graphics = this.make.graphics();
graphics.fillStyle(0xffffff);
graphics.fillRect(0, 0, 10, 40);
graphics.generateTexture('ship', 10, 40);
graphics.fillStyle(0xff0000);
graphics.fillRect(0, 0, 30, 10);
graphics.generateTexture('flag', 30, 10);
graphics.generateTexture('flag2', 20, 6);
let hull = this.add.image(0, 0, 'ship')
let flag = this.add.image(0, -5, 'flag')
let flag2 = this.add.image(0, 10, 'flag2')
this.ship = this.add.container(100, 80, [ hull, flag, flag2]);
this.ship.setAngle(-90)
this.ship.setSize(40, 30)
this.physics.world.enable(this.ship);
this.ship.body.setVelocity(100, 0).setBounce(1, 1).setCollideWorldBounds(true);
}
new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
Info: this demo is based partly from this official example

Different SVG paths are part of segments

I created a SVG file which consists of 35 different paths (train tracks).
Now I want to split the paths/tracks into 16 segments so another SVG path (train) can move along it.
The goal in the end is that the user can determine which paths should be actived, i.e. the segments later on should be clickable by the user in sequence.
To test if it's working the train should randomly move along the tracks.
Currently I tried to assign the paths into segments like this:
const segments = {
1: { x: document.getElementById("track1"), y: document.getElementById("track2")},
2: { x: document.getElementById("track3"), y: document.getElementById("track4")},
3: { x: ocument.getElementById("track5"), y: document.getElementById("track6")},
...
};
This unfortunately is not working. I don't know why since I thought I could just assign the paths into the corresponding segments. Before the SVG file was a normally drawn PNG file in which the segments were manually assigned through their coordinates like this and it worked:
const segments = {
1: { x: 1534, y: 534 },
2: { x: 2278, y: 630 },
3: { x: 2488, y: 1179 },
...
};
I'm new to coding in general, so I unfortunately don't know what to look for. The solutions I found were not exactly suited for my problem.
Thank you in advance for helping me.
document.getElementById("track1") will just return a path element. If you need the coordinates of the start of the path, you would need to do something like:
1: { x: document.getElementById("track1").getPointAtLength(0).x,
y: document.getElementById("track1").getPointAtLength(0).y }

Control multiple fills and strokes of an SVG with a function

So I've built a map with several different colored lines. I chopped up the lines into a string of segments at each dot.
What I'm trying to do is use javascript to change the colors of the lines and eventually move to being able to change the dynamically with a feed.
I made a color chart that I'm trying to get the line segment object to find its color and change to the proper corresponding color. The dots pulsate the fill color with greensock properly but the lines are giving me trouble. I keep getting an object isn't a function error.
I've tried a few different ways to set up the formula but I'm stuck.
var colorSet = {
'#ff0000': '#ff6666',
'#008250': '#42a680',
'#a3238f': '#bd73b2',
'#0079c2': '#42a0db',
'#ff8c00': '#ffba66',
'#96c800': '#cae087',
'#a86000': '#c28f4e',
'#999999': '#cccccc',
'#ffe000': '#fff399'
}
var animateThis = function(obj) {
var getStroke = obj.getAttribute('stroke');
TweenLite.to(obj, 1.5, {
fill: "#bbbbbb",
yoyo: true,
repeat: -1
});
};
Here is my fiddle: https://jsfiddle.net/Spiderian/hzafm6vk/3/#&togetherjs=6e0qwPovaP
To color lines you need to use stroke, not fill. And on <line> not on <g>.
getStroke is not used in you code. (And there is no getAttribute on $ by the way. There is attr())
colorSet also unused, and I don't really understand what is it for. As all of lines and points in the jsfiddle you've provided are of the same color.
Don't really understand why there are two lines for each <g>.
But nevertheless here is what you need to do:
// change all line selectors from this
// const lsSIT0001 = $("#SIT0001");
// const lsSIT0002 = $("#SIT0002");
// ...
// to this
const lsSIT0001 = $("#SIT0001 line");
const lsSIT0002 = $("#SIT0002 line");
// ...
// because you need to change stroke color of `<line>`s, not `<g>`s
// split
// var itemsToAnimate = [ lsSIT0020, ..., lsSIT0001, SIR4947, ..., SIR4629 ]
// into
const linesToAnimate = [ lsSIT0020, ..., lsSIT0001 ]
const pointsToAnimate = [ SIR4947 , ..., SIR4629 ]
// run separate animations for lines and dots
const animatePoints = obj => TweenLite.to(obj, 1.5, { fill : "#ff0000", yoyo: true, repeat: -1 })
const animateLines = obj => TweenLite.to(obj, 1.5, { stroke: "#0000ff", yoyo: true, repeat: -1 })
linesToAnimate .forEach(animateLines )
pointsToAnimate.forEach(animatePoints)
Update:
To use colorSet you need to either
set style='stroke: some_color' on each <line> and then use it like this:
const style = obj.eq(i).attr('style')
// `i` is the index of a line inside <g> the color of which you want to get
TweenLite.to(obj, 1.5, { stroke: colorSet[style], ... })
In this case colorSet should look like
const colorSet = {
"stroke: #ff0000": '#ff6666',
...
"stroke: #ffe000": '#fff399',
}
or get computed styles with obj.get(i).computedStyleMap().get("stroke").toString()
In this case colorSet should look like
const colorSet = {
"rgb(255, 0, 0)": '#ff6666',
...
"rgb(255, 224, 0)": '#fff399',
}
But it's experimental technology. So probably don't :)
Or better yet - make a map not from color to color but from ids to color:
const colorSet = {
"#SIT0001": '#ff6666',
...
"#SIT0020": '#fff399',
}
Then you won't need to get colors from DOM.

Surrounding 3d sound effects using howler.js or another library?

I'm working on a project and I need to add 3d sounds effects, like the sound is continually moving around the listener effects. Is it possible to achieve that with howlerjs i see that with howler i'm able to play a sound from specific coordinates/orientation but how to achieve surrounding/ambisonics sounds ?
Or another library in JavaScript to achieve that?
Thanks for your help.
Half a year late, but yeah that's entirely possible in howler.js, haven't used it myself but judging from the docs you can just update the position. there's some more libraries that do it that I've found, check here how 3dage does exactly what you want:
https://codepen.io/naugtur/pen/QgmvOB?editors=1010
var world = IIIdage.World({
tickInterval: 200
})
var annoyingFly = IIIdage.Thing({
is: ['fly'],
sounds: {
'buzzing constantly': {
sound: 'buzz',
times: Infinity
}
},
reacts: [
{
// to: world.random.veryOften(),
to: world.time.once(),
with: 'buzzing constantly'
}
]
})
// scene should create and expose a default world or accept one
var scene = IIIdage.Scene({
title: 'Annoying fly',
library: {
sounds: {
'buzz': {
src: ['https://webaudiogaming.github.io/3dage/fly.mp3']
}
}
},
world: world,
things: [ // scene iterates all things and spawns them into the world. same can be done manually later on.
annoyingFly({
pos: [-1, -15, 0],
dir: [1, 0, 0],
v: 1
})
]
}).load().run()
setTimeout(function () {
scene.dev.trace(IIIdage.dev.preview.dom())
}, 500)
setInterval(function rotateVector() {
var angleRad = 0.15
var d=scene.things[0].attributes.dir
var x=d[0], y=d[1]
var cosAngle = Math.cos(angleRad), sinAngle = Math.sin(angleRad)
scene.things[0].attributes.dir = [x * cosAngle - y * sinAngle, y * cosAngle + x * sinAngle, 0]
}, 500)
window.scene = scene
There's still some others that do similar stuff:
https://www.npmjs.com/package/songbird-audio
https://www.npmjs.com/package/ambisonics
Hope this pushes you in the right direction if you still want help with it.

How to insert node into polyline link in gojs, preserving positions of points in links either side of the new node

I asked a question on StackOverflow (Seeking Javascript library for displaying and editing networks of nodes and edges) and was pointed at the gojs splice sample.
This has got me a long way, so thanks for the answer, but I have run into a brick wall trying to get the behaviour I want.
The app I am trying to create is to edit the borders on a map:
node = place where three or borders meet
link = segment of border between two nodes.
Hence, the nodes and links are unlabelled (nodes are just small circles, links are just polylines).
I have attempted to adapt the splice sample (https://gojs.net/extras/splicing.html) appropriately. The key features I need over and above what the sample does are:
choosing exactly where to position the new node on the link between the existing ones
preserving the shape of the polylines.
(The existing sample puts the new node equidistant between the existing ones and uses straight links.)
The user experience I have tried to create is this: first, you select the link, so it gets its usual adornments; then you shift-click on one of the adornments at a point on the polyline and that point becomes the new node.
I have sought to do this by overriding methods of the LinkReshapingTool using the extension mechanism described at https://gojs.net/latest/intro/extensions.html (rather than creating a subclass).
Whatever I have tried, though, I can't get the polylines to stay. By inspecting the diagram data model in the Chrome DevTools debugger after my code has run, it appears that it is correct (i.e. I can see the correct array of points in the links). However, when I then allow execution to continue the links do not display as expected (they are straight), and if I subsequently look at the data model then the multiple points have disappeared and each link just has a start and end.
I have tried various things, without success, for example:
deferring the splicing till after the tool has completed
passing the points into the modified links in different ways (array v list v string)
putting the processing into different overridden methods.
My current code is below. Please excuse crass stylistic faux pas - I am not an experienced JavaScript programmer.
<!DOCTYPE html> <!-- HTML5 document type -->
<!--
Adapted from splicing example from gojs.net
-->
<html>
<head>
<!-- use go-debug.js when developing and go.js when deploying -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/gojs/1.8.28/go-debug.js"></script>
</head>
<body>
<div id="myDiagramDiv"
style="width:400px; height:300px; background-color: #DAE4E4;"></div>
<script>
var $ = go.GraphObject.make;
// state variables to remember what to do after reshaping tool aborted
var doSpliceNode = false;
var doSpliceIntoLink = null;
var doSplicePoint = null;
var doSpliceIndex = -1;
// diagram
var myDiagram = $(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true
});
var tool = myDiagram.toolManager.linkReshapingTool;
// Override doMouseDown on linkreshapingtool. If user clicks on a handle with SHIFT pressed, want to insert
// a new node at that point rather than use the default behaviour to (further) reshape the link, and moreover
// want to retain the points in the link. I.e. turn one of the points in the link into a new node.
// (Existing gojs splicing example does not do this: it just puts a new node at the midpoint of the existing
// link, with no regard to the points along the link.)
tool.doMouseDown = function() {
console.log("mousedown at (" + this.Fp.M + "," + this.Fp.N + ")");
console.log(" on link from " + this.adornedLink.fromNode + " to " + this.adornedLink.toNode);
console.log(" with shift pressed? " + myDiagram.lastInput.shift);
var spliced = false;
if (myDiagram.lastInput.shift)
{
// work out which of the points on the link was clicked
var link = this.adornedLink;
var numpts = link.pointsCount;
var i;
var x = this.Fp.M; // ##TODO - by inspection in debugger this contains the X coord, but what's documented place to get this?
var y = this.Fp.N; // ##TODO - ditto for Y coord
for (i = 1; !spliced && (i < numpts - 1); i++)
{
if ((link.getPoint(i).x == x) && (link.getPoint(i).y == y))
{
console.log(" .. at point " + i);
// Store off what to do. (This used to be done inline - deferred to after as one of the things
// to try to make it work.)
doSpliceNode = true;
doSpliceIntoLink = link;
doSplicePoint = new go.Point(x, y);
doSpliceIndex = i;
spliced = true;
}
}
}
//if (!doSpliceNode)
{
console.log(".. call base class doMouseDown");
go.LinkReshapingTool.prototype.doMouseDown.call(tool);
}
}
// Override doMouseUp as well. If we had decided during mousedown to do the splice, then stop the tool now.
tool.doMouseUp = function()
{
// First call base class
go.LinkReshapingTool.prototype.doMouseUp.call(tool);
if (doSpliceNode)
{
// Doing splice - stop tool
console.log("STOP TOOL");
this.stopTool();
this.doDeactivate();
}
}
// Finally, override doStop to actually do the splice
tool.doStop = function() {
console.log("doStop");
// First call base class
go.LinkReshapingTool.prototype.doStop.call(tool);
if (doSpliceNode)
{
// now splice the node
console.log("splice node");
spliceNewNodeIntoLink2(doSpliceIntoLink, doSplicePoint, doSpliceIndex); // ##TODO make it respect points in existing link before and after
}
// Reset everything
doSpliceNode = false;
doSpliceIntoLink = null;
doSplicePoint = null;
doSpliceIndex = -1;
}
// Debug variable for inspecting later - not functional
var debugLastLink = null;
// Model, node and links for this application. Based heavily on https://gojs.net/temp/splicing.html and adapted as needed.
var myModel = $(go.GraphLinksModel);
myDiagram.nodeTemplate = $(go.Node,
"Auto",
new go.Binding("location", "location", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Circle", { width: 6, height: 6, strokeWidth: 0 }));
myDiagram.linkTemplate =
$(go.Link,
{
relinkableFrom: true, relinkableTo: true,
reshapable: true, resegmentable: true,
/* selectionAdornmentTemplate: ## COMMENT OUT - NOT NEEDED
$(go.Adornment,
$(go.Shape, { isPanelMain: true, stroke: "dodgerblue", strokeWidth: 2 }),
$(go.Shape, "PlusLine",
{
isActionable: true, // so that click works in an Adornment
width: 16, height: 16, stroke: "green", strokeWidth: 4, background: "transparent",
segmentOffset: new go.Point(8, 0),
click: function(e, shape) {
alert(e);
var link = shape.part.adornedPart;
var p0 = link.getPoint(0);
var p1 = link.getPoint(link.pointsCount - 1);
var pt = new go.Point((p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
// ##TODO - instead, find the position where the mouse was clicked and place the node there
// ... need to work out which segment of polyline this was in so as to calculate new lines
// ##TODO - handle drag of node so that it just affects segments of lines immediately into it, rather than
// blatting over top of them
// ##TODO - what is object e and its components
spliceNewNodeIntoLink(link, pt);
},
cursor: "pointer"
})
), */
toShortLength: 1
},
new go.Binding("points").makeTwoWay(), // Use the points information from the linkDataArray initializer
$(go.Shape, { strokeWidth: 2 })
);
/* function spliceNewNodeIntoLink(link, pt) { // ## original version no longer called
link.diagram.commit(function(diag) {
var tokey = link.toNode.key;
// add a new node
var newnodedata = { text: "on link", location: go.Point.stringify(pt) };
diag.model.addNodeData(newnodedata);
// and splice it in by changing the existing link to refer to the new node
diag.model.setToKeyForLinkData(link.data, newnodedata.key);
// and by adding a new link from the new node to the original "toNode"
diag.model.addLinkData({ from: newnodedata.key, to: tokey });
// optional: select the new node
diag.select(diag.findNodeForData(newnodedata));
}, "spliced in node on a link");
} */
// Utility function used in one attempt to get this to work. Initializers in nodeDataArray do it via an array of numbers,
// so try that here.
function toArray(nodelist)
{
var returnarray = new Array();
var i;
for (i = 0; i < nodelist.size; i++)
{
var pt = nodelist.elt(i);
returnarray.push(pt.x);
returnarray.push(pt.y);
}
return returnarray;
}
// Function to splice the new node into the link. Parameters are
// - link: the link to splice into
// - pt: the point within the link to turn into a node
// - index: index into existing polyline of that point
function spliceNewNodeIntoLink2(link, pt, index) {
link.diagram.commit(function(diag) {
var oldlinkpointslist = link.points;
var link1pointslist = new go.List(go.Point);
var link2pointslist = new go.List(go.Point);
var i;
// Create new points list, from "from" node to new node to be added
for (i = 0; i <= index; i++)
{
var point = new go.Point(link.getPoint(i).x, link.getPoint(i).y);
link1pointslist.add(point);
}
console.log(link1pointslist);
// .. and from new node to "to" node
for (i = index; i < link.pointsCount; i++)
{
var point = new go.Point(link.getPoint(i).x, link.getPoint(i).y);
link2pointslist.add(point);
}
console.log(link2pointslist);
var tokey = link.toNode.key;
// add a new node
var newnodedata = { text: "on link", location: go.Point.stringify(pt) };
diag.model.addNodeData(newnodedata);
// and splice it in by changing the existing link to refer to the new node
diag.model.setToKeyForLinkData(link.data, newnodedata.key);
// ** NEW CODE
// Code this was based on re-used the existing link, re-purposing it to go from "from" node
// to new node, so do the same, but give it a new points list.
link.points = link1pointslist; // ##TODO find out why this doesn't work
// ... actually it does, but something ditches the points later ...
// so maybe I need to move this code to after the tool has really finished operating
// by saving off the info and calling it in an override of the last tool method that
// gets called (perhaps not - did this and it didn't work)
debugLastLink = link; // ##TEMP
// and by adding a new link from the new node to the original "toNode"
// ** UPDATED to include the second new point list
diag.model.addLinkData({ from: newnodedata.key, to: tokey, points: toArray(link2pointslist) });
// optional: select the new node
diag.select(diag.findNodeForData(newnodedata));
}, "spliced in node on a link");
}
// not called at present
function maySpliceOutNode(node) {
return node.findLinksInto().count === 1 &&
node.findLinksOutOf().count === 1 &&
node.findLinksInto().first() !== node.findLinksOutOf().first();
}
// not called at present
function spliceNodeOutFromLinkChain(node) {
if (maySpliceOutNode(node)) {
node.diagram.commit(function(diag) {
var inlink = node.findLinksInto().first();
var outlink = node.findLinksOutOf().first();
// reconnect the existing incoming link
inlink.toNode = outlink.toNode;
// remove the node and the outgoing link
diag.removeParts([node, outlink], false);
// optional: select the original link
diag.select(inlink);
}, "spliced out node from chain of links");
}
}
// Initialize modeldi
myModel.nodeDataArray = [
{ key: "1" , "location": "30 30" },
{ key: "2" , "location": "130 30" },
{ key: "3" , "location": "30 130" }
];
myModel.linkDataArray = [
{ from: "1", to: "2", "points": [ 30,30, 70,20, 100,40, 130,30 ] },
{ from: "2", to: "3", "points": [ 130,30, 100,80, 70,90, 30,130 ] },
{ from: "3", to: "1", "points": [ 30,130, 20,100, 40,70, 30,30 ] }
];
myDiagram.model = myModel;
</script>
</body>
</html>
Some suggestions:
Call Link.findClosestSegment to find the segment where the user clicked to insert a node.
Don't splice in the new node in an override of Tool.doStop, because that will be called even if the user hit the Escape key to cancel the tool's operation. Do it in either doMouseDown or doMouseUp, depending on the behavior that you want. But doStop is a reasonable time to clean up the tool's state.
I think it should work if you add the new Node and a new Link, connect them together properly, make sure the Node is at the right location, and only then set Link.points explicitly. The TwoWay Binding on Link.points will save the points to the model.
The problem that you are encountering is that when you create a new Node it takes time to be measured and arranged and positioned. Any one of those activities will invalidate the routes of all connected links. And obviously connecting a link with a node will invalidate that link's route. So you have to make sure everything is done in the right order.

Categories