Making sprites equally spaced while moving around a circle - javascript

I am trying to make a number of circles rotate around a point. I have gotten the spacing to work properly, but now I need some sort of script that can calculate how many circles are rotating, and be able to add more circles while equally spacing all of them. Here is my current code:
let petals = [
{
name: "basic-common",
damage: 2,
health: 5,
reloadtime: 3
}
]
petals.forEach(el => {
const petal = add([
sprite(el.name),
pos(center()),
area(),
rotate(0),
origin("center"),
// origin("right"),
health(el.health),
"petal",
]);
petal.onUpdate(() => {
petal.angle += 3
})
});
The point that the circles has to rotate must be able to change too, so the code can not only use a single point.

To add the functionality you are asking for, you can add a variable to keep track of the number of circles, and update the code that calculates the spacing between the circles to dynamically adjust based on the number of circles. Here's an example:
let petals = [{
name: "basic-common",
damage: 2,
health: 5,
reloadtime: 3
}];
let numCircles = petals.length;
let angleStep = 360 / numCircles;
petals.forEach((el, i) => {
const petal = add([
sprite(el.name),
pos(center()),
area(),
rotate(angleStep * i),
origin("center"),
// origin("right"),
health(el.health),
"petal",
]);
petal.onUpdate(() => {
petal.angle += 3
})
});
This code uses the angleStep variable to calculate the amount each circle should be rotated by. The angleStep is calculated by dividing 360 (the number of degrees in a full circle) by the number of circles. Then, for each circle in the petals array, the rotate property is set to angleStep * i, where i is the index of the current circle in the array.
To add more circles to the rotation, you can simply add more objects to the petals array and the code will automatically adjust to include the new circles in the rotation.

Related

Calculating part of area inside zone. Fabric.js/Canvas

I have an area (in this case, the Kitchen area with yellow borders), inside this area there are other shapes (numbered 1 and 2 light blue color) that divide the kitchen area into several parts (A, B, C). I need to calculate separately the area of each Green part.
I use a js worker to calculate the area of the blue and green zone(in total). But I need to somehow calculate these divided green zones separately.
To calculate area I use getImageData() where I get pixels of the entire kitchen area. Then I loop the pixels and filter. Depending on the color of the pixel, I add it to the area result of either the blue or green zone.
Are there ready-made solutions in Fabric.js or Canvas for counting a part of a zone in another zone? If not, do you have any ideas how to implement it?
Here is a small piece of code with a pixel cycle:
calculateCoverage: function (options) {
options.oversampling = options.oversampling || 1;
var result = {},
pixel = new app.Color(),
oversamplingArea = Math.pow(options.oversampling, 2),
pixelCoverage, value,
i;
for (i = 0; options.imageData && i < options.imageData.data.length; i += 4) {
pixel.x = options.imageData.data[i];
pixel.y = options.imageData.data[i + 1];
pixel.z = options.imageData.data[i + 2];
pixel.a = options.imageData.data[i + 3];
// Apply binary filtering to the pixel value.
pixel.filter(app.Color.BinaryFilter).filter(app.Color.BinaryFilterAlpha);
// Ignore low alpha pixels.
if (!pixel.a) {
continue;
}
pixelCoverage = this.getPixelCoverageType(pixel, options.types);
value = pixel.a / 255 / oversamplingArea;
if (!result[pixelCoverage]) {
result[pixelCoverage] = 0;
}
// Iterate pixel coverage data.
result[pixelCoverage] += value;
}
return result;
}

Get the row and column in a canvas

I am making a minimap for players to see each other in the world. I want to add a sector indicator which tells the individual player which sector they are in. The world is a 5000x5000 matrix.
Take the scale of the world and divide by the rows and columns to get the scale. Then divide the players x, y by the scale to get the sectors. I made COLUMNS and ROWS arrays in case you want to change to naming system. This method returns a string.
function getSector(x, y) {
// The dimensions of the map
const WIDTH = 5000, HEIGHT = 5000;
// The sectors row and column labels
const COLUMNS = ['1','2','3','4','5'];
const ROWS = ['A','B','C','D','E'];
// Scale map to number of sectors
const colScale = Math.floor(WIDTH / COLUMNS.length);
const rowScale = Math.floor(HEIGHT / ROWS.length);
// Convert xy coordinates to sectors
const col = Math.floor(x / colScale);
const row = Math.floor(y / rowScale);
// Returns string of current sector
return `${ROWS[row]}${COLUMNS[col]}`;
}
console.log(getSector(0, 0))
console.log(getSector(4999, 4999))

Random Transform of 3d dice- get dice throw result

Code pen (available online, have not made any changes here)
https://codepen.io/SteveJRobertson/pen/zxEwrK
Javascript
var cube = document.getElementById('cube');
var min = 1;
var max = 24;
cube.onclick = function() {
var xRand = getRandom(max, min);
var yRand = getRandom(max, min);
cube.style.webkitTransform = 'rotateX('+xRand+'deg)
rotateY('+yRand+'deg)';
cube.style.transform = 'rotateX('+xRand+'deg)
rotateY('+yRand+'deg)';
}
function getRandom(max, min) {
return (Math.floor(Math.random() * (max-min)) + min) *
90;
}
What I want-
after the dice finishes transition, it finishes with a face facing you. Is there a way to get which face this is?(i am considering this face as the output of the dice throw)
What I did-
I could not find the solution. Do after the dice finishes transition, I force it to another transition I want so that it finishes where I want it to. (
#cube.show-front {
transform: translateZ(-100px) rotateY( 0deg);
}
will make the cube land on its front side
You could have some complex matrix maths to figure that out but a quick look at how things are done can give you a simple solution.
The first thing to make sure to note is the initial position of all the faces. The faces are not positioned like on a real dice (the sum of opposite faces would equal 7, e.g. 1 opposed to 6).
Another thing is that the rotation only happens on 2 axes, each by a multiple of 90 degrees (a quarter of turn). And 4 quarters of turns (i.e. 1 full turn) is equivalent to no turn at all, so it is a repeating pattern and we can work with modulos.
Now for the actual rotation, I find it easier to work with fixed origins (not moving with the object), which means you need to read the CSS transform values from right to left.
First you are rotating the cube around the Y axis (front face moving towards the left / right) a certain number of times.
Once that is done you are rotating the cube around the X axis (front face moving up /down).
If you try to picture that you might notice that no matter what we do during the first step the top face will stay at the top (5 here) and the bottom one at the bottom (6 here). Which means with the second and last rotation we can easily tell if the cube finished on 5, 6, or a different number.
For the other cases this is just a matter of picking the correct value based on the first Y rotation (while not forgetting that a 180 degrees rotation on the X axis will show the opposite face).
// modulo not giving negative results - see https://stackoverflow.com/q/4467539/1336843
function mod(n, m) {
return ((n % m) + m) % m;
}
function getResult(rotX, rotY) {
let countX = mod(rotX / 90, 4);
if (countX === 1) {
// Bottom face
return 6;
}
if (countX === 3) {
// Top face
return 5;
}
// We add countX here to correctly offset in case it is a 180 degrees rotation
// It can be 0 (no rotation) or 2 (180 degrees)
let countY = mod(rotY / 90 + countX, 4);
// Faces order
return [1, 4, 2, 3][countY];
}
Fork of the pen logging the result to the console: codepen
You will notice that this shuffling method will not give each result an equal probability. The top and bottom faces (5 and 6) will be more likely to appear (1 time out of 4 each, while all the other faces will appear 1 time out of 8).

How do I get a one-sided gradient effect for createJS beginLinearGradientStroke?

