How to work with multiple datasets in p5.js? - p5.js
I want to create multiple line graphs with their own datasets into one p5.js sketch.
I created one line graph and do not know how to make another line graph to work with a different dataset.
https://editor.p5js.org/ariel.koh/sketches/VsRk3KxYp
I tried to create another preload table for my second graph but it did not work so I am still confused.
This was what I tried but I think it is not right, I never tried working with multiple datasets before so I am confused :(
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
// canonattacks dataset
canonaattacksdataset = loadTable("canonattacks.csv", "csv",
"header");
}
You're on the right track loading the data.
The p5.js code you posted is a bit convoluted, here only a few examples:
the year labels a manually drawn, for each chart (even though the data is contained in the csv files)
if the text is simply drawn for the years but separate style, coordinate transformations, etc. are used then the push()/pop() call don't add anything.(e.g push();let sbm = 'Saul Bass Movies';...)
the drawLineGraph() function is defined twice (which might get you into variable shadowing bugs) and might be accidentally called within itself
No wonder you're confused.
I'd simplify as much as possible:
get back to loading and displaying one graph
load the second dataset (as you already correctly do above)
display the second graph
For example:
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
}
function draw() {
background(184, 37, 0);
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text("Burns", 30, 20, 330, 150); // Text wraps within text box
pop();
//linegraph
drawLineGraph({
dataset: burnsdataset,
column: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text("Canon Attacks", 30, 250, 330, 150); // Text wraps within text box
pop();
//linegraph
drawLineGraph({
dataset: canonaattacksdataset,
column: 1,
x: 30,
y: 280,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.column);
let minValue = min(values);
let maxValue = max(values);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
// we will calcualte the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
With that working you can focus on making the code nicer.
Taking the idea of "don't repeat yourself(DRY)" you can notice a few patterns that could be improved:
you try to not just draw the graph, but also also display the graph's
label: perhaps the drawLineGraph() could include that
you seem to manually be drawing every single year label, even though the data is already in the dataset and the x position is already calculated to display the points of the graph
Tackling point 1 is fairly straight foward: simply move the label drawing instrunctions inside the function, handle the extra argument to get the label text and adjust coordinates so they're relative to the graph.
Here's a modified version of the above integrating label as part of the drawLineGraph() function:
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
}
function draw() {
background(184, 37, 0);
//linegraph
drawLineGraph({
dataset: burnsdataset,
label: "Burns",
column: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
//linegraph
drawLineGraph({
dataset: canonaattacksdataset,
label: "Canon Attacks",
column: 1,
x: 30,
y: 280,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.column);
let minValue = min(values);
let maxValue = max(values);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let label = theProps.label || "";
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text(label, x, y + h + marginTopBottom * 0.5, w, h); // Text wraps within text box
pop();
// we will calculate the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
And here's a modified version of the above that renders the labels on the x axis (year):
// file -> duplicate and file -> save
// this sketch first before you
// start working on it.
//
//
//
// Graph from Data, Line graph example
//
// Slides:
// http://slides.com/sojamo/cid-3-2122/fullscreen#/12/5
let burnsdataset;
let canonattacksdataset;
function preload() {
// burns dataset
burnsdataset = loadTable("burns.csv", "csv", "header");
// canon attacks dataset
canonaattacksdataset = loadTable("canonattacks.csv", "csv", "header");
}
function setup() {
// if you add SVG as 3rd parameter and then
// press s, the canvas will be saved as SVG file
createCanvas(displayWidth, displayHeight, SVG);
drawPlots();
}
function drawPlots() {
background(184, 37, 0);
// burnsdataset linegraph
drawLineGraph({
dataset: burnsdataset,
label: "Burns",
xColumn: 0,
yColumn: 1,
x: 30,
y: 50,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
// canonaattacksdataset linegraph
drawLineGraph({
dataset: canonaattacksdataset,
label: "Canon Attacks",
xColumn: 0,
yColumn: 1,
x: 30,
y: 300,
w: width - 1500,
h: height - 900,
lc: color(255, 255, 255),
dc: color(169, 247, 111),
thickness: 1.5,
isCurve: true,
isDots: true,
isBackground: true,
isLabel: true,
});
}
function drawLineGraph(theProps = {}) {
let values = theProps.dataset.getColumn(theProps.yColumn);
let minValue = min(values);
let maxValue = max(values);
let labels = theProps.dataset.getColumn(theProps.xColumn);
let x = theProps.x || 0;
let y = theProps.y || 0;
let w = theProps.w || 400;
let h = theProps.h || 300;
let bg = theProps.bg || color(255, 40);
let fg = theProps.fg || color(255, 120);
let dc = theProps.dc || color(0, 120);
let bc = theProps.bc || color(0, 120);
let lc = theProps.lc || color(255);
let thickness = theProps.thickness || 1;
let isLabel = theProps.isLabel || false;
let isCurve = theProps.isCurve || false;
let isDots = theProps.isDots || false;
let isBackground = theProps.isBackground || false;
let label = theProps.label || "";
let spacing = w / (values.length - 1);
let marginTopBottom = 20;
// y position for labels (e.g. years)
let labelsY = marginTopBottom * 0.5;
//bottom label title
push();
textSize(14);
textFont("inconsolata");
textStyle(BOLDITALIC);
fill(243, 230, 214);
text(label, x, y - marginTopBottom, w, h); // Text wraps within text box
pop();
// we will calculate the x and y values for each
// point first, because we need it later a couple
// of times.
let xx = [];
let yy = [];
let n = values.length;
for (let i = 0; i < n; i++) {
xx[i] = i * spacing;
yy[i] = map(
values[i],
minValue,
maxValue,
-marginTopBottom,
marginTopBottom - h
);
}
push();
translate(x, y);
translate(0, h);
// 1. draw background
if (isBackground == true) {
fill(bg);
rect(0, 0, w, -h);
// 2. draw grid
noStroke();
for (let i = 0; i < n - 1; i++) {
// fill(255,i%2 == 0 ? 80:40);
rect(xx[i], 0, 1, -h);
}
}
// 3. draw curved line graph
noFill();
stroke(lc);
strokeWeight(thickness);
beginShape();
if (isCurve == true) {
vertex(xx[0], yy[0]);
}
for (let i = 0; i < n; i++) {
let fn = isCurve == true ? curveVertex : vertex;
fn(xx[i], yy[i]);
// label per data point
push();
noStroke();
fill(255);
textSize(9);
textAlign(CENTER);
text(labels[i], xx[i], labelsY);
pop();
}
if (isCurve == true) {
vertex(xx[n - 1], yy[n - 1]);
}
endShape();
// 4. draw dot / label for each value
noStroke();
// finally lets draw the dots and
// labels if enabled
let d = thickness + 8;
for (let i = 0; i < n; i++) {
push();
translate(xx[i], yy[i]);
if(isDots == true) {
fill(bc);
ellipse(0, 0, d + 4, d + 4);
fill(dc);
ellipse(0, 0, d, d);
}
if (isLabel == true) {
fill(lc)
rotate(-0.5);
textSize(7);
text(values[i], d, -d);
}
pop();
}
pop();
}
// if you want to use the SVG export
// option, go to setup and enable SVG mode
function keyPressed() {
if (key === "s") {
saveSVG("line-graph.svg");
}
}
There's one slight detail snuck in there: I've renamed draw() to drawPlots() and called it once from setup(). That is to render the plots a single time since they don't change and save CPU resources. If you do plan to have some sort interation changing these graphs then you should use draw().
Related
Is there a way to draw a matter.js composite with p5?
I recently saw the matter.js on the coding train channel from 2017, I've managed to replicate the examples shown on those videos but now I wanted to do something more advanced. There is a Composite module called stack in the documentation used to create a soft body in the matter.js demos but I wonder if there is a way to draw this using p5 instead. This is what I've gotten so far, any help is appreciated
I think the main issue with your code was that you weren't adding the Composite to the world. Here's a working example with a few other tweaks: const { Bodies, Common, Composites, Constraint, Engine, Runner, World } = Matter; var engine; var world; var particles = []; var boundaries = []; var composi1; var composi2; function setup() { createCanvas(400, 400); engine = Engine.create(); world = engine.world; // Use a runner to actually run the simulation const runner = Runner.create(); Runner.run(runner, engine); // Add two composites so we can see them interact composi1 = new softbodi(100, 50, 4, 4, 0, 0, true, 20); composi2 = new softbodi(50, 300, 4, 2, 0, 0, true, 20); boundaries.push(new Boundary(200, height, width, 50, 0)); } function draw() { background(51); for (var i = 0; i < boundaries.length; i++) { boundaries[i].show(); } composi1.show(); composi2.show(); } function softbodi( xx, yy, columns, rows, columnGap, rowGap, crossBrace, particleRadius) { this.r = particleRadius; this.composite = Composites.stack( xx, yy, columns, rows, columnGap, rowGap, function(x, y) { return Bodies.circle(x, y, particleRadius); } ); this.mesh = Composites.mesh(this.composite, columns, rows, crossBrace); // Dont forget to add you composite to the world World.add(world, this.composite); this.show = function() { var parr = []; parr = Matter.Composite.allBodies(this.composite); for (var i = 0; i < parr.length; i++) { var pos = parr[i].position; var angle = parr[i].angle; push(); translate(pos.x, pos.y); rotate(angle); rectMode(CENTER); strokeWeight(1); stroke(255); fill(127); ellipse(0, 0, this.r * 2); pop(); } }; } function Boundary(x, y, w, h, a) { var options = { friction: 0, restitution: 0.95, angle: a, isStatic: true }; this.body = Bodies.rectangle(x, y, w, h, options); this.w = w; this.h = h; World.add(world, this.body); this.show = function() { var pos = this.body.position; var angle = this.body.angle; push(); translate(pos.x, pos.y); rotate(angle); rectMode(CENTER); strokeWeight(1); noStroke(); fill(0); rect(0, 0, this.w, this.h); pop(); }; } <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.17.1/matter.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
P5.js Creating a fading curve on a grid
I've made a square grid on top of the canvas and also a cruve (that is meant to have a fading trail). I made them seperately and tried combining them so the curve would appear on top of the grid. However, it doesn't show the curve. I've commented out the grid so it's easier to see the curve. How do I get this to work? var cols = 10; var rows = 10; var t = 0; var particleArray = []; function setup() { createCanvas(600, 600); background(0); fill(100); rect(0, 0, 550, 550, 25); } // blue grid function draw() { /*for (var c = 0; c < cols; c++) { for (var r = 0; r < rows; r++) { var XO = 25 + c * 50; var YO = 25 + r * 50; stroke(0); fill(100,149,237); rect(XO, YO, 50, 50); noLoop(); // :( } } */ //curve y = width / 2 + 270 * sin(3 * t + PI / 2) - 25; x = height / 2 + 270 * sin(1 * t) - 25; particleArray.push(new Particle(x, y, t)); for (i=0; i<particleArray.length; i++) { particleArray[i].show(t); } if (particleArray.length > 700) { particleArray.shift(); } t += .01; } function Particle(x, y, t) { this.x = x; this.y = y; this.t = t; this.show = function(currentT) { var _ratio = t / currentT; _alpha = map(_ratio, 0, 1, 0, 255); //points will fade out as time elaps fill(255, 255, 255, _alpha); ellipse(x, y, 5, 5); } }
I don't know if this was intentional but you called noLoop() function where you're drawing the grid. If you comment that out it works.
p5.js Add a dissapearing ellipse trail to Lissajous curve line
I have a simple code that traces the Liss cruve with a small ellipse. I was wondering how to add a fading trail to this shape so it represents the cruve more clearly. I only know a bit about adding trails that follows the mouse but I'm not sure how to do this one. Any help is appreciated, here is the code: var t = 0; function setup() { createCanvas(500, 500); fill(255); } function draw() { background(0); for (i = 0; i < 1; i++) { y = 160*sin(3*t+PI/2); x = 160*sin(1*t); fill(255); ellipse(width/2+x, height/2+y, 5, 5); t += .01; } }
Try changing background(0) to background(0, 0, 0, 4) :) Here is a working example: https://editor.p5js.org/chen-ni/sketches/I-FbLFDXi Edit: Here is another solution that doesn't use the background trick: https://editor.p5js.org/chen-ni/sketches/HiT4Ycd5U Basically, it keeps track of each point's position and redraws them in every frame with updated alpha to create the "fading out" effect. var t = 0; var particleArray = []; function setup() { createCanvas(500, 500); } function draw() { background(0); y = width / 2 + 160 * sin(3 * t + PI / 2); x = height / 2 + 160 * sin(1 * t); particleArray.push(new Particle(x, y, t)); for (i=0; i<particleArray.length; i++) { particleArray[i].show(t); } //keep the array short, otherwise it runs very slow if (particleArray.length > 800) { particleArray.shift(); } t += .01; } function Particle(x, y, t) { this.x = x; this.y = y; this.t = t; this.show = function(currentT) { var _ratio = t / currentT; _alpha = map(_ratio, 0, 1, 0, 255); //points will fade out as time elaps fill(255, 255, 255, _alpha); ellipse(x, y, 5, 5); } }
Texture flickering in p5
I have a scene with a cube and a custom obj. I am attempting to apply a gradient as a texture to the cube via createGraphics, but every time I use createGraphics as a texture on the cube it flickers The custom model does not have the same issue when using the createGraphics texture for it, it is exclusively a problem with the cube. Here is my code: var camy; var camz; var camoffset; var horiZon; var c1; var c2; function preload() { fria = loadImage('nocity.png'); island = loadModel('untitled.obj'); } function setup() { canvas = createCanvas(windowWidth, windowHeight, WEBGL); pixelDensity=1; c1 = color(255, 255, 255); c2 = color(0, 0, 0); sunset = createGraphics(200, 200); } function windowResized() { resizeCanvas(windowWidth,windowHeight); } function draw() { background(0, 5, 100); angleMode(DEGREES); camoffset = 2500 - windowWidth; horiZon = map(mouseY, 0, height, -35, -65); camx = map(mouseX, 0, width, -500, 500); camz = map(mouseY, height, 0, -1400 - camoffset, -2100 - camoffset); camy = map(mouseY, height, 0, -1000 - camoffset, -400); setGradient(0, 0, 200, 200, c1, c2); perspective(PI / 3.0, width / height, 0.1, 10000); camera(camx, camy, camz, 0, 0, 0, 0, 1, -0.25); translate(-2.5, 6, 0); rotateZ(180); rotateY(180); noStroke(); texture(fria); model(island); texture(sunset); translate(0, 100, horiZon); box(200, 200, 1); } function setGradient(x, y, w, h, c1, c2) { noFill(); for (var i = y; i <= y + h; i++) { var inter = map(i, y, y + h, 0, 1); var c = lerpColor(c1, c2, inter); sunset.stroke(c); sunset.line(x, i, x + w, i); } }
I found a solution to this problem. When I removed the camera code, the flickering disappeared. So the solution I made was I instead used translation and rotation to emulate the camera motions that I wanted. It is quite hard to think of it this way, but you can figure out what translation you need to do with simple trig.
How to set Text position steady?
With the help of TextGeometry, I am drawing text around meshes. PerspectiveCamera is in steady mode, My cube is moving itself in the scene. How can text take a look to the object rotation? Check this I want to do like this same. var storeCamera = new THREE.PerspectiveCamera(75, $domElement.innerWidth() / $domElement.innerHeight(), 1, 10000); dist = (largestSide - 0) / 2 + (largestSide - 0) / (2 * Math.tan(storeCamera.fov * Math.PI / 360)); storeCamera.position.z = dist; var axisHelperScene = new THREE.Scene(); var axisHelperCamera = new THREE.PerspectiveCamera(75, $domElement.find('.axis-helper').innerWidth() / $domElement.find('.axis-helper').innerHeight(), 1, 10000); axisHelperCamera.position.z = 350; var axisHelperRenderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); axisHelperRenderer.setSize($domElement.find('.axis-helper').innerWidth(), $domElement.find('.axis-helper').innerHeight()); $domElement.find('.axis-helper').append(axisHelperRenderer.domElement); var directionX = new THREE.Vector3(1, 0, 0); var directionY = new THREE.Vector3(0, 0, -1); var directionZ = new THREE.Vector3(0, 1, 0); var origin = new THREE.Vector3(0, 0, 0); var length = 150; var color = 0x4a4f65; var headLength = 45; var headWidth = 30; // creating axes var arrowHelperX = new THREE.ArrowHelper(directionX, origin, length, color, headLength, headWidth); arrowHelperX.line.material.linewidth = 4; var arrowHelperY = new THREE.ArrowHelper(directionY, origin, length, color, headLength, headWidth); arrowHelperX.line.material.linewidth = 4; var arrowHelperZ = new THREE.ArrowHelper(directionZ, origin, length, color, headLength, headWidth); arrowHelperX.line.material.linewidth = 4; // origin sphere var axisSphere = new THREE.Mesh(new THREE.SphereGeometry(15, 40, 40, 40), new THREE.MeshLambertMaterial({ color: 0x4a4f65 })); var axisGroup = new THREE.Group(); axisGroup.add(arrowHelperX); axisGroup.add(arrowHelperY); axisGroup.add(arrowHelperZ); axisGroup.add(axisSphere); axisGroup.rotation.x = 0.60; axisGroup.rotation.y = -0.50; // #region Adding axis labels var fontLoader = new THREE.FontLoader(); var jsonFont = String.format("{0}Scripts/threejs/json/helvetiker_regular.typeface.json", GetResourceFromClient("RootUrl")); fontLoader.load(jsonFont, function (theFont) { var xLabel = new THREE.TextGeometry("X", { font: theFont, size: 35, height: 10, curveSegments: 12, bevelThickness: 1, bevelSize: 1, bevelEnabled: true }); var yLabel = new THREE.TextGeometry("Y", { font: theFont, size: 35, height: 10, curveSegments: 12, bevelThickness: 1, bevelSize: 1, bevelEnabled: true }); var zLabel = new THREE.TextGeometry("Z", { font: theFont, size: 35, height: 10, curveSegments: 12, bevelThickness: 1, bevelSize: 1, bevelEnabled: true }); var textMaterial = new THREE.MeshLambertMaterial({ color: 0x4a4f65 }); var xMesh = new THREE.Mesh(xLabel, textMaterial); xMesh.position.x = 160; xMesh.position.y = -10; axisGroup.add(xMesh); var yMesh = new THREE.Mesh(yLabel, textMaterial); yMesh.position.x = -10; yMesh.position.z = -160; axisGroup.add(yMesh); var zMesh = new THREE.Mesh(zLabel, textMaterial); zMesh.position.x = -10; zMesh.position.y = 160; axisGroup.add(zMesh); }); // #endregion Adding axis labels function render() { storeRenderer.render(storeScene, storeCamera); axisHelperRenderer.render(axisHelperScene, axisHelperCamera); requestAnimFrame(render); }
Instead of using a TextGeometry for the axis labels a sprite could be an option var xLabel = makeTextSprite(" X ", { fontsize: 100, borderColor: { r: 0, g: 0, b: 0, a: 1.0 }, backgroundColor: { r: 255, g: 255, b: 255, a: 0.8 } , borderThickness: 5}); xLabel.position.set(150, 0, 0); axisGroup.add(xLabel); // creates a THREE.Sprite object with the given text and parameters function makeTextSprite(theMessage, theParameters) { if (theParameters === undefined) theParameters = { }; var fontface = theParameters.hasOwnProperty("fontface") ? theParameters["fontface"] : "Arial"; var fontsize = theParameters.hasOwnProperty("fontsize") ? theParameters["fontsize"] : 18; var borderThickness = theParameters.hasOwnProperty("borderThickness") ? theParameters["borderThickness"] : 4; var borderColor = theParameters.hasOwnProperty("borderColor") ? theParameters["borderColor"] : { r: 0, g: 0, b: 0, a: 1.0 }; var backgroundColor = theParameters.hasOwnProperty("backgroundColor") ? theParameters["backgroundColor"] : { r: 255, g: 255, b: 255, a: 1.0 }; var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); context.font = "Bold " + fontsize + "px " + fontface; // get size data (height depends only on font size) var metrics = context.measureText(theMessage); var textWidth = metrics.width; // background color context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g + "," + backgroundColor.b + "," + backgroundColor.a + ")"; // border color context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + "," + borderColor.b + "," + borderColor.a + ")"; context.lineWidth = borderThickness; roundRect(context, borderThickness / 2, borderThickness / 2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6); // 1.4 is extra height factor for text below baseline: g,j,p,q. // text color context.fillStyle = "rgba(0, 0, 0, 1.0)"; context.fillText(theMessage, borderThickness, fontsize + borderThickness); // canvas contents will be used for a texture var texture = new THREE.Texture(canvas) texture.needsUpdate = true; var spriteMaterial = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: false }); var sprite = new THREE.Sprite(spriteMaterial); sprite.scale.set(100, 50, 1.0); return sprite; } // function for drawing rounded rectangles function roundRect(ctx, x, y, w, h, r) { ctx.beginPath(); ctx.moveTo(x + r, y); ctx.lineTo(x + w - r, y); ctx.quadraticCurveTo(x + w, y, x + w, y + r); ctx.lineTo(x + w, y + h - r); ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h); ctx.lineTo(x + r, y + h); ctx.quadraticCurveTo(x, y + h, x, y + h - r); ctx.lineTo(x, y + r); ctx.quadraticCurveTo(x, y, x + r, y); ctx.closePath(); ctx.fill(); ctx.stroke(); } }