基于HTML5(canvas)、JavaScript实现画布的填充功能
最近由于需求,在canvas画布绘图功能上实现一个填充功能。记录下实现方法,用到了种子填充算法,是基于JavaScript实现的。
一、种子填充算法
网上可以找到很多关于种子填充算法的内容,这里不进行表述。这里借鉴的是“4-联通非递归”方式的一种。
二、逻辑思路
步骤一:
比对鼠标选中的种子点颜色是否与要填充的颜色相同,相同则不进 行填充,直接结束;
步骤二:
使用“‘种子4-联通非递归"算法实现 选中区域的填充
三、代码实现
一. function getDataByCanvasData(cas, ctx, startX, startY, newColor)
其中: cas是画布对象, ctx是cas.getContext(‘2d’) , startX,startY是鼠标选中要填充区域内部的某一点坐标, newColor是要填充的颜色。调用该函数就会将cas画布上选中的区域填充成newColor颜色。
/**
* 使用 漫水填充的种子填充非递归算法((堆的4领域填充)),填充封闭区域
* @param cas 目标画布
* @param ctx 目标画布操作对象
* @param startX 横坐标
* @param startY 纵坐标
* @param newColor 填充的颜色
*/
function getDataByCanvasData(cas, ctx, startX, startY, newColor) {
//获取画布的宽(列数)高(行数)
var width = cas.width;
var height = cas.height;
//获取画布像素信息
var casData = ctx.getImageData(0, 0, width, height);
//第 startY行 第 startX 列的像素所在 ImageData 坐标
var i = startY * width + startX;
//获取原图的种子点颜色值
var colorR = casData.data[4*i];
var colorG = casData.data[4*i+1];
var colorB = casData.data[4*i+2];
//获取填充颜色的RGB数组
var fillingColor = colorHexToRGB(newColor);
//如果当前指定颜色等于要填充的颜色 则直接返回
if(colorR==fillingColor[0] && colorG==fillingColor[1] && colorB==fillingColor[2]){
return ;
}
/** 堆栈 数组使用 push进 Pop出 **/
//列数的堆栈
var stackColumn = new Array();
//行数的堆栈
var stackRow = new Array();
//存储种子点
stackColumn.push(startX);
stackRow.push(startY);
/**
* 检验该点是否是同色点,是的话就将其作为种子点
* @param r 行数
* @param c 列数
* @constructor 返回布尔值
*/
function CheckNewSeed(r, c){
//获取
let n = r * width + c;
//获取原图的 r 行 c列 的RGB像素值
let needColorR = casData.data[4*n+0];
let needColorG = casData.data[4*n+1];
let needColorB = casData.data[4*n+2];
//判断颜色 + 存储种子点://在判断 颜色 是否是 种子点的颜色
if( c>=0 && c <= width && r>=0 && r<= height
&& needColorR == colorR && needColorG== colorG && needColorB ==colorB){
// 若 符合情况 则将该店改颜色
casData.data[4*n] = fillingColor[0];
casData.data[4*n+1] = fillingColor[1];
casData.data[4*n+2] = fillingColor[2];
//并且将其作为种子点
stackRow.push(r);
stackColumn.push(c);
}
}
var c;
var r;
//非递归种子算法
while(true){
//当堆栈中的元素为零时,即 无种子元素 则 退出循环
if(stackColumn.length <= 0){
break;
}
c = stackColumn.pop();
r = stackRow.pop();
CheckNewSeed(r, c);
CheckNewSeed(r + 1, c);
CheckNewSeed(r - 1, c);
CheckNewSeed(r, c + 1);
CheckNewSeed(r, c - 1);
}
ctx.putImageData(casData, 0, 0);
}
二. colorHexToRGB(hex)函数
用于将 16进制颜色值(例 ”#FFFFFF“)转换成RGB的颜色值(例: [255,255,255])。
//十六进制颜色值的正则表达式
var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
/**
* 颜色的 16进制值 转换成 RGB值
* @param hex 颜色的16进制值
* @returns {string|[]} 转成RGB值
*/
function colorHexToRGB(hex){
var that = hex;
var sColor = that.toLowerCase();
//处理六位的颜色值
var sColorChange = [];
if(sColor && reg.test(sColor)){
if(sColor.length === 4){
var sColorNew = "#";
for(var i=1; i<4; i+=1){
sColorNew += sColor.slice(i,i+1).concat(sColor.slice(i,i+1));
}
sColor = sColorNew;
}
for(var i=1; i<7; i+=2){
sColorChange.push(parseInt("0x"+sColor.slice(i,i+2)));
}
return sColorChange;
}else{
return sColorChange;
}
}
四、效果
填充前:
填充后: