Skip to content

Instantly share code, notes, and snippets.

@dribnet
Last active January 27, 2022 03:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 66 You must be signed in to fork a gist
  • Save dribnet/94327e00769397284a442537b68aaec0 to your computer and use it in GitHub Desktop.
Save dribnet/94327e00769397284a442537b68aaec0 to your computer and use it in GitHub Desktop.
MDDN242 Assignment 3: Glyph
license: mit

PS3 MDDN 242 2018

Color Glyphs

Describe your black and white shapes that are meant to represent the colors above them (replacing this text). Be sure to use complete sentences, and you can reference your image above. The explanation should be short but compete, roughly 100 words.

Also update both images keeping their original sizes: preview.jpg (960x500) and thumbnail.png (230x120).

/* change default application behavior */
var defaultMode = "sketch";
var defaultSize = 128;
var defaultDisplay = "both"
var defaultEmoji = 100;
var backgroundColor = "hsb(0, 0%, 94%)";
function Glyph() {
/*
* values is an array of 3 numbers: [hue, saturation, lightness]
* + hue ranges from 0..360
* + saturation ranges from 0..100
* + lightness ranges from 0..100
*
* size is the number of pixels for width and height
*
* use p5.js to draw a round grayscale glyph
* the glyph should stay within the ellipse [0, 0, width, height]
* this is a grayscale glyph, so only lightness can be adjusted.
* the range for lightness is 0..100
*
* When setting the lightness of stroke or fill always use either strokeUniform()
* or fillUniform() calls. Each takes one arguement - the lightness from
* 0 to 100. Examples:
* - fillUniform(50); // ranges from 0-100
* - strokeUniform(100); // white
*/
this.draw = function(values, size) {
// replace this with your own version
// map lightness to large circle shade
let color1 = map(values[2], 0, 100, 10, 70)
strokeUniform(color1);
fillUniform(color1)
let s2 = size/2;
ellipse(s2, s2, size);
// inner size is set to 30%
let inner_size = 0.2 + 0.4 * 0.3;
let s3 = size * inner_size;
// inner color based on saturation
let color2 = map(values[1], 0, 100, color1+20, 240)
fillUniform(color2);
strokeUniform(color2);
// hue controls left/right shift
let shift_frac = (values[0] - 180.0) / 180.0;
let max_shift = 0.5 * (size - s3);
let x_shift = shift_frac * max_shift;
ellipse(s2 + x_shift, s2, s3);
}
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/p5.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.6.0/addons/p5.dom.js"></script>
<script src="z_hsluv-0.0.3.min.js" type="text/javascript"></script>
<script language="javascript" type="text/javascript" src="z_purview_helper.js"></script>
<script language="javascript" type="text/javascript" src="z_color_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.0;
-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>Hue</td>
<td id="slider1Container"></td>
</tr>
<tr>
<td>Saturation</td>
<td id="slider2Container"></td>
</tr>
<tr>
<td>Lightness</td>
<td id="slider3Container"></td>
</tr>
<tr>
<td>
<hr>
</td>
</tr>
<tr>
<td>Mode</td>
<td id="selector1Container"></td>
</tr>
<tr>
<td>Size</td>
<td id="selector3Container"></td>
</tr>
<tr>
<td>Display</td>
<td id="selector2Container"></td>
</tr>
<tr>
<td>Show Guide</td>
<td id="checkContainer"></td>
</tr>
<tr>
<td></td>
<td id="buttonContainer"></td>
</tr>
</div>
</div>
</table>
</body>
{
"commits": [
{
"sha": "741659ce99f24eafa34c93e3973750eb54623250",
"name": "final example: (double spinner)"
},
{
"sha": "40acba7243a32d2d6b107dfc7ae61914eb8487e6",
"name": "final example (spinner)"
},
{
"sha": "906be590e037ccc57c608cf6725c2d0c712ee9e9",
"name": "gradient example (spinner)"
},
{
"sha": "83a0dd1aa6d94f9703d917d12e81ba93b6dea111",
"name": "random example2: button"
},
{
"sha": "b004b13c84f46572bff37901a0e4d7fe4f035ee0",
"name": "random example1: spinner"
},
{
"sha": "0b61a1a2e34cd5c5fecfde3fafec155fc6f7503e",
"name": "sketch example"
}
]
}
if (typeof defaultMode === 'undefined') {
var defaultMode = "sketch";
}
if (typeof defaultSize === 'undefined') {
var defaultSize = "128";
}
if (typeof defaultDisplay === 'undefined') {
var defaultDisplay = "both";
}
if (typeof defaultEmoji === 'undefined') {
var defaultDisplay = 76;
}
if (typeof backgroundColor === 'undefined') {
var backgroundColor = "rgb(232, 232, 232)";
}
let canvasWidth = 960;
let canvasHeight = 500;
let glyphSelector;
let modeSelector;
let sizeSelector;
let show_oddball = false;
let oddball_row = 0;
let oddball_col = 0;
let val_sliders = [];
let max_vals = [360, 100, 100];
let curEmoji = defaultEmoji;
let NUM_EMOJI = 872;
let EMOJI_WIDTH = 38;
let lastKeyPressedTime;
let secondsUntilSwapMode = 10;
let secondsPerEmoji = 5;
let isSwappingEmoji = false;
let emojiSwapLerp = 0;
let prevEmoji = 0;
let lastEmojiSwappedTime;
let emojiImg;
let sketchImg;
let curEmojiImg;
let curEmojiPixels;
let curEmojiColors, nextEmojiColors, prevEmojiColors;
function preload() {
emojiImg = loadImage("twemoji36b_montage.png");
sketchImg = loadImage("sketch.png");
}
function setup() {
// create the drawing canvas, save the canvas element
let main_canvas = createCanvas(canvasWidth, canvasHeight);
main_canvas.parent('canvasContainer');
let now = millis();
lastKeyPressedTime = now;
lastEmojiSwappedTime = now;
// create two sliders
for (i=0; i<3; i++) {
let slider = createSlider(0, 10*max_vals[i], 10*max_vals[i]/2);
slider.parent("slider" + (i+1) + "Container")
slider.changed(sliderUpdated);
slider.mouseMoved(sliderUpdated);
slider.touchMoved(sliderUpdated);
val_sliders.push(slider);
}
modeSelector = createSelect();
modeSelector.option('sketch');
modeSelector.option('edit');
modeSelector.option('random');
modeSelector.option('gradient');
modeSelector.option('oddball');
modeSelector.option('image');
modeSelector.changed(modeChangedEvent);
modeSelector.value(defaultMode);
modeSelector.parent('selector1Container');
glyphSelector = createSelect();
glyphSelector.option('color');
glyphSelector.option('glyph');
glyphSelector.option('both');
glyphSelector.value(defaultDisplay);
glyphSelector.parent('selector2Container');
sizeSelector = createSelect();
sizeSelector.option('32');
sizeSelector.option('64');
sizeSelector.option('128');
sizeSelector.parent('selector3Container');
sizeSelector.value(defaultSize);
sizeSelector.changed(sizeChangedEvent);
guideCheckbox = createCheckbox('', false);
guideCheckbox.parent('checkContainer');
guideCheckbox.changed(guideChangedEvent);
button = createButton('redo');
button.mousePressed(buttonPressedEvent);
button.parent('buttonContainer');
curEmojiImg = createImage(36, 36);
// create an array for HSB values: [18][18][3]
curEmojiPixels = Array(18);
curEmojiColors = Array(18);
for(let i=0; i<18; i++) {
curEmojiPixels[i] = Array(18);
curEmojiColors[i] = Array(18);
for(let j=0; j<18; j++) {
curEmojiPixels[i][j] = Array(3);
}
}
gray_glyph = new Glyph();
refreshGridData();
modeChangedEvent();
}
function sliderUpdated() {
redraw();
}
function mouseClicked() {
if (mouseX > width/4) {
refreshGridData();
}
redraw();
}
function dataInterpolate(data1, data2, val) {
let d = new Array(3);
for(let i=0; i<3; i++) {
d[i] = lerp(data1[i], data2[i], val);
}
return d;
}
let numGridRows;
let numGridCols;
let gridValues; // row, col order
let gridOffsetX, gridOffsetY;
let gridSpacingX, gridSpacingY;
// Generate data for putting glyphs in a grid
function clamp(num, min, max) {
return Math.min(Math.max(num, min), max);
}
function refreshGridData() {
let mode = modeSelector.value();
let glyphSize = parseInt(sizeSelector.value(), 10);
if (mode == "image") {
if(glyphSize == 32) {
numGridCols = 18;
numGridRows = 17;
gridOffsetX = 320;
gridSpacingX = 31;
gridOffsetY = 2;
gridSpacingY = 29;
}
else if(glyphSize == 64) {
numGridCols = 10;
numGridRows = 9;
gridOffsetX = 280;
gridSpacingX = 66;
gridOffsetY = -18;
gridSpacingY = 59;
}
else if(glyphSize == 128) {
numGridCols = 6;
numGridRows = 5;
gridOffsetX = 164;
gridSpacingX = 132;
gridOffsetY = -50;
gridSpacingY = 118;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 3;
gridOffsetX = 172;
gridSpacingX = 262;
gridOffsetY = -100;
gridSpacingY = 234;
}
}
else if(glyphSize == 128) {
numGridCols = 6;
numGridRows = 3;
gridOffsetX = 38;
gridSpacingX = 156;
gridOffsetY = 32;
gridSpacingY = 166;
}
else if(glyphSize == 256) {
numGridCols = 3;
numGridRows = 1;
gridOffsetX = 20;
gridSpacingX = 320;
gridOffsetY = 100;
gridSpacingY = 500;
}
else if(glyphSize == 64) {
numGridCols = 12;
numGridRows = 6;
gridOffsetX = 15;
gridSpacingX = 78;
gridOffsetY = 15;
gridSpacingY = 81;
}
else if(glyphSize == 32) {
numGridCols = 21;
numGridRows = 11;
gridOffsetX = 22;
gridSpacingX = 44;
gridOffsetY = 22;
gridSpacingY = 42;
}
gridValues = new Array(numGridRows);
for (let i=0; i<numGridRows; i++) {
gridValues[i] = new Array(numGridCols);
for (let j=0; j<numGridCols; j++) {
gridValues[i][j] = new Array(8);
}
}
if (mode == "gradient" || mode == 'oddball') {
let top_left = Array(3);
let top_right = Array(3);
let bottom_left = Array(3);
let bottom_right = Array(3);
for (let k=0; k<3; k++) {
top_left[k] = random(max_vals[k]);
top_right[k] = random(max_vals[k]);
bottom_left[k] = random(max_vals[k]);
bottom_right[k] = random(max_vals[k]);
}
for (let i=0; i<numGridRows; i++) {
let frac_down = 0;
if(numGridRows != 1) {
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 (let j=0; j<numGridCols; j++) {
let frac_over = 0;
if(numGridCols != 0) {
frac_over = j / (numGridCols - 1.0);
}
gridValues[i][j] = dataInterpolate(d_left, d_right, frac_over);
}
}
if (mode == 'oddball') {
// replace an entry at random
oddball_row = Math.floor(random(numGridRows))
oddball_col = Math.floor(random(numGridCols))
for (let k=0; k<3; k++) {
gridValues[oddball_row][oddball_col][k] = random(max_vals[k]);
}
}
}
else if(mode == "image") {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
for (let k=0; k<3; k++) {
gridValues[i][j][k] = curEmojiPixels[i][j][k];
}
}
}
}
else {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
for (let k=0; k<3; k++) {
gridValues[i][j][k] = random(max_vals[k]);
}
}
}
}
}
function sizeChangedEvent() {
let mode = modeSelector.value();
if (mode != 'edit') {
refreshGridData();
}
redraw();
}
function guideChangedEvent() {
show_oddball = guideCheckbox.checked();
redraw();
}
function modeChangedEvent() {
let mode = modeSelector.value();
// enable/disable sliders
if (mode === 'edit') {
// disable the button
// button.attribute('disabled','');
// enable the size selector
sizeSelector.removeAttribute('disabled');
// enable the first four sliders
for(let i=0; i<3; i++) {
val_sliders[i].removeAttribute('disabled');
}
}
else {
// enable the button
// button.removeAttribute('disabled');
// disable the sliders
for(let i=0; i<3; i++) {
val_sliders[i].attribute('disabled','');
}
// enable the size selector
// sizeSelector.removeAttribute('disabled');
// refresh data
refreshGridData();
}
if (mode === "image") {
// get current emoji image
let offsetX = 36 * (curEmoji % 38);
let offsetY = 36 * Math.floor(curEmoji / 38);
let squareOffsets = [ [0,0], [0,1], [1,1], [1, 0] ];
curEmojiImg.copy(emojiImg, offsetX, offsetY, 36, 36, 0, 0, 36, 36);
curEmojiImg.loadPixels();
for(let i=0; i<17; i++) {
// i is y
let maxX = 18;
let offsetX = 0;
if (i%2 == 1) {
maxX = 17;
offsetX = 1;
}
for(let j=0; j<maxX; j++) {
// j is x
let sumColor = [0, 0, 0];
for(let k=0; k<4; k++) {
// k is summing over 4 adacent pixels
let curColor = curEmojiImg.get(j*2 + squareOffsets[k][0] + offsetX, 1 + i*2 + squareOffsets[k][1]);
for(let l=0; l<3; l++) {
sumColor[l] += curColor[l] / 4.0;
}
}
let curColor = color(sumColor);
curEmojiColors[i][j] = curColor;
let rgba = curColor._array;
let rgb = [ rgba[0], rgba[1], rgba[2] ];
let hscol = hsluv.rgbToHsluv(rgb);
curEmojiPixels[i][j][0] = hscol[0];
curEmojiPixels[i][j][1] = hscol[1];
curEmojiPixels[i][j][2] = hscol[2];
}
}
// refresh data
refreshGridData();
}
redraw();
}
function buttonPressedEvent() {
refreshGridData();
redraw();
}
// function fillHsluv(h, s, l) {
// var rgb = hsluv.hsluvToRgb([h, s, l]);
// fill(rgb[0] * 255, rgb[1] * 255, rgb[2] * 255);
// }
function ColorGlyph() {
this.draw = function(values, size) {
let rgb = hsluv.hsluvToRgb(values);
fillHsluv(values[0], values[1], values[2]);
// print(values);
// fill(rgb[0]*255, rgb[1]*255, rgb[2]*255);
stroke(0);
let s2 = size/2;
ellipse(s2, s2, size);
}
}
let color_glyph = new ColorGlyph();
function highlightGlyph(glyphSize) {
let halfSize = glyphSize / 2.0;
stroke(0, 0, 255, 128);
noFill();
strokeWeight(4);
ellipse(halfSize, halfSize, glyphSize+4);
fill(0);
strokeWeight(1);
}
function getGyphObject() {
return gray_glyph;
}
function drawGlyph(glyphValues, glyphSize) {
let shawdowShift = glyphSize / 5.0;
let glyphMode = glyphSelector.value();
if(glyphMode != "glyph") {
translate(-shawdowShift, -shawdowShift);
color_glyph.draw(glyphValues, glyphSize);
translate(shawdowShift, shawdowShift);
}
if(glyphMode != "color") {
gray_glyph.draw(glyphValues, glyphSize);
}
}
function drawDriveMode() {
let glyphSize = 320;
let halfSize = glyphSize / 2;
background(backgroundColor);
let middle_x = canvasWidth / 2;
let middle_y = canvasHeight / 2;
middle_x = middle_x + glyphSize / 10.0;
middle_y = middle_y + glyphSize / 10.0;
let val = [0,0,0];
for(i=0; i<3; i++) {
val[i] = val_sliders[i].value() / 10.0;
}
resetMatrix();
translate(middle_x - halfSize, middle_y - halfSize);
drawGlyph(val, glyphSize);
if (show_oddball) {
resetMatrix();
translate(middle_x - halfSize, middle_y - halfSize);
highlightGlyph(glyphSize)
}
// resetMatrix();
// translate(middle_x + halfSize + 32, middle_y - halfSize);
// color_glyph.draw(val, glyphSize);
}
function drawGridMode() {
let mode = modeSelector.value();
let glyphSize = parseInt(sizeSelector.value(), 10);
background(backgroundColor);
if (show_oddball && mode == 'oddball') {
resetMatrix();
translate(gridOffsetX + oddball_col * gridSpacingX, gridOffsetY + oddball_row * gridSpacingY);
highlightGlyph(glyphSize)
}
let hexOffset = (mode == "image");
for (let i=0; i<numGridRows; i++) {
let tweakedNumGridCols = numGridCols;
let offsetX = 0;
if (hexOffset && i%2 == 1) {
offsetX = gridSpacingX / 2;
tweakedNumGridCols = numGridCols - 1;
}
for (let j=0; j<tweakedNumGridCols; j++) {
resetMatrix();
translate(gridOffsetX + j * gridSpacingX + offsetX, gridOffsetY + i * gridSpacingY);
drawGlyph(gridValues[i][j], glyphSize);
resetMatrix();
}
}
}
function colorCopyArray(c) {
d = Array(18);
for(let i=0; i<18; i++) {
d[i] = Array(18);
for(let j=0; j<18; j++) {
d[i][j] = c[i][j];
}
}
return d;
}
function checkImageUpdate() {
let mode = modeSelector.value();
isSwappingEmoji = false;
if (mode == "image") {
now = millis();
if(lastKeyPressedTime + 1000 * secondsUntilSwapMode < now) {
// key not pressed recently
if(lastEmojiSwappedTime + 1000 * secondsPerEmoji < now) {
prevEmoji = curEmoji;
prevEmojiColors = colorCopyArray(curEmojiColors);
// no swaps recently
updateEmoji(1);
nextEmojiColors = colorCopyArray(curEmojiColors);
lastEmojiSwappedTime = now;
}
if(now - lastEmojiSwappedTime < 1000) {
isSwappingEmoji = true;
emojiSwapLerp = (now - lastEmojiSwappedTime) / 1000.0;
// print("LERP: " + emojiSwapLerp);
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
// let curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
let curColor = prevEmojiColors[i][j];
if (curColor) {
curColor = lerpColor(prevEmojiColors[i][j], nextEmojiColors[i][j], emojiSwapLerp);
curEmojiPixels[i][j][0] = curColor._getHue();
curEmojiPixels[i][j][1] = curColor._getSaturation();
curEmojiPixels[i][j][2] = curColor._getBrightness();
}
}
}
refreshGridData();
}
else {
for (let i=0; i<numGridRows; i++) {
for (let j=0; j<numGridCols; j++) {
let curColor = nextEmojiColors[i][j];
if (curColor) {
curEmojiPixels[i][j][0] = curColor._getHue();
curEmojiPixels[i][j][1] = curColor._getSaturation();
curEmojiPixels[i][j][2] = curColor._getBrightness();
}
}
}
refreshGridData();
}
}
}
}
let is_drawing = false;
function draw () {
if (is_drawing) {
return;
}
is_drawing = true;
let mode = modeSelector.value();
if (mode == "sketch") {
image(sketchImg, 0, 0, width, height);
is_drawing = false;
return;
}
checkImageUpdate();
if (mode == 'edit') {
drawDriveMode();
}
else {
drawGridMode();
}
resetMatrix();
if (mode == "image") {
image(curEmojiImg, 96, height-32-36);
}
is_drawing = false;
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
else if (key == '@') {
saveBlocksImages(true);
}
else if (key == ' ') {
refreshGridData();
redraw();
}
else if (key == 'd') {
let curGlyph = glyphSelector.value()
if(curGlyph == "color") {
glyphSelector.value('glyph');
}
else if(curGlyph == "glyph") {
glyphSelector.value('both');
}
else if(curGlyph == "both") {
glyphSelector.value('color');
}
redraw();
}
else if (key == 'c') {
let old_value = guideCheckbox.checked();
guideCheckbox.checked(!old_value);
guideChangedEvent();
}
else if (key == '1') {
sizeSelector.value('32');
sizeChangedEvent()
}
else if (key == '2') {
sizeSelector.value('64');
sizeChangedEvent()
}
else if (key == '3') {
sizeSelector.value('128');
sizeChangedEvent()
}
else if (key == 's') {
modeSelector.value('sketch');
modeChangedEvent()
}
else if (key == 'e') {
modeSelector.value('edit');
modeChangedEvent()
}
else if (key == 'g') {
modeSelector.value('gradient');
modeChangedEvent()
}
else if (key == 'r') {
modeSelector.value('random');
modeChangedEvent()
}
else if (key == 'o') {
modeSelector.value('oddball');
modeChangedEvent()
}
else if (key == 'i') {
modeSelector.value('image');
modeChangedEvent()
}
}
function updateEmoji(offset) {
curEmoji = (curEmoji + NUM_EMOJI + offset) % NUM_EMOJI;
modeChangedEvent()
}
function keyPressed() {
lastKeyPressedTime = millis();
if (keyCode == LEFT_ARROW) {
updateEmoji(-1);
}
else if (keyCode == RIGHT_ARROW) {
updateEmoji(1);
}
else if (keyCode == UP_ARROW) {
updateEmoji(-38);
}
else if (keyCode == DOWN_ARROW) {
updateEmoji(38);
}
}
function mouseMoved() {
lastKeyPressedTime = millis();
}
function mouseDragged() {
lastKeyPressedTime = millis();
}
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment