Bonjour mes amis!Préface
Une fois que la navigation sur le Web m'a conduit à cela .Plus tard, j'ai découvert un article sur la façon dont cela fonctionne.Cela ne semble rien de spécial - Pikachu, dessiné avec CSS. Cette technique est appelée Pixel Art (pixel art?). Ce qui m'a frappé, c'est la complexité du processus. Chaque cellule est peinte manuellement (enfin, presque; car il y a des préprocesseurs; Sass dans ce cas). Bien sûr, la beauté nécessite des sacrifices. Cependant, le développeur est une créature paresseuse. J'ai donc pensé à l'automatisation. Donc, ce que j'ai appelé Pixel Art Maker est apparu.Conditions
Que voulons-nous obtenir?Nous avons besoin d'un programme qui génère un nombre donné de cellules avec la possibilité de les colorer avec des couleurs arbitraires.Voici quelques exemples tirés du Web:Fonctions supplémentaires:- forme de cellule - carré ou cercle
- largeur de cellule en pixels
- nombre de cellules
- Couleur de l'arrière plan
- couleur à colorier
- fonction de création de canevas
- fonction d'affichage du numéro de cellule
- fonction d'enregistrement / suppression d'image
- fonction de nettoyage de la toile
- fonction de suppression de la toile
Nous discuterons de petits détails dans le processus de codage.Alors allons-y.Marquage
Pour implémenter les fonctionnalités nécessaires, notre code HTML devrait ressembler à ceci:
<div class="tools">
<div>
<p>Shape Form</p>
<select>
<option value="squares">Square</option>
<option value="circles">Circle</option>
</select>
</div>
<div class="numbers">
<div>
<p>Shape Width <br> <span>(from 10 to 50)</span></p>
<input type="number" value="20" class="shapeWidth">
</div>
<div>
<p>Shape Number <br> <span>(from 10 to 50)</span></p>
<input type="number" value="30" class="shapeNumber">
</div>
</div>
<div class="colors">
<div>
<p>Background Color</p>
<input type="color" value="#ffff00" required class="backColor">
</div>
<div>
<p>Shape Color</p>
<input type="color" value="#0000ff" class="shapeColor">
</div>
</div>
<div class="buttons">
<input type="button" value="Generate Canvas" class="generate">
<input type="button" value="Show/Hide Numbers" class="show">
<input type="button" value="Save/Delete Image" class="save">
<input type="button" value="Clear Canvas" class="clear">
<input type="button" value="Delete Canvas" class="delete">
</div>
</div>
<canvas></canvas>
La plage (limite) de valeurs pour la largeur et le nombre de cellules a été déterminée empiriquement. Les expériences ont montré que des valeurs plus petites / plus grandes ne sont pas pratiques pour des raisons de détails excessifs (pour des valeurs <10 pour la largeur), de performances réduites (pour des valeurs> 50 pour la quantité), etc.modes
Nous n'avons rien de spécial dans les styles.CSS:* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
align-content: flex-start;
}
h1 {
width: 100%;
text-align: center;
font-size: 2.4em;
color: #222;
}
.tools {
height: 100%;
display: inherit;
flex-direction: column;
margin: 0;
font-size: 1.1em;
}
.buttons {
display: inherit;
flex-direction: column;
align-items: center;
}
div {
margin: .25em;
text-align: center;
}
p {
margin: .25em 0;
user-select: none;
}
select {
padding: .25em .5em;
font-size: .8em;
}
input,
select {
outline: none;
cursor: pointer;
}
input[type="number"] {
width: 30%;
padding: .25em 0;
text-align: center;
font-size: .8em;
}
input[type="color"] {
width: 30px;
height: 30px;
}
.buttons input {
width: 80%;
padding: .5em;
margin-bottom: .5em;
font-size: .8em;
}
.examples {
position: absolute;
top: 0;
right: 0;
}
a {
display: block;
}
span {
font-size: .8em;
}
canvas {
display: none;
margin: 1em;
cursor: pointer;
box-shadow: 0 0 1px #222;
}
Javascript
Définissez le canevas et son contexte (contexte de dessin 2D):let c = document.querySelector('canvas'),
$ = c.getContext('2d')
Nous trouvons le bouton pour créer le canevas et y accrochons le gestionnaire d'événements click:document.querySelector('.generate').onclick = generateCanvas
Tout le code supplémentaire sera dans la fonction generateCanvas:function generateCanvas(){
...
}
Nous déterminons la forme, la largeur, la quantité horizontale et la quantité totale (la toile représente le même nombre de cellules horizontalement et verticalement), ainsi que la couleur de fond:
let shapeForm = document.querySelector('select').value
let shapeWidth = parseInt(document.querySelector('.shapeWidth').value)
let shapeNumber = parseInt(document.querySelector('.shapeNumber').value)
let shapeAmount = Math.pow(shapeNumber, 2)
let backColor = document.querySelector('.backColor').value
Nous déterminons la taille du canevas et définissons les attributs appropriés pour cela (rappelez-vous que la taille de canevas correcte est définie via les attributs):
let W = H = shapeWidth * shapeNumber
c.setAttribute('width', W)
c.setAttribute('height', H)
Quelques paramètres supplémentaires:
let border = 1
let borderColor = 'rgba(0,0,0,.4)'
let isShown = false
if (shapeWidth < 10 || shapeWidth > 50 || shapeNumber < 10 || shapeNumber > 50 || isNaN(shapeWidth) || isNaN(shapeNumber)) {
throw new Error(alert('wrong number'))
} else if (shapeForm == 'squares') {
c.style.display = 'block'
squares()
} else {
c.style.display = 'block'
circles()
}
Voici à quoi ressemble la fonction carrés:function squares() {
let x = y = 0
let squares = []
let w = h = shapeWidth
addSquares()
function Square(x, y) {
this.x = x
this.y = y
this.color = backColor
this.isSelected = false
}
function addSquares() {
for (let i = 0; i < shapeAmount; i++) {
let square = new Square(x, y)
x += w
if (x == W) {
y += h
x = 0
}
squares.push(square)
}
drawSquares()
}
function drawSquares() {
$.clearRect(0, 0, W, H)
for (let i = 0; i < squares.length; i++) {
let square = squares[i]
$.beginPath()
$.rect(square.x, square.y, w, h)
$.fillStyle = square.color
$.lineWidth = border
$.strokeStyle = borderColor
$.fill()
$.stroke()
if (isShown) {
$.beginPath()
$.font = '8pt Calibri'
$.fillStyle = 'rgba(0,0,0,.6)'
$.fillText(i + 1, square.x, (square.y + 8))
}
}
}
c.onclick = select
function select(e) {
let clickX = e.pageX - c.offsetLeft,
clickY = e.pageY - c.offsetTop
for (let i = 0; i < squares.length; i++) {
let square = squares[i]
if (clickX > square.x && clickX < (square.x + w) && clickY > square.y && clickY < (square.y + h)) {
if (square.isSelected == false) {
square.isSelected = true
square.color = document.querySelector('.shapeColor').value
} else {
square.isSelected = false
square.color = backColor
}
drawSquares()
}
}
}
document.querySelector('.show').onclick = showNumbers
function showNumbers() {
if (!isShown) {
isShown = true
for (let i = 0; i < squares.length; i++) {
let square = squares[i]
$.beginPath()
$.font = '8pt Calibri'
$.fillStyle = 'rgba(0,0,0,.6)'
$.fillText(i + 1, square.x, (square.y + 8))
}
} else {
isShown = false
}
drawSquares()
}
}
La fonction cercles est très similaire à la fonction carrés.JavaScript:function circles() {
let r = shapeWidth / 2
let x = y = r
let circles = []
addCircles()
function Circle(x, y) {
this.x = x
this.y = y
this.color = backColor
this.isSelected = false
}
function addCircles() {
for (let i = 0; i < shapeAmount; i++) {
let circle = new Circle(x, y)
x += shapeWidth
if (x == W + r) {
y += shapeWidth
x = r
}
circles.push(circle)
}
drawCircles()
}
function drawCircles() {
$.clearRect(0, 0, W, H)
for (let i = 0; i < circles.length; i++) {
let circle = circles[i]
$.beginPath()
$.arc(circle.x, circle.y, r, 0, Math.PI * 2)
$.fillStyle = circle.color
$.strokeStyle = borderColor
$.lineWidth = border
$.fill()
$.stroke()
if (isShown) {
$.beginPath()
$.font = '8pt Calibri'
$.fillStyle = 'rgba(0,0,0,.6)'
$.fillText(i + 1, (circle.x - 8), circle.y)
}
}
}
c.onclick = select
function select(e) {
let clickX = e.pageX - c.offsetLeft,
clickY = e.pageY - c.offsetTop
for (let i = 0; i < circles.length; i++) {
let circle = circles[i]
let distanceFromCenter = Math.sqrt(Math.pow(circle.x - clickX, 2) + Math.pow(circle.y - clickY, 2))
if (distanceFromCenter <= r) {
if (circle.isSelected == false) {
circle.isSelected = true
circle.color = document.querySelector('.shapeColor').value
} else {
circle.isSelected = false
circle.color = backColor
}
drawCircles()
}
}
}
document.querySelector('.show').onclick = showNumbers
function showNumbers() {
if (!isShown) {
isShown = true
for (let i = 0; i < circles.length; i++) {
let circle = circles[i]
$.beginPath()
$.font = '8pt Calibri'
$.fillStyle = 'rgba(0,0,0,.6)'
$.fillText(i + 1, (circle.x - 8), circle.y)
}
} else {
isShown = false
}
drawCircles()
}
}
Nous trouvons le bouton pour enregistrer / supprimer le résultat (image) et y accrocher le gestionnaire d'événements click:document.querySelector('.save').onclick = () => {
let img = document.querySelector('img')
img == null ? document.body.appendChild(document.createElement('img')).src = c.toDataURL() : document.body.removeChild(img)
}
On retrouve le bouton pour nettoyer la toile et ...:document.querySelector('.clear').onclick = () => {
$.clearRect(0, 0, W, H)
generateCanvas()
}
Trouvez le bouton pour supprimer le canevas et ...:document.querySelector('.delete').onclick = () => {
$.clearRect(0, 0, W, H)
c.style.display = 'none'
}
Le résultat ressemble à ceci:
Codepen (ajouté quelques cas d'utilisation)GithubMerci pour votre attention.