用JS制作的像素画板,一起来画像素画吧~

2,072 阅读5分钟

我正在参加「码上掘金挑战赛」详情请看:码上掘金挑战赛来了!

前言

终于等到了掘金的码上掘金活动!带着激动的心敲出了这个

我在敲代码之余也在做一些像素画,于是心想能不能将我们熟悉的PS界面取下一部分放到浏览器页面里呢?

像素画的重点在于概括,但一个好的像素画是需要一点颜色上的渐变来描述它的阴影,不过我迫于时间精力与个人技术不足等原因没有把调色板搞出来,仅放上了一些较为常用的颜色

演示

代码解读

image.png

正式开始解读代码前我们先画一个小熊,不为别的,就是觉得很可爱

HTML框架与CSS样式

HTML

    <div id="main">
        <div id="draw"></div>             <!-- 画板 -->
        <div id="tools">                  <!-- 侧边工具栏(选色器) -->
            <div id="now-color"></div>    <!-- 展示现在选中的颜色 -->
            <ul id="color-list"></ul>     <!-- 展示所有可用颜色 -->
        </div>
    </div>
    <div class="button-group">
        <button id="show-hide-line">展示/隐藏网格</button>
        <button id="clear">清空</button>
    </div>

CSS

        #main {
            display: flex;
            flex-direction: row;
            width: 900px;
            margin: 0 auto;
        }

        #draw {
            width: 640px;
            height: 640px;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
            margin: 0 auto;
            border: 1px solid rgb(211, 211, 211);
        }

        .pixel-line {
            width: 38px;
            height: 38px;
            border: 1px solid rgb(211, 211, 211);
        }

        .pixel {
            width: 40px;
            height: 40px;
        }

        .button-group {
            width: 200px;
            margin: 0 auto;
        }

        .button-group button {
            float: left;
        }

        #color-list {
            display: flex;
            flex-direction: column;
            flex-wrap: wrap;
        }

        #tools {
            width: 20%;
        }

        .color-item {
            height: 20px;
            width: 20px;
        }

        #now-color {
            width: 80px;
            height: 80px;
            border: 1px solid rgb(147, 147, 147);
        }

        button {
            height: 30px;
            width: 100px;
            border-radius: 15px;
        }

        li {
            list-style: none;
            margin-bottom: 3px;
            display: block;
            box-sizing: border-box;
        }
  • 整个HTML框架并没有太多的东西, 因为有太多的事件与重复的组件,因此大多步骤都在JS中完成
  • .pixel-line为“显示网格”时添加的CSS样式,与此相对应的pixel是“隐藏网格”时添加的CSS样式

创建像素画画板

let box = []
let color = '#000'                           //为color赋初值,后续仍会更改
var draw = document.getElementById('draw')   //获取画板元素节点

for (let i = 0; i < 16; i++) {               //创建像素点16*16
    for (let j = 0; j < 16; j++) {
        box.push(document.createElement("div"))
    }
}
for (let i = 0; i < box.length; i++) {
    box[i].className = 'pixel-line'          //为元素添加class
    box[i].onclick = function () {
        box[i].style.backgroundColor = color //点击后将背景色改变为目前color的值
    }
    draw.appendChild(box[i])                 //将像素块逐一挂载
}
  • 整个画板是使用16 * 16个div所构成的,每个div上都被绑定了相应的点击事件
  • 创建画板的流程大致为:开始 -> 创建元素节点 -> 将元素节点放入数组内方便后续管理 -> 为数组内的元素节点添加class名与点击事件 -> 将元素挂载至HTML中 -> 结束
  • 点击事件也可仅为外层容器添加,我这里是给每个元素逐一添加,更加方便理解
  • box[i].style.backgroundColor = color是指将背景色改为color,其中color的值初始为黑色,在下一模块“创建右侧色彩列表”中选中某一颜色后color后会发生更改,以达到切换画笔颜色的效果
  • box[i].className = 'pixel-line'是指初始时默认网格是显示的,如上一部分“HTML框架与CSS”中所说的那样,该class会给元素加上border与一个合适的宽高

其余详细内容请看代码注释

创建右侧色彩列表

var colorList = document.getElementById('color-list')//获取颜色列表结点
var nowColor = document.getElementById('now-color')//获取当前所选颜色元素节点
//color变量在上一模块已被创建

let colors = ['#FFF', '#000', '#FF0000', '#FFFF00', '#008B8B', '#7FFFD4', '#0000FF', 
'#8A2BE2', '#A52A2A', '#7FFF00', '#FF7F50', '#6495ED', '#DC143C', '#00FFFF', '#B8860B',
'#A9A9A9', '#006400', '#FFDAB9', '#8B008B', '#FF00FF', '#483D8B', '#2F4F4F', '#D2B48C']
// ↑ 颜色列表 ↑
for (let i = 0; i < colors.length; i++) {
    let colorItem = document.createElement("li")  //创建元素节点li
    colorItem.className = 'color-item'            //为元素节点添加class
    colorItem.style.backgroundColor = colors[i]   //为元素节点添加背景色
    colorItem.onclick = function () {
        color = colors[i]                         //当选中该元素节点所代表的颜色时,将color的值变为当前所遍历到的colos[i]的值
        nowColor.style.backgroundColor = colors[i]//当选中该元素节点所代表的颜色时,将展示目前所选中颜色的元素节点背景色改为当前所遍历到的colors[i]的值
    }
    if (i === 0) {
        colorItem.style.border = '1px solid #000000'//如果是第一个,则需要添加板框,因为第一个是白色
    }
    colorList.appendChild(colorItem)               //将颜色列表逐一挂载
}
  • 因为没有做调色板,所以我们需要将所需要的颜色列出来,并存储为一个数组colors
  • 我认为将选中颜色高亮或添加边框的话不够突出,因此我使用了一般绘图软件所采用的方法:将所选颜色放大并展示在另一个醒目位置
  • 白色与背景色相同,因此需要给白色添加一个边框以让它能被我们看见
  • 选中颜色后,color将会发生改变,因此在上一模块“创建像素画板”中每个像素点所绑定的点击事件将会发生改变,以达到切换画笔颜色的效果

其余详细内容请看代码注释

为下方按钮组绑定事件

var lineButton = document.getElementById('show-hide-line')
var clearButton = document.getElementById('clear')

let showLine = true
lineButton.onclick = function () {      //显示隐藏网格按钮
    if (showLine) {
        changeClass(box, 'pixel')       //如果正在显示网格,则隐藏网格并将showLine复制为false
        showLine = false
    } else {
        changeClass(box, 'pixel-line')  //如果正在隐藏网格,则显示网格并将showLine赋值为true
        showLine = true
    }
}
clearButton.onclick = function () {     //清空按钮
    for (let i = 0; i < box.length; i++) {
        box[i].style.backgroundColor = '#fff'  //遍历box并将他们的背景色全部改为白色,box是存放所有像素点的数组
    }
}

function changeClass(arr, className) {  //遍历第一个形参并将每一项的className改为第二个形参的函数
    for (let i = 0; i < arr.length; i++) {
        arr[i].className = className
    }
}
  • 当点击显示隐藏网格按钮时,若正在显示网格则将所有像素点的class改为pixel,反之则改为pixel-line
  • 当点击清空按钮时,将所有像素点的背景色统一改为白色

其余详细内容请看代码注释

这样所有的部分都已经介绍完啦~祝大家中秋节快乐!