I'm working on a gradient stroke for a "loading circle" using createJS. However, I only need the gradient effect to be applied on one "joining point" of the two colors, and not apply it on the other joining point.
What I did was this, but it's only giving me a normal gradient effect:
var rd = 64;
timerCount.graphics.setStrokeStyle(8)
/* yellow ,red*/
.beginLinearGradientStroke( ["#F7CC00","#FE1D1E"] ,[0,1] ,0,rd*0.5 ,0,-rd );
Please refer to the image below:
Anyone knows how I can do this?
Here's my code in JSFiddle:
https://jsfiddle.net/flamedenise/gg9aabug/18/
Thank you and Happy New Year ahead!
You are not looking for a radial gradient, but rather a conical gradient (or angle gradient in Photoshop), which Canvas does not support directly. I did a quick search on Angle Gradients, and found a few ideas that might help:
http://www.nixtu.info/2010/08/html5-canvas-gradients-angular-gradient.html
https://gist.github.com/akm2/3721702
Angle gradient in canvas
Best of luck.
I have managed to create a workaround to achieve this! Since beginLinearGradientStroke() only creates a "normal" gradient, I figured out overlaying it with another gradient (with transparent as the second color) would work.
What I did was create the first circle with two colors that appear as "solid" (by setting the ratios and x and y positions accordingly) and then overlaid it with another gradient circle - with one color the combination of the first two colors, and the other one transparent.
Here's the JSFiddle showing the final outcome:
https://jsfiddle.net/flamedenise/n9no9Lgw/
var rd = 64;/*radius*/
var circles = {};
var ic = [
/*0*/{ a:"#FEC331" ,b:"#FB1E24" ,r1:0.5 ,r2:0.5 ,x0:0 ,y0:rd*0.3 ,x1:0 ,y1:-rd},
/*1*/{ a:"#EA6F2B" ,b:"transparent" ,r1:0 ,r2:1 ,x0:-rd ,y0:0 ,x1:rd ,y1:0 }
];
var circleX = [ 0.5 ,0.75 ];
var circleY = [ 0.7 ,0.7 ];
for(var i=0; i<2; i++){
circles[l][i] = new createjs.Shape();
circles[l][i].graphics.setStrokeStyle(8)
.beginLinearGradientStroke( [ ic[k].a ,ic[k].b ], [ic[k].r1, ic[k].r2], ic[k].x0,ic[k].y0 ,ic[k].x1,ic[k].y1 );
circles[l][i].rotation = -90;
circles[l][i].x = ww*circleX[l];
circles[l][i].y = wh*circleY[l];
var arcCommand = circles[l][i].graphics.arc(0, -20, rd, 600 * Math.PI, 0).command;
if (run == 1) {
createjs.Tween.get(arcCommand)
.to({
endAngle: (360 * Math.PI / 180)
}, time * 1000);
}
circleStage.addChild(circles[l][i]);
}/*END for loop*/

D3.js Convex Hull With 2 Data Points

The API for Hull Geom states: "Assumes the vertices array is greater than three in length. If vertices is of length <= 3, returns []." (https://github.com/mbostock/d3/wiki/Hull-Geom)
I need to draw convex hulls around 2 nodes. I am using the force layout, so the convex hull needs to be dynamic in that it moves around the nodes if I click a node and drag it around. My code is currently based off of this example: http://bl.ocks.org/donaldh/2920551
For context, this is what I am trying to draw a convex hull around:
Here it works when there are 3 nodes:
Here is what I am trying to draw a convex hull around (doesn't work with the code from the example above because Hull Geom will only take arrays with 3+ vertices):
I understand the traditional use of a convex hull would never involve only two points, but I have tried drawing ellipses, rectangles, etc around the 2 nodes and it doesn't look anywhere near as good as the 3 nodes does.
I understand that Hull Geom ultimately just spits out a string that is used for pathing, so I could probably write a modified version of Hull Geom for 2 nodes.
Any suggestions on how to write a modified Hull Geom for 2 nodes or any general advice to solve my problem is really appreciated.
Basically, you need to at least one fake point very close to the line to achieve the desired result. This can be achieved in the groupPath function.
For d of length 2 you can create a temporary array and attach it to the result of the map function as follows:
var groupPath = function(d) {
var fakePoints = [];
if (d.values.length == 2)
{
//[dx, dy] is the direction vector of the line
var dx = d.values[1].x - d.values[0].x;
var dy = d.values[1].y - d.values[0].y;
//scale it to something very small
dx *= 0.00001; dy *= 0.00001;
//orthogonal directions to a 2D vector [dx, dy] are [dy, -dx] and [-dy, dx]
//take the midpoint [mx, my] of the line and translate it in both directions
var mx = (d.values[0].x + d.values[1].x) * 0.5;
var my = (d.values[0].y + d.values[1].y) * 0.5;
fakePoints = [ [mx + dy, my - dx],
[mx - dy, my + dx]];
//the two additional points will be sufficient for the convex hull algorithm
}
//do not forget to append the fakePoints to the input data
return "M" +
d3.geom.hull(d.values.map(function(i) { return [i.x, i.y]; })
.concat(fakePoints))
.join("L")
+ "Z";
}
Here a fiddle with a working example.
Isolin has a great solution, but it can be simplified. Instead of making the virtual point on the line at the midpoint, it's enough to add the fake points basically on top of an existing point...offset by an imperceptible amount. I adapted Isolin's code to also handle cases of groups with 1 or 2 nodes.
var groupPath = function(d) {
var fakePoints = [];
if (d.length == 1 || d.length == 2) {
fakePoints = [ [d[0].x + 0.001, d[0].y - 0.001],
[d[0].x - 0.001, d[0].y + 0.001],
[d[0].x - 0.001, d[0].y + 0.001]]; }
return "M" + d3.geom.hull(d.map(function(i) { return [i.x, i.y]; })
.concat(fakePoints)) //do not forget to append the fakePoints to the group data
.join("L") + "Z";
};

Categories

Resources