Compare commits
15 Commits
master
...
solution_b
Author | SHA1 | Date | |
---|---|---|---|
|
64a8e7a99c | ||
|
ee1ebd4d7c | ||
|
b729be165b | ||
|
5cbbbc70b7 | ||
|
307079543c | ||
|
8f162092f4 | ||
|
330690f972 | ||
|
6433be1b3b | ||
|
7ff3bbd0e1 | ||
|
21bea1f92a | ||
|
6de40658a0 | ||
|
fe80bf0448 | ||
|
f6f51aaedd | ||
|
9ea669d3ba | ||
|
58da59c8a9 |
@ -43,6 +43,15 @@ Research [LocalStorage](https://developer.mozilla.org/en-US/docs/Web/API/Storage
|
|||||||
|
|
||||||
Create a fill tool that will [flood fill](https://en.wikipedia.org/wiki/Flood_fill) boundaries with a chosen paint color.
|
Create a fill tool that will [flood fill](https://en.wikipedia.org/wiki/Flood_fill) boundaries with a chosen paint color.
|
||||||
|
|
||||||
|
### Bonus 5
|
||||||
|
|
||||||
|
Load a PNG file directly onto the canvas using these resources:
|
||||||
|
|
||||||
|
- [FileReader.readAsDataUrl](https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL)
|
||||||
|
- [Canvas.drawImage](https://stackoverflow.com/questions/8751020/how-to-get-a-pixels-x-y-coordinate-color-from-an-image?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
|
||||||
|
- [Image.onload](https://stackoverflow.com/questions/12354865/image-onload-event-and-browser-cache?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
|
||||||
|
- [FileReader example](https://stackoverflow.com/questions/3146483/html5-file-api-read-as-text-and-binary?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
|
||||||
|
- [Get pixel color from Canvas](https://stackoverflow.com/questions/6735470/get-pixel-color-from-canvas-on-mouseover?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa)
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
|
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
<html>
|
||||||
|
<title>Pixel Art Maker</title>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<script defer type="module" src="index.js"></script>
|
||||||
|
</head>
|
||||||
|
<body></body>
|
||||||
|
</html>
|
107
index.js
Normal file
107
index.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
const WIDTH = 48;
|
||||||
|
const HEIGHT = 24;
|
||||||
|
|
||||||
|
// State
|
||||||
|
let brushColor = '';
|
||||||
|
let mouseDown = false;
|
||||||
|
document.body.addEventListener('mouseup', () => mouseDown = false);
|
||||||
|
document.body.addEventListener('mouseenter', () => mouseDown = false);
|
||||||
|
|
||||||
|
// Container
|
||||||
|
const container = document.createElement('div');
|
||||||
|
container.className = 'container';
|
||||||
|
container.style.width = `${WIDTH * 16}px`;
|
||||||
|
|
||||||
|
// Canvas
|
||||||
|
const canvas = document.createElement('div');
|
||||||
|
canvas.className = 'canvas';
|
||||||
|
canvas.addEventListener('mousedown', () => mouseDown = true);
|
||||||
|
const pixels = [];
|
||||||
|
for(let y = 0; y < HEIGHT; y++) {
|
||||||
|
const pxRow = [];
|
||||||
|
const row = document.createElement('div');
|
||||||
|
row.className = 'row';
|
||||||
|
for(let x = 0; x < WIDTH; x++) {
|
||||||
|
const pixel = document.createElement('div');
|
||||||
|
pixel.className = 'pixel';
|
||||||
|
pixel.addEventListener('click', () => pixel.style.backgroundColor = brushColor);
|
||||||
|
pixel.addEventListener('mouseover', () => {
|
||||||
|
if(!mouseDown) return;
|
||||||
|
pixel.style.backgroundColor = brushColor;
|
||||||
|
});
|
||||||
|
row.appendChild(pixel);
|
||||||
|
pxRow.push(pixel);
|
||||||
|
}
|
||||||
|
canvas.appendChild(row);
|
||||||
|
pixels.push(pxRow);
|
||||||
|
}
|
||||||
|
container.appendChild(canvas);
|
||||||
|
|
||||||
|
// Palette
|
||||||
|
const colors = ['#b23232', '#ff4848', '#ff6c6c', '#e59b40', '#ffad48', '#ffc57e', '#e5de40', '#fff748', '#fffa91', '#39cc4b', '#48ff5e', '#91ff9e', '#3248b2', '#4867ff', '#91a3ff', '#6432b2', '#8f48ff', '#bb91ff', '#7c2b99', '#cf48ff', '#e291ff', '#000000', '#323232', '#666666', '#999999', '#cccccc', '#ffffff', '#3a2119', '#512e23', '#754233', '#90675b', '#ac8d84'];
|
||||||
|
const palette = document.createElement('div');
|
||||||
|
palette.className = 'palette';
|
||||||
|
for(let color of colors) {
|
||||||
|
const swatch = document.createElement('div');
|
||||||
|
swatch.className = 'swatch';
|
||||||
|
swatch.style.backgroundColor = color;
|
||||||
|
swatch.addEventListener('click', () => {
|
||||||
|
brushColor = color;
|
||||||
|
title.style.backgroundColor = color;
|
||||||
|
});
|
||||||
|
palette.appendChild(swatch);
|
||||||
|
}
|
||||||
|
const title = document.createElement('h2');
|
||||||
|
title.innerText = 'BRUSH COLOR';
|
||||||
|
palette.appendChild(title);
|
||||||
|
container.appendChild(palette);
|
||||||
|
|
||||||
|
// File reader
|
||||||
|
/*
|
||||||
|
<input type='file' id='fileinput'>
|
||||||
|
<input type='button' id='btnLoad' value='Load' onclick='loadFile();'>
|
||||||
|
*/
|
||||||
|
const fileDiv = document.createElement('div');
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.setAttribute('type', 'file');
|
||||||
|
fileDiv.appendChild(fileInput);
|
||||||
|
const btnLoad = document.createElement('input');
|
||||||
|
btnLoad.setAttribute('type', 'button');
|
||||||
|
btnLoad.setAttribute('value', 'Load');
|
||||||
|
btnLoad.addEventListener('click', () => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', () => {
|
||||||
|
const img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.setAttribute('visibility', 'hidden');
|
||||||
|
canvas.width = img.width;
|
||||||
|
canvas.height = img.height;
|
||||||
|
document.body.appendChild(canvas);
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(img, 0, 0, img.width, img.height);
|
||||||
|
for(let y = 0; y < img.height / 16; y++) {
|
||||||
|
for(let x = 0; x < img.width / 16; x++) {
|
||||||
|
const p = ctx.getImageData(x * 16 + 8, y * 16 + 8, 1, 1).data;
|
||||||
|
const hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
|
||||||
|
if(y >= pixels.length) continue;
|
||||||
|
if(x >= pixels[y].length) continue;
|
||||||
|
pixels[y][x].style.backgroundColor = hex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.body.removeChild(canvas);
|
||||||
|
};
|
||||||
|
img.src = reader.result;
|
||||||
|
}, false);
|
||||||
|
reader.readAsDataURL(fileInput.files[0]);
|
||||||
|
});
|
||||||
|
fileDiv.appendChild(btnLoad);
|
||||||
|
|
||||||
|
function rgbToHex(r, g, b) {
|
||||||
|
if (r > 255 || g > 255 || b > 255)
|
||||||
|
throw "Invalid color component";
|
||||||
|
return ((r << 16) | (g << 8) | b).toString(16);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.body.appendChild(container);
|
||||||
|
document.body.appendChild(fileDiv);
|
BIN
sprite.png
Normal file
BIN
sprite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
55
style.css
Normal file
55
style.css
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-family: "Gill Sans";
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: rgb(153, 153, 153);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 15px;
|
||||||
|
background-color: rgb(229, 229, 229);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pixel {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border: 1px solid rgb(229, 229, 229);
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
background-color: rgb(229, 229, 229);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swatch {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
border: 1px solid rgb(187, 187, 187);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.currentSwatch {
|
||||||
|
width: 50px;
|
||||||
|
height: 35px;
|
||||||
|
display: flex;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user