Skip to content

Instantly share code, notes, and snippets.

@dribnet
Last active May 7, 2019 07:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 31 You must be signed in to fork a gist
  • Save dribnet/1b4c38b6dc5b9c69177466a17c4680b2 to your computer and use it in GitHub Desktop.
Save dribnet/1b4c38b6dc5b9c69177466a17c4680b2 to your computer and use it in GitHub Desktop.
Dimensional Glyph
license: mit
// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
function saveBlocksImages(doZoom) {
if(doZoom == null) {
doZoom = false;
}
// generate 960x500 preview.jpg of entire canvas
// TODO: should this be recycled?
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = 960;
offscreenCanvas.height = 500;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 960, 500);
context.drawImage(this.canvas, 0, 0, 960, 500);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/jpeg');
imageData = imageData.replace('image/jpeg', downloadMime);
p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');
// generate 230x120 thumbnail.png centered on mouse
offscreenCanvas.width = 230;
offscreenCanvas.height = 120;
// background is flat white
context = offscreenCanvas.getContext('2d');
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, 230, 120);
if(doZoom) {
// pixelDensity does the right thing on retina displays
var pd = this._pixelDensity;
var sx = pd * mouseX - pd * 230/2;
var sy = pd * mouseY - pd * 120/2;
var sw = pd * 230;
var sh = pd * 120;
// bounds checking - just displace if necessary
if (sx < 0) {
sx = 0;
}
if (sx > this.canvas.width - sw) {
sx = this.canvas.width - sw;
}
if (sy < 0) {
sy = 0;
}
if (sy > this.canvas.height - sh) {
sy = this.canvas.height - sh;
}
// save to browser
context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
}
else {
// now scaledown
var full_width = this.canvas.width;
var full_height = this.canvas.height;
context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
}
imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}

PS4 MDDN 342 2016

This is the code for getting started with PS4.

/*
* val4 is an array of 4 numbers that range from [0,100]
* size is the number of pixels for width and height
* use p5.js to draw a round grawscale glpyh within the bounding box
*/
function glyph4(values, size) {
var color1 = map(values[0], 0, 100, 10, 70)
stroke(color1);
fill(color1)
var s2 = size/2;
ellipse(s2, s2, size);
var inner_size = 0.2 + 0.4 * values[2] / 100.0;
var s3 = size * inner_size;
var color2 = map(values[1], 0, 100, color1+20, 240)
fill(color2);
stroke(color2);
var shift_frac = (values[3] - 50.0) / 50.0;
var max_shift = 0.5 * (size - s3);
var x_shift = shift_frac * max_shift;
ellipse(s2 + x_shift, s2, s3);
}
/*
* val8 is an array of 8 numbers that range from [0,100]
* size is the number of pixels for width and height
* use p5.js to draw a square color glpyh within the bounding box
*/
function glyph8(values, size) {
var red = [255, 0, 0];
var green = [0, 255, 0];
var blue = [0, 0, 255];
var white = [255, 255, 255];
var colors = [red, green, blue, white, red, green, blue, white];
stroke(0);
fill(0);
rect(0, 0, size, size);
for(var i=0; i<8; i++) {
stroke(colors[i]);
fill(colors[i]);
offsety = i * size / 8;
offsetx = (size * values[i]) / 100;
rect(0, offsety, offsetx, size/8);
}
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.3/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src=".purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="glyph.js"></script>
<script language="javascript" type="text/javascript" src="sketch.js"></script>
<style>
body { padding: 0; margin: 0; }
.inner { position: absolute; }
#controls {
font: 300 12px "Helvetica Neue";
padding: 5;
margin: 5;
background: #f0f0f0;
opacity: 0.1;
-webkit-transition: opacity 0.2s ease;
-moz-transition: opacity 0.2s ease;
-o-transition: opacity 0.2s ease;
-ms-transition: opacity 0.2s ease;
}
#controls:hover { opacity: 0.9; }
</style>
</head>
<body style="background-color:white">
<div class="outer">
<div class="inner">
<div id="canvasContainer"></div>
</div>
<div class="inner" id="controls" height="500px">
<table>
<tr>
<td>1</td>
<td id="slider1Container"></td>
</tr>
<tr>
<td>2</td>
<td id="slider2Container"></td>
</tr>
<tr>
<td>3</td>
<td id="slider3Container"></td>
</tr>
<tr>
<td>4</td>
<td id="slider4Container"></td>
</tr>
<tr>
<td>5</td>
<td id="slider5Container"></td>
</tr>
<tr>
<td>6</td>
<td id="slider6Container"></td>
</tr>
<tr>
<td>7</td>
<td id="slider7Container"></td>
</tr>
<tr>
<td>8</td>
<td id="slider8Container"></td>
</tr>
<tr>
<td>
<hr>
</td>
</tr>
<tr>
<td>Mode</td>
<td id="selector1Container"></td>
</tr>
<tr>
<td>Glyph</td>
<td id="selector2Container"></td>
</tr>
<tr>
<td>Size</td>
<td id="selector3Container"></td>
</tr>
<tr>
<td></td>
<td id="buttonContainer"></td>
</tr>
</div>
</div>
</table>
</body>
var canvasWidth = 960;
var canvasHeight = 500;
var glyphSelector;
var modeSelector;
var sizeSelector;
var val_sliders = [];
function setup () {
// create the drawing canvas, save the canvas element
var main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
// create two sliders
for (i=0; i<8; i++) {
var slider = createSlider(0, 100, 50);
slider.parent("slider" + (i+1) + "Container")
slider.changed(sliderUpdated);
slider.mouseMoved(sliderUpdated);
slider.touchMoved(sliderUpdated);
val_sliders.push(slider);
}
modeSelector = createSelect();
modeSelector.option('gradient');
modeSelector.option('analogy');
modeSelector.option('drive');
modeSelector.option('random_grid');
modeSelector.changed(modeChangedEvent);
modeSelector.value('gradient');
modeSelector.parent('selector1Container');
glyphSelector = createSelect();
glyphSelector.option('glyph4');
glyphSelector.option('glyph8');
glyphSelector.changed(modeChangedEvent);
glyphSelector.parent('selector2Container');
sizeSelector = createSelect();
sizeSelector.option('64');
sizeSelector.option('128');
sizeSelector.option('256');
sizeSelector.parent('selector3Container');
sizeSelector.value('128');
sizeSelector.changed(sizeChangedEvent);
button = createButton('redo');
button.mousePressed(buttonPressedEvent);
button.parent('buttonContainer');
noLoop();
refreshGridData();
modeChangedEvent();
}
function sliderUpdated() {
redraw();
}
function mouseClicked() {
analogyCycleStep = (analogyCycleStep + 1) % 3;
if(analogyCycleStep == 0) {
refreshAnalogyData();
}
redraw();
}
function dataInterpolate(data1, data2, val) {
var d = new Array(8);
for(var i=0; i<8; i++) {
d[i] = lerp(data1[i], data2[i], val);
}
return d;
}
var numGridRows;
var numGridCols;
var gridValues; // row, col order
var gridOffsetX, gridOffsetY;
var gridSpacingX, gridSpacingY;
// Generate data for putting glyphs in a grid
var numAnalogyChoices = 5;
var analogyValues = new Array(4);
var analogyChoices = new Array(numAnalogyChoices);
var analogyAnswer;
var analogyCycleStep;
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
function refreshAnalogyData() {
for (var i=0; i<4; i++) {
analogyValues[i] = new Array(8);
}
for (var i=0; i<3; i++) {
for (var j=0; j<8; j++) {
analogyValues[i][j] = random(100);
}
}
for (var j=0; j<8; j++) {
analogyValues[3][j] = clamp(analogyValues[1][j] - analogyValues[0][j] + analogyValues[2][j], 0, 100);
// handle overflow
analogyValues[1][j] = clamp(analogyValues[3][j] - analogyValues[2][j] + analogyValues[0][j], 0, 100);
}
analogyAnswer = Math.floor(random(numAnalogyChoices))
for (var i=0; i<numAnalogyChoices; i++) {
analogyChoices[i] = new Array(8);
for (var j=0; j<8; j++) {
if (i == analogyAnswer) {
analogyChoices[i][j] = analogyValues[3][j];
}
else {
analogyChoices[i][j] = random(100);
}
}
}
analogyCycleStep = 0;
}
function refreshGridData() {
var glyphSize = parseInt(sizeSelector.value(), 10);
if(glyphSize == 128) {
numGridCols = 7;
numGridRows = 3;
gridOffsetX = 10;
gridSpacingX = 136;
gridOffsetY = 20;
gridSpacingY = 166;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 1;
gridOffsetX = 20;
gridSpacingX = 320;
gridOffsetY = 100;
gridSpacingY = 500;
}
else if(glyphSize == 64) {
numGridCols = 14;
numGridRows = 7;
gridOffsetX = 3;
gridSpacingX = 68;
gridOffsetY = 6;
gridSpacingY = 71;
}
gridValues = new Array(numGridRows);
for (var i=0; i<numGridRows; i++) {
gridValues[i] = new Array(numGridCols);
for (var j=0; j<numGridCols; j++) {
gridValues[i][j] = new Array(8);
}
}
var mode = modeSelector.value();
if (mode == "gradient") {
var top_left = Array(8);
var top_right = Array(8);
var bottom_left = Array(8);
var bottom_right = Array(8);
for (var k=0; k<8; k++) {
top_left[k] = random(100);
top_right[k] = random(100);
bottom_left[k] = random(100);
bottom_right[k] = random(100);
}
for (var i=0; i<numGridRows; i++) {
if(numGridRows == 0) {
var frac_down = 0;
}
else {
var frac_down = i / (numGridRows - 1.0);
}
d_left = dataInterpolate(top_left, bottom_left, frac_down);
d_right = dataInterpolate(top_right, bottom_right, frac_down);
for (var j=0; j<numGridCols; j++) {
if(numGridCols == 0) {
var frac_over = 0;
}
else {
var frac_over = j / (numGridCols - 1.0);
}
gridValues[i][j] = dataInterpolate(d_left, d_right, frac_over);
}
}
}
else {
for (var i=0; i<numGridRows; i++) {
for (var j=0; j<numGridCols; j++) {
for (var k=0; k<8; k++) {
gridValues[i][j][k] = random(100);
}
}
}
}
refreshAnalogyData();
}
function sizeChangedEvent() {
var mode = modeSelector.value();
if (mode != "drive") {
refreshGridData();
}
redraw();
}
function modeChangedEvent() {
var mode = modeSelector.value();
var glyph = glyphSelector.value();
// enable/disable sliders
if (mode === "drive") {
// disable the button
button.attribute('disabled','');
// enable the size selector
sizeSelector.removeAttribute('disabled');
// enable the first four sliders
for(i=0; i<4; i++) {
val_sliders[i].removeAttribute('disabled');
}
if(glyph === "glyph4") {
for(i=4; i<8; i++) {
val_sliders[i].attribute('disabled','');
}
}
else {
for(i=4; i<8; i++) {
val_sliders[i].removeAttribute('disabled');
}
}
}
else {
// enable the button
button.removeAttribute('disabled');
// disable the sliders
for(i=0; i<8; i++) {
val_sliders[i].attribute('disabled','');
}
if (mode == "analogy") {
// enable the size selector
sizeSelector.attribute('disabled','');
}
else {
// enable the size selector
sizeSelector.removeAttribute('disabled');
}
// refresh data
refreshGridData();
}
redraw();
}
function buttonPressedEvent() {
analogyCycleStep = 0;
refreshGridData();
redraw();
}
var colorBack = [128, 128, 128];
var colorFront = [200, 200, 200];
function drawDriveMode() {
var glyph_is_glyph4 = true;
if(glyphSelector.value() === "glyph8")
glyph_is_glyph4 = false;
var glyphSize = parseInt(sizeSelector.value(), 10);
var halfSize = glyphSize / 2;
background(colorBack);
var halfSize = glyphSize / 2;
var middle_x = canvasWidth / 2;
var middle_y = canvasHeight / 2;
resetMatrix();
translate(middle_x - halfSize, middle_y - halfSize);
var val = [0,0,0,0,0,0,0,0];
for(i=0; i<8; i++) {
val[i] = val_sliders[i].value();
}
stroke(128, 128, 192);
noFill();
if(glyph_is_glyph4) {
ellipse(halfSize, halfSize, glyphSize+2);
glyph4(val, glyphSize)
}
else {
rect(-1, -1, glyphSize+2, glyphSize+2);
glyph8(val, glyphSize)
}
}
function drawGridMode() {
var glyph_fn = glyph4;
if(glyphSelector.value() === "glyph8")
glyph_fn = glyph8;
var glyphSize = parseInt(sizeSelector.value(), 10);
background(colorBack);
for (var i=0; i<numGridRows; i++) {
for (var j=0; j<numGridCols; j++) {
resetMatrix();
translate(gridOffsetX + j * gridSpacingX, gridOffsetY + i * gridSpacingY);
for (var k=0; k<8; k++) {
glyph_fn(gridValues[i][j], glyphSize);
}
}
}
}
var analogyOffsetX = 350;
var analogyOffsetY = 40;
var analogySpacingX = 160;
var analogySpacingY = 160;
var analogyChoiceOffsetX = 260;
var analogyChoiceOffsetY = 380;
var analogyChoiceSpacingX = 100;
function drawAnalogy() {
background(colorBack);
var glyph_fn = glyph4;
if(glyphSelector.value() === "glyph8")
glyph_fn = glyph8;
resetMatrix();
translate(analogyOffsetX + 0 * analogySpacingX, analogyOffsetY + 0 * analogySpacingY);
glyph_fn(analogyValues[0], 128);
resetMatrix();
translate(analogyOffsetX + 1 * analogySpacingX, analogyOffsetY + 0 * analogySpacingY);
glyph_fn(analogyValues[1], 128);
resetMatrix();
translate(analogyOffsetX + 0 * analogySpacingX, analogyOffsetY + 1 * analogySpacingY);
glyph_fn(analogyValues[2], 128);
resetMatrix();
translate(analogyOffsetX + 1 * analogySpacingX, analogyOffsetY + 1 * analogySpacingY);
if(analogyCycleStep == 2) {
glyph_fn(analogyValues[3], 128);
}
else {
stroke(64, 64, 192);
noFill();
if(glyph_fn === glyph4) {
ellipse(64, 64, 128+2);
}
else {
rect(-1, -1, 128+2, 128+2);
}
}
if(analogyCycleStep != 0) {
for(var i=0; i<numAnalogyChoices; i++) {
resetMatrix();
translate(analogyChoiceOffsetX + i * analogyChoiceSpacingX, analogyChoiceOffsetY);
if(analogyCycleStep == 2 && analogyAnswer == i) {
stroke(64, 64, 192);
fill(64, 64, 192);
rect(-6, -6, 64+12, 64+12);
}
glyph_fn(analogyChoices[i], 64);
}
}
}
function draw () {
var mode = modeSelector.value();
if (mode == "drive") {
drawDriveMode();
}
else if (mode == "analogy") {
drawAnalogy();
}
else {
drawGridMode();
}
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment