Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds D3 graphing !!! #22

Merged
merged 1 commit into from
Nov 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 62 additions & 32 deletions src/js/lib/application.tsx
Original file line number Diff line number Diff line change
@@ -1,111 +1,141 @@
import React from 'react';
import "./styles.css"
import React from "react";
import "./styles.css";
import * as dataviz from "./dataviz";
import * as galaxy from "./galaxy";

const wasm = import("galaxy_gen_backend/galaxy_gen_backend");

export function Interface() {
export function Interface() {
const [galaxySize, setGalaxySize] = React.useState(100);
const [galaxySeedMass, setGalaxySeedMass] = React.useState(3);
const [galaxyGravityReach, setGalaxyGravityReach] = React.useState(10);
const [galaxySeedMass, setGalaxySeedMass] = React.useState(5);
const [minStarMass, setMinStarMass] = React.useState(1000);
let wasmModule: any = null;
let galaxyFrontend: galaxy.Frontend = null;

wasm.then((module) => {
console.log("wasm module loaded: ", module)
console.log("wasm module loaded: ", module);
wasmModule = module;
});

const handleGalaxySizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setGalaxySize(parseInt(event.target.value));
const handleGalaxySizeChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const value = parseInt(event.target.value);
setGalaxySize(Number.isNaN(value) ? 0 : value);
};

const galaxySizeInput = (
<div className="input-group mb-3">
<span className="input-group-text" id="basic-addon1">Galaxy Size:</span>
<span className="input-group-text" id="basic-addon1">
Galaxy Size:
</span>
<input
type="text" className="form-control" placeholder="Username" name="galaxySize"
value={galaxySize.toString()} onChange={handleGalaxySizeChange}
type="text"
className="form-control"
name="galaxySize"
value={galaxySize.toString()}
onChange={handleGalaxySizeChange}
/>
</div>
)
);

const handleGalaxySeedMassChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setGalaxySeedMass(parseInt(event.target.value));
const handleGalaxySeedMassChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const value = parseInt(event.target.value);
setGalaxySeedMass(Number.isNaN(value) ? 0 : value);
};

const galaxySeedMassInput = (
<div className="input-group mb-3">
<span className="input-group-text" id="basic-addon1">Seed Mass:</span>
<span className="input-group-text" id="basic-addon1">
Seed Mass:
</span>
<input
type="text" className="form-control" placeholder="Username" name="galaxySeedMass"
value={galaxySeedMass.toString()} onChange={handleGalaxySeedMassChange}
type="text"
className="form-control"
name="galaxySeedMass"
value={galaxySeedMass.toString()}
onChange={handleGalaxySeedMassChange}
/>
</div>
)
);

const handleGalaxyGravityReachChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setGalaxySeedMass(parseInt(event.target.value));
const handleMinStarMassChange = (
event: React.ChangeEvent<HTMLInputElement>
) => {
const value = parseInt(event.target.value);
setMinStarMass(Number.isNaN(value) ? 0 : value);
};

const galaxyGravityReachInput = (
const minStarMassInput = (
<div className="input-group mb-3">
<span className="input-group-text" id="basic-addon1">Gravity Reach:</span>
<span className="input-group-text" id="basic-addon1">
Min Star Mass:
</span>
<input
type="text" className="form-control" placeholder="Username" name="galaxyGravityReach"
value={galaxyGravityReach.toString()} onChange={handleGalaxyGravityReachChange}
type="text"
className="form-control"
name="minStarMass"
value={minStarMass.toString()}
onChange={handleMinStarMassChange}
/>
</div>
)
);

const handleInitClick = () => {
if (wasmModule === null) {
console.error("wasm not yet loaded");
} else {
console.log("initializing galaxy");
galaxyFrontend = new galaxy.Frontend(galaxySize);
galaxyFrontend = new galaxy.Frontend(galaxySize, minStarMass);
dataviz.initViz(galaxyFrontend);
}
};

const initButton = (
<button type="button" className="btn btn-primary" onClick={handleInitClick}>
init new galaxy
</button>
)
);

const handleSeedClick = () => {
if (galaxyFrontend === null) {
console.error("galaxy not yet initialized");
} else {
console.log("seeding galaxy");
galaxyFrontend.seed(galaxySeedMass);
dataviz.initData(galaxyFrontend);
}
};

const seedButton = (
<button type="button" className="btn btn-primary" onClick={handleSeedClick}>
seed the galaxy
</button>
)
);

const handleTickClick = () => {
galaxyFrontend.tick(galaxyGravityReach);
galaxyFrontend.tick(minStarMass);
};

const tickButton = (
<button type="button" className="btn btn-primary" onClick={handleTickClick}>
advance time
</button>
)
);

return (
<div className="container">
<h1>Galaxy Generator</h1>
<h2><small className="text-muted">( rust =&gt; wasm =&gt; js ) galaxy generation simulation</small></h2>
<h2>
<small className="text-muted">
( rust =&gt; wasm =&gt; js ) galaxy generation simulation
</small>
</h2>
{galaxySizeInput}
{galaxySeedMassInput}
{galaxyGravityReachInput}
{minStarMassInput}
<div className="d-flex justify-content-between">
{initButton}
{seedButton}
Expand Down
94 changes: 59 additions & 35 deletions src/js/lib/dataviz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,47 +2,71 @@ import React from "react";
import * as d3 from "d3";
import * as galaxy from "./galaxy";

export function DataViz(data: galaxy.Frontend) {
// set the dimensions and margins of the graph
const margin = { top: 10, right: 30, bottom: 30, left: 60 },
width = 460 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
const margin = { top: 40, right: 40, bottom: 40, left: 40 };

function getSizeModifier(galaxyFrontend: galaxy.Frontend) {
return Math.sqrt(galaxyFrontend.galaxySize);
}

export function initViz(galaxyFrontend: galaxy.Frontend) {
const sizeModifier = getSizeModifier(galaxyFrontend);
const width = galaxyFrontend.galaxySize + margin.left + margin.right;
const height = galaxyFrontend.galaxySize + margin.top + margin.bottom;

// remove old svg
d3.select("#dataviz svg").remove();

// append the svg object to the body of the page
const svg = d3
.select("#dataviz")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("width", width * sizeModifier + margin.left + margin.right)
.attr("height", height * sizeModifier + margin.top + margin.bottom)
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);

//Read the data
d3.csv("https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/2_TwoNum.csv").then( function(data) {

// Add X axis
const x = d3.scaleLinear()
.domain([0, 4000])
.range([ 0, width ]);
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(d3.axisBottom(x));

// Add Y axis
const y = d3.scaleLinear()
.domain([0, 500000])
.range([ height, 0]);
svg.append("g")
.call(d3.axisLeft(y));

// Add dots
svg.append('g')
.selectAll("dot")
.data(data)
.join("circle")
.attr("cx", function (d) { return x(d.GrLivArea); } )
.attr("cy", function (d) { return y(d.SalePrice); } )
.attr("r", 1.5)
.style("fill", "#69b3a2")
});
// Add X axis
const x = d3
.scaleLinear()
.domain([0, galaxyFrontend.galaxySize])
.range([0, galaxyFrontend.galaxySize * sizeModifier]);
svg
.append("g")
.attr(
"transform",
`translate(0, ${galaxyFrontend.galaxySize * sizeModifier})`
)
.call(d3.axisBottom(x));

// Add Y axis
const y = d3
.scaleLinear()
.domain([0, galaxyFrontend.galaxySize])
.range([galaxyFrontend.galaxySize * sizeModifier, 0]);
svg.append("g").call(d3.axisLeft(y));
}

export function initData(galaxyFrontend: galaxy.Frontend) {
const sizeModifier = getSizeModifier(galaxyFrontend);

// remove old data
d3.select("#dataviz svg circle").remove();

// append the svg object to the body of the page
const svg = d3.select("#dataviz svg");
svg
.append("g")
.selectAll("dot")
.data(galaxyFrontend.cells())
.join("circle")
.attr("cx", function (c: galaxy.Cell) {
return c.x * sizeModifier + margin.left;
})
.attr("cy", function (c: galaxy.Cell) {
return c.y * sizeModifier + margin.top;
})
.attr("r", function (c: galaxy.Cell) {
return c.mass;
})
.style("fill", "#69b3a2");
}
29 changes: 15 additions & 14 deletions src/js/lib/galaxy.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as wasm from "galaxy_gen_backend/galaxy_gen_backend";

interface Cell {
export interface Cell {
mass: number;
x: number;
y: number;
Expand All @@ -12,32 +12,33 @@ interface Cell {
*/
export class Frontend {
private galaxy: wasm.Galaxy; // pointer to galaxy
private galaxySize: number;
public galaxySize: number;

constructor(galaxySize: number) {
this.galaxy = new wasm.Galaxy(galaxySize, 0);
constructor(galaxySize: number, minStarMass: number) {
this.galaxy = new wasm.Galaxy(galaxySize, 0, minStarMass);
this.galaxySize = galaxySize;
}

public seed(additionalMass: number): void {
this.galaxy.seed(additionalMass);
this.galaxy = this.galaxy.seed(additionalMass);
}

public tick(gravityReach: number): void {
this.galaxy.tick(gravityReach);
this.galaxy = this.galaxy.tick(gravityReach);
}

public cells(): Cell[] {
// Uint16Array to list of numbers
let cells: Cell[] = [];
const mass = Array.from(this.galaxy.mass());
mass.forEach((element, index) => {
const mass = this.galaxy.mass();
const x = this.galaxy.x();
const y = this.galaxy.y();
const cells: Cell[] = [];
for (let i = 0; i < this.galaxySize ** 2; i++) {
cells.push({
mass: element,
x: index % this.galaxySize,
y: Math.floor(index / this.galaxySize),
mass: mass[i],
x: x[i],
y: y[i],
});
});
}
return cells;
}
}
Loading