Skip to content

Instantly share code, notes, and snippets.

@sgnl
Last active March 27, 2017 22:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sgnl/913efaa9ac13ca5992a40b17c1c4fd25 to your computer and use it in GitHub Desktop.
Save sgnl/913efaa9ac13ca5992a40b17c1c4fd25 to your computer and use it in GitHub Desktop.
OOP PixelPainter - an example for dev league students
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<div id="painter-app"></div>
<script src="/js/painter-app.js"></script>
</body>
</html>
class Pixel {
constructor(color, width, height) {
this.color = color;
this.element = document.createElement('div'); // public DOM access
this.element.classList.add('pixel');
/**
* styling
*/
this.element.style.backgroundColor = this.color;
this.element.style.height = `${height}px`;
this.element.style.width = `${width}px`;
}
}
class Swatch {
constructor(parent, colors) {
// Parent is an instance of Painter class
// we will need to use some public methods
this.parent = parent;
this.currentColor = null;
this.element = document.createElement('div');
this.element.classList.add('swatch');
// create colors
// a Swatch contains many Pixels
colors.forEach(color => {
let colorPixel = new Pixel(color, 30, 30);
this.element.appendChild(colorPixel.element);
});
/**
* events
*/
this.element.addEventListener('click', this.setCurrentColor.bind(this));
}
/**
* public methods
*/
setCurrentColor(e) {
// only care if the the clicked element is an instance of Pixel
// by checking if the element has a class name of `pixel`
if (e.target.classList.contains('pixel')) {
// set the current color of the app via Parent's public method
this.parent.currentColor = e.target.style.backgroundColor;
}
}
}
class Canvas {
constructor(parent, size) {
// Parent is an instance of Painter class
// we will need to use some public methods
this.parent = parent;
this.element = document.createElement('div');
this.element.classList.add('canvas');
let pixelSize = 20;
// a Canvas contains many Pixels
// create canvas { size x size }
for (let i = size; i > 0; i--) {
let rowDiv = document.createElement('div');
rowDiv.classList.add('row');
for (let j = size; j > 0; j--) {
let blankPixel = new Pixel('white', pixelSize, pixelSize);
rowDiv.appendChild(blankPixel.element);
}
this.element.appendChild(rowDiv);
}
/**
* styling
*/
this.element.style.height = `${size * 20}px`;
/**
* events
*/
this.element.addEventListener('click', e => this.setPixelColor(e));
}
/**
* public methods
*/
reset() {
// find all Pixel elements inside of the Canvas grid
// iterate through and set the background-color to 'white'
let canvasPixels = document.querySelectorAll('.canvas .pixel');
canvasPixels.forEach(pixel => pixel.style.backgroundColor = 'white');
}
setPixelColor(e) {
// retrieve color value from public method on Parent class
// and set it to the element which was clicked
e.target.style.backgroundColor = this.parent.currentColor;
}
}
/**
* helper function for creating interactive elements with do 'things'
*/
class Clickable {
// options {
// type: String,
// text: String,
// events: Array[ String{event name}, Function{event handler}]
// }
constructor(parent, options) {
// Parent is an instance of Painter class
// we will need to use some public methods
this.parent = parent;
this.element = document.createElement(options.type);
this.element.innerText = options.text;
// add events dynamically
//
options.events.forEach(eventTuple => {
this.element.addEventListener(eventTuple[0], eventTuple[1]);
});
}
}
class Painter {
constructor(target, size, colors) {
this.element = document.createElement('div');
this.container = document.querySelector(target);
this.element.classList.add('painter-main-app');
this._currentColor = null;
this.swatch = new Swatch(this, colors);
this.canvas = new Canvas(this, size);
this.clearButton = new Clickable(this, {
type: 'button',
text: 'clear',
events: [
['click', e => this.resetCanvas()],
['click', e => console.log('tracking')],
]
});
this.eraseButton = new Clickable(this, {
type: 'button',
text: 'erase',
events: [
['click', e => this.currentColor = 'white']
]
});
this.swatch.element.appendChild(this.clearButton.element);
this.swatch.element.appendChild(this.eraseButton.element);
this.element.appendChild(this.swatch.element);
this.element.appendChild(this.canvas.element);
this.container.appendChild(this.element);
}
/**
* public methods
*/
set currentColor(value) {
this._currentColor = value;
}
get currentColor() {
return this._currentColor;
}
resetCanvas() {
this.canvas.reset();
}
}
/**
* 🎉
*/
new Painter('#painter-app', 10, ['red', 'green', 'yellow', 'blue']);
.pixel {
box-sizing: border-box;
border: 1px solid black;
}
.swatch {
display: flex;
flex-flow: column nowrap;
width: 30%;
}
.swatch .pixel {}
.canvas {
display: flex;
flex-flow: row wrap;
justify-content: flex-start;
}
.painter-main-app {
display: flex;
width: 660px;
margin: 0 auto;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment