Simultaneous Rotate and Translate not working as expected in javafx - graphics

I have built the following "system" from Circles and a Line.
I am trying to implement just following two transitions in the system.
When the Green Circle is dragged, both the Green and Blue circle should rotate about the Red center, in the direction of drag.
When the Red center is dragged, the whole system should get dragged with it accordingly(like a monolith).
I have tried to implement it but facing a problem.
Both the transitions are working fine when done alone.
i.e. When the application starts, and you try to drag Green circle, whole system perfectly rotates about Red circle. Similarly, on startup, when Red circle is dragged, everything gets dragged fine.
But
When either of these drags are tried after the other, shapes flow away from each other !!
Please suggest what may be causing this behavior.Any other way to implement the transitions is also welcomed, as I am still new to Animations in JavaFx and this obviously is not the best code to solve the problem.
following is my code:
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
public class SpindleAndWheel extends Application
{
Circle circle;
Circle oppositeCircle;
Circle pivot;
Line spindle;
Rotate rotateCircle, rotateOppositeCircle;
Translate translateCircle, translateOppositeCircle;
Translate translateCircleBack, translateOppositeCircleBack;
Translate dragTranslateCircle, dragTranslatePivot, dragTranslateOppositeCircle, dragTranslateSpindle;
double dragInitX, dragInitY;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
double dragTranslateCircleBackupX,dragTranslatePivotBackupX, dragTranslateOppositeCircleBackupX, dragTranslateSpindleBackupX;
double dragTranslateCircleBackupY,dragTranslatePivotBackupY, dragTranslateOppositeCircleBackupY, dragTranslateSpindleBackupY;
#Override
public void start(Stage primaryStage) throws Exception
{
Stage stage = new Stage();
stage.setMinHeight(500);
stage.setMinWidth(500);
Pane root = new Pane();
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Animations **********/
rotateCircle = new Rotate(0, 0, 0);
translateCircle = new Translate(0, 0);
translateCircleBack = new Translate(0, 0);
dragTranslateCircle = new Translate(0, 0);
rotateOppositeCircle = new Rotate(0, 0, 0);
translateOppositeCircle = new Translate(0, 0);
translateOppositeCircleBack = new Translate(0, 0);
dragTranslateOppositeCircle = new Translate(0, 0);
dragTranslatePivot = new Translate(0, 0);
dragTranslateSpindle = new Translate(0, 0);
/****************************************************/
/**************** Adding Animations **************/
circle.getTransforms().addAll(translateCircle, rotateCircle, translateCircleBack, dragTranslateCircle);
oppositeCircle.getTransforms().addAll(translateOppositeCircle, rotateOppositeCircle, translateOppositeCircleBack, dragTranslateOppositeCircle);
pivot.getTransforms().addAll(dragTranslatePivot);
spindle.getTransforms().addAll(dragTranslateSpindle);
/****************************************************/
Scene scene = new Scene(root);
stage.setScene(scene);
root.getChildren().addAll(circle,oppositeCircle,pivot,spindle);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitX = event.getSceneX();
dragInitY = event.getSceneY();
dragInitTheta = angleOfRotation + dragInitTheta;
double initialSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
initialSlope = Math.atan((dragInitY - (pointOfRotationX)) / (dragInitX - (pointOfRotationY)));
theta1 = Math.toDegrees(initialSlope);
if (dragInitX < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double finalSlope;
double pointOfRotationX,pointOfRotationY;
pointOfRotationY = pivot.getCenterY() + dragTranslatePivot.getY();
pointOfRotationX = pivot.getCenterX() + dragTranslatePivot.getX();
finalSlope = Math.atan((event.getSceneY() - (pointOfRotationX)) / (event.getSceneX() - (pointOfRotationY)));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
translateCircle.setX(pointOfRotationX);
translateCircle.setY(pointOfRotationY);
rotateCircle.setAngle(angleOfRotation + dragInitTheta);
translateCircleBack.setX(-pointOfRotationX);
translateCircleBack.setY(-pointOfRotationY);
translateOppositeCircle.setX(pointOfRotationX);
translateOppositeCircle.setY(pointOfRotationY);
rotateOppositeCircle.setAngle(angleOfRotation + dragInitTheta);
translateOppositeCircleBack.setX(-pointOfRotationX);
translateOppositeCircleBack.setY(-pointOfRotationY);
spindle.setRotate(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateCircleBackupX = dragTranslateCircle.getX();
dragTranslateCircleBackupY = dragTranslateCircle.getY();
dragTranslatePivotBackupX = dragTranslatePivot.getX();
dragTranslatePivotBackupY = dragTranslatePivot.getY();
dragTranslateOppositeCircleBackupX = dragTranslateOppositeCircle.getX();
dragTranslateOppositeCircleBackupY = dragTranslateOppositeCircle.getY();
dragTranslateSpindleBackupX = dragTranslateSpindle.getX();
dragTranslateSpindleBackupY = dragTranslateSpindle.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
dragTranslateCircle.setX(dragTranslateCircleBackupX + systemDragOffsetX);
dragTranslateCircle.setY(dragTranslateCircleBackupY + systemDragOffsetY);
dragTranslatePivot.setX(dragTranslatePivotBackupX+ systemDragOffsetX);
dragTranslatePivot.setY(dragTranslatePivotBackupY+ systemDragOffsetY);
dragTranslateOppositeCircle.setX(dragTranslateOppositeCircleBackupX+ systemDragOffsetX);
dragTranslateOppositeCircle.setY(dragTranslateOppositeCircleBackupY+ systemDragOffsetY);
dragTranslateSpindle.setX(dragTranslateSpindleBackupX+ systemDragOffsetX);
dragTranslateSpindle.setY(dragTranslateSpindleBackupY + systemDragOffsetY);
});
/********************************************/
}
public static void main(String[] args)
{
launch(args);
}
}

Nice approach, but as you have already found out, it has a main drawback: after applying one transformation, the other is not well performed. The reason for that is on the way you define the transformations. Besides, assigning so many transformations leads to a complex system, hard to mantain.
My proposal is far more simple: just wrap all your shapes in one Group, and only transform this group, translating it when you drag the pivot, or rotating it over the pivot, when you drag the circle. Note that you can use here setPivotX() and setPivotY() to indicate the actual point of rotation.
As you can see, you will need just two transformations, and more important, you won't have any side effect of applying in any order any of them.
EDIT
As the OP correctly states, there was a mistake in the rotation calculations. For the sake of completeness, I've edited my answer to show the correct code.
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1,theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX,dragPivotInitY,systemDragOffsetX,systemDragOffsetY;
#Override
public void start(Stage stage){
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle,oppositeCircle,pivot,spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup,rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root,500,500);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
double pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}

José Pereda, Great Answer!! Way better approach.Learned MANY new thing from it.
Just need to make a simple correction. During the calculation of slope of point of drag, you also need to consider the offset due to (translateGroup.getY(),translateGroup.getX()) in the (pivot.getCenterY(),pivot.getCenterX()).
Following is José's Code with the above mentioned corrections.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.transform.Rotate;
import javafx.scene.transform.Translate;
import javafx.stage.Stage;
import javafx.scene.Group;
public class SpindleAndWheelGroup extends Application
{
private Circle circle;
private Circle oppositeCircle;
private Circle pivot;
private Line spindle;
private Group group;
private Rotate rotateGroup;
double dragInitTheta;
double theta1, theta2;
double angleOfRotation;
private Translate translateGroup;
private double dragTranslateGroupBackupX, dragTranslateGroupBackupY;
private double dragPivotInitX, dragPivotInitY, systemDragOffsetX, systemDragOffsetY;
double pointOfRotationX,pointOfRotationY;
#Override
public void start(Stage stage)
{
circle = new Circle(150, 150, 30);
oppositeCircle = new Circle(350, 350, 30);
pivot = new Circle(250, 250, 5);
spindle = new Line(150, 150, 350, 350);
group = new Group(circle, oppositeCircle, pivot, spindle);
/**************** Initializing Shapes **********/
circle.setFill(Color.GREEN.deriveColor(1, 1, 1, 0.35));
circle.setStroke(Color.GREEN);
oppositeCircle.setFill(Color.BLUE.deriveColor(1, 1, 1, 0.35));
oppositeCircle.setStroke(Color.BLUE);
pivot.setFill(Color.RED.deriveColor(1, 1, 1, 0.35));
pivot.setStroke(Color.RED);
spindle.setStrokeWidth(3);
spindle.setStroke(Color.BLACK.deriveColor(1, 1, 1, 0.35));
/****************************************************/
/**************** Initializing Transforms **********/
rotateGroup = new Rotate(0, 0, 0);
translateGroup = new Translate(0, 0);
/****************************************************/
/**************** Adding Transforms **************/
group.getTransforms().addAll(translateGroup, rotateGroup);
/****************************************************/
Pane root = new Pane(group);
Scene scene = new Scene(root, 800, 700);
stage.setScene(scene);
stage.show();
/** Get angle of point of click with
* point of rotation, before drag begins **/
circle.setOnMousePressed(event -> {
dragInitTheta = angleOfRotation + dragInitTheta;
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double initialSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta1 = Math.toDegrees(initialSlope);
if (event.getSceneX() < pointOfRotationX)
theta1 = (360 + theta1) % 360;
else
theta1 = 180 + theta1;
});
/********************************************/
/** Get angle of point of drags with
* point of rotation, when the drag is on **/
circle.setOnMouseDragged(event -> {
pointOfRotationY = pivot.getCenterY() + translateGroup.getY();
pointOfRotationX = pivot.getCenterX() + translateGroup.getX();
double finalSlope = Math.atan((event.getSceneY() - pointOfRotationY) / (event.getSceneX() - pointOfRotationX));
theta2 = Math.toDegrees(finalSlope);
if (event.getSceneX() < pointOfRotationX)
theta2 = (360 + theta2) % 360;
else
theta2 = 180 + theta2;
angleOfRotation = theta2 - theta1;
rotateGroup.setPivotX(pivot.getCenterX());
rotateGroup.setPivotY(pivot.getCenterY());
rotateGroup.setAngle(angleOfRotation + dragInitTheta);
});
/********************************************/
/** Relocate the whole system when the point of
* rotation is dragged **/
pivot.setOnMousePressed(event -> {
dragPivotInitX = event.getSceneX();
dragPivotInitY = event.getSceneY();
dragTranslateGroupBackupX = translateGroup.getX();
dragTranslateGroupBackupY = translateGroup.getY();
});
pivot.setOnMouseDragged(event -> {
systemDragOffsetX = event.getSceneX() - dragPivotInitX;
systemDragOffsetY = event.getSceneY() - dragPivotInitY;
translateGroup.setX(dragTranslateGroupBackupX + systemDragOffsetX);
translateGroup.setY(dragTranslateGroupBackupY + systemDragOffsetY);
});
/********************************************/
}
}

Related

Processing: how to make box() appear solid (non-transparent) in 3d mode

I'm trying to create layers of 3d boxes in Processing. I want them to appear solid, so that you can't see the boxes "behind" other boxes, but the way they're displaying makes them seem transparent; you can see the stroke of boxes behind other boxes. How do I make them appear solid?
// number of boxes
int numBox = 300;
// width of each box
int boxWidth = 30;
// number of boxes per row
float numPerRow;
void setup() {
size(800, 800, P3D);
pixelDensity(1);
colorMode(HSB, 360, 100, 100, 100);
background(40, 6, 85);
stroke(216, 0, 55);
smooth(4);
fill(0, 0, 90, 100);
numPerRow = width / boxWidth;
}
void draw() {
background(40, 6, 85);
translate((boxWidth / 2), 100);
rotateX(-PI/6);
rotateY(PI/8);
for (int i = 0; i < numBox; i++) {
drawBox(i);
if (i == numBox - 1) {
noLoop();
}
}
}
void drawBox(int i) {
if ((i % 2) == 0) {
pushMatrix();
translate(((boxWidth / 2) * i) % width, 20 * floor(i / (2 * numPerRow)));
translate(0, -((i % 30) / 2));
box(boxWidth, i % 30, boxWidth);
popMatrix();
};
}
Close-up of how the boxes are being displayed:
The issue is that the boxes are intersecting and the strokes of these intersecting boxes are what give the appearance of "see through".
I'm noticing you are using x and y translation, but not z.
If you don't plan to increase x, y spacing to avoid intersections, you can easily offset rows on the z axis so rows of boxes appear in front of each other.
Here's a slightly modified version of your code illustrating this idea:
// number of boxes
int numBox = 300;
// width of each box
int boxWidth = 30;
// number of boxes per row
float numPerRow;
void setup() {
size(800, 800, P3D);
pixelDensity(1);
colorMode(HSB, 360, 100, 100, 100);
background(40, 6, 85);
stroke(216, 0, 55);
smooth(4);
fill(0, 0, 90, 100);
numPerRow = width / boxWidth;
}
void draw() {
background(40, 6, 85);
translate((boxWidth / 2), 100);
if(mousePressed){
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, PI, -PI));
}else{
rotateX(-PI/6);
rotateY(PI/8);
}
for (int i = 0; i < numBox; i++) {
drawBox(i);
//if (i == numBox - 1) {
// noLoop();
//}
}
}
void drawBox(int i) {
if ((i % 2) == 0) {
pushMatrix();
float x = ((boxWidth / 2) * i) % width;
float y = 20 * floor(i / (2 * numPerRow));
float z = y * 1.5;
translate(x, y, z);
translate(0, -((i % 30) / 2));
box(boxWidth, i % 30, boxWidth);
popMatrix();
};
}
(Click and drag to rotate and observe the z offset.
Feel free to make z as interestersting as you need it it.
Nice composition and colours!
(framing (window size) could use some iteration/tweaking, but I'm guessing this is WIP))

Moving circles - like bouncing

Just another question! I'm trying to make the circle bounce around, but it's not working I even tried the most basic way, of just adding a value (from a 'step' int) to the circle x, but it's not working. What's the approach I should follow?
I know it's a basic question, but I'm knew to this :)
float time;
PFont font1;
/*float posX, posY, velX, velY, raio;
int dirX = 1;
int dirY = -1;*/
int passo = 2;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
background (#F6C4C7);
ellipseMode(RADIUS);
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
/*void move() {
posY+=velY*dirY;
if (posY>height-raio || posY<raio)
dirY*=-1;
posX+=velX*dirX;
if (posX>width-raio || posX<raio)
dirX*=-1;
}*/
void draw () {
smooth();
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c1, c2);
} else
desenhar_grad(150 + coluna * 150, 200 + linha * 150, 30, c4, c3);
}
}
}
} ```
Also, should I create a class for the circles in order to optimize the code?
Thank you!
I see your attempt with using the move() function (and related variables).
Again, close, but there are a few gotchas:
the values used in move() should be initialised: otherwise they'll default to 0 and any number multiplied by 0 is 0 which will result in no movement at all
once you have computed the correct posX, posY you could use those to translate() everything (i.e. the gradients): once everything is translated the 150, 200 offsets could be removed (and used as posX, posY initial values)
it's unclear with the "pivot" of the 3x3 gradient grid should be at the centre or the top left corner of the grid. Let's start with the simpler top left option. This can easily be changed later to centre simply by adding had the grid size to posX and posY
Here's a modified version of your sketch using the notes above:
float time;
// initialise movement variables
float posX = 150, posY = 200, velX = 1, velY = 1;
int raio = 30;
int dirX = 1;
int dirY = -1;
color c1 = color (253, 196, 80, 40);
color c2 = color(254, 127, 168, 40);
color c3 = color (53, 63, 114, 80);
color c4 = color (206, 186, 221, 80);
void setup() {
size(600, 800);
smooth();
ellipseMode(RADIUS);
smooth();
noStroke();
time = 17;
}
//make gradient
void desenhar_grad(float posX, float posY, int raio, color color1, color color2) {
pushStyle();
noStroke();
for (int r = raio; r > 0; r--) {
int tom = lerpColor(color1, color2, map(r, 0, raio, 0.0, 1.0)); // os últimos dois valores são as cores. o primeiro é o centro, o segundo é o exterior
fill(tom);
circle(posX, posY, r * 2);
}
popStyle();
}
void move() {
posY += velY * dirY;
if (posY > height - raio || posY < raio)
dirY *= -1;
posX += velX * dirX;
if (posX > width - raio || posX < raio)
dirX *= -1;
// for testing only:
println("posX",posX, "width", width, "posY", posY, "height", height);
}
void draw () {
if(!mousePressed) background (#F6C4C7);
// update posX, posY taking sketch borders into account
move();
// translate everything to the updated position
translate(posX, posY);
for (int linha = 0; linha < 3; linha++) {
for (int coluna = 0; coluna < 3; coluna++) {
if (time <= 19) {
desenhar_grad(coluna * 150, linha * 150, raio, c1, c2);
} else
desenhar_grad(coluna * 150, linha * 150, raio, c4, c3);
}
}
}
I've removed unused variables for clarity and added a few comments.
There are still a few confusing, perhaps unrelated items:
should the screen be cleared or should the grid leave trails ? (for now you can leave trails by holding the mouse pressed, but you can easily choose when to call background() based on the look you're going for)
how should the time variable be updated ? Currently it's set to 17 in setup() and doesn't change making the if/else condition inside the nested for loops redundant. Perhaps you meant to update in draw() based on some conditions ?
should the grid move as a whole or should each gradient move on its own ? my assumption is you're trying move the grid altogether however if you want to move each gradient on its own bare in mind you will need to use an array for each variable used in move() so it can be updated independently for each gradient (e.g. float[] posX, posY, velX, velY).)
Side note: If the movement is this simple you could get away with pos and
vel variables and not use dir variables:
void move() {
posY += velY;
if (posY > height - raio || posY < raio)
velY *= -1;
posX += velX;
if (posX > width - raio || posX < raio)
velY *= -1;
}
Manually updating each x,y variable is a great way to learn.
At a later date you might find PVector useful for movement.

How to center this grid of squares?

I am trying to simply produce a grid of 5 rotated rectangles. But the grid will not come out centered. Can anyone help me out?
int margin = 150; //padding to sides and top/bottom
int rectH = 60; // height of rectangle
int rectW = 20; // width of rectangle
int n_rectangles = 5; // 5 rectangles to draw
size(800,800);
for (int x = margin+rectW; x <= width - margin; x += (width-2*(margin+rectW))/n_rectangles) {
for (int y = margin+rectH; y <= height - margin; y += (height-2*(margin+rectH))/n_rectangles) {
fill(255);
//now rotate matrix 45 degrees
pushMatrix();
translate(x, y);
rotate(radians(45));
// draw rectangle at x,y point
rect(0, 0, rectW, rectH);
popMatrix();
}
}
I recommend to draw single "centered" rectangles, the origin of the rectangle is (-rectW/2, -rectH/2):
rect(-rectW/2, -rectH/2, rectW, rectH);
Calculate the distance of the first rectangle center tor the last rectangle center, for row and column:
int size_x = margin * (n_rectangles-1);
int size_y = margin * (n_rectangles-1);
Translate to the center of the screen (width/2, height/2),
to the position of the upper left rectangle (-size_x/2, -size_y/2)
and finally each rectangle to its position (i*margin, j*margin):
translate(width/2 - size_x/2 + i*margin, height/2 - size_y/2 + j*margin);
See the final code:
int margin = 150; //padding to sides and top/bottom
int rectH = 60; // height of rectangle
int rectW = 20; // width of rectangle
int n_rectangles = 5; // 5 rectangles to draw
size(800,800);
int size_x = margin * (n_rectangles-1);
int size_y = margin * (n_rectangles-1);
for (int i = 0; i < n_rectangles; ++i ) {
for (int j = 0; j < n_rectangles; ++j ) {
fill(255);
pushMatrix();
translate(width/2 - size_x/2 + i*margin, height/2 -size_y/2 + j*margin);
rotate(radians(45));
rect(-rectW/2, -rectH/2, rectW, rectH);
popMatrix();
}
}

svg text wrapping issues

I am attempting to wrap called data into two lines of text on an svg. Right now it is displaying the text over six lines. Can anyone help with this.
function wrap(text, width, content) {
text.each(function () {
var text = d3.select(this),
words = content.split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1, // ems
x = text.attr("x"),
y = text.attr("y"),
dy = 0, //parseFloat(text.attr("dy")),
tspan = text.text(null)
.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(''));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan")
.attr("x", x)
.attr("y", y)
.attr("dy", ++lineNumber * lineHeight + dy + "em")
.text(word);
}
}
});
}
Thermometer.prototype.drawTick = function(t, label, labelColor, textOffset, width, tubeWidth, lineColor, scale, svg) {
svg.append("line")
.attr("id", label + "Line")
.attr("x1", width / 2 - tubeWidth / 2)
.attr("x2", width / 2 + tubeWidth / 2)
.attr("y1", scale(t))
.attr("y2", scale(t))
.style("stroke", lineColor)
.style("stroke-width", "2px")
.style("shape-rendering", "crispEdges");
if (label) {
svg.append("text")
.attr("x", width / 2 + tubeWidth / 2 + 15)
.attr("y", scale(t))
.attr("dy", ".5em")
.text(label)
.style("fill", labelColor)
.style("stroke", "black")
.style("font-size", "14px")
.call(wrap,30,label)
}
};
return Thermometer;
the link to my fiddle is here
https://jsfiddle.net/corcorancr/sxs5n2cw/1/
The drawTick() function is calling another function called wrap() to plot the text. As might be suggested by that name, wrap() is splitting the input text into words and wrapping it onto a new line if it gets wider than the width you pass in.
The width value is the "30" in the following line:
.call(wrap,30,label)
Try changing it to something bigger so that it doesn't wrap so soon. 180 seems to be about the right value.
https://jsfiddle.net/sxs5n2cw/4/

Pie Chart with d34raphael

I need to draw a pie chart that's works in IE 8, so I'm using d34raphael.
currently this is my code, which is modified from a d3 pie chart example https://raw.github.com/mbostock/d3/master/examples/pie/pie.html
var width = 300,
height = 300,
outerRadius = Math.min(width, height) / 2,
innerRadius = outerRadius * .6,
data = d3.range(10).map(Math.random),
color = d3.scale.category20(),
donut = d3.layout.pie(),
arc = d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius);
// #chart is a div
var paper = new Raphael($('#chart')[0], width, height);
var svg = d3.raphael(paper);
paper.setStart();
var vis = svg.selectAll('rect')
.data([data])
.enter().append('rect')
.attr('x', 0)
.attr('y', 0)
.attr('width', width)
.attr('height', height);
svg.selectAll('path')
.data(donut)
.enter().append('path')
.attr('fill', function(d, i) { return color(i); })
.attr('d', arc)
.attr('transform', 'translate(' + outerRadius + ',' + outerRadius + ')');
paper.setFinish().transform(['t', 0, 0]);
it crashes when I pass donut into the data function, the bind function inside d3's data function has a group argument. after stepping through the data function, I found that group was undefined. (for me, it crashes on d3.v2.js:4997 bind(group = this[i], value.call(group, group.parentNode.__data__, i));, it tries to reference parentNode on the undefined group) I think this may be related to raphael not supporting the g tag. any Ideas on how i can use the d3 pie layout with d34raphael? Thanks

Resources