您的位置:首页 > 编程语言

Canvas---Canvas版画图、圆角矩形、圆形、矩形、图形填充、mvc模式重新整合代码版

2015-01-27 15:08 337 查看

使用Canvas实现画图程序。(转载注明出处与作者啊)

本次主要更新了一下功能:

新添加图形:矩形,圆形,圆角矩形

实现了描边颜色与填充颜色的选择

使用类似mvc的模式重新整理了代码。

M层: 特殊图形的路径规划代码组成,只包含路径规划,无样式设计。

V层:设计样式,调用路径规划代码,实际绘制图案。在这里完成填充、描边。

C层:判断选择框内容,调用不同的实际绘制代码

其他:事件处理与辅助计算函数等

不足:感觉代码结构还是不够好,果然是我没用面向对象么?

下面是效果图:



下面是源代码:

①本体HTML5代码

<!docutype html>
<!--date 2015-1-27-- by MIKUScallion 首发于CSDN>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style type="text/css">
canvas{
background-color: rgb(247, 247, 247);
margin-top: 10px;
}
</style>
</head>
<body>
<div class="controls">
图案类型<select id="lineTypeSelectBox">
<option value="solid">实线</option>
<option value="dashed">虚线</option>
<option value="arc">圆形</option>
<option value="rect">矩形</option>
<option value="roundedRect">圆角矩形</option>
</select>
描边颜色<select id="strokeColorSelectBox">
<option value="black">black</option>
<option value="red">red</option>
<option value="blue">blue</option>
<option value="rgba(255, 0, 0, 0)">null</option>
</select>
填充颜色<select id="fillColorSelectBox">
<option value="rgba(255, 0, 0, 0)">null</option>
<option value="#7dce96">green</option>
<option value="#db884b">orange</option>
<option value="#d88ba9">pink</option>
</select>
描边宽度<select id="lineWidthSelectBox">
<option value="1">1</option>
<option value="2">2</option>
<option value="4">4</option>
</select>

网格线<input  id="gridCheckBox" type="checkbox" checked="checked" >
坐标轴<input  id="axesCheckBox" type="checkbox" checked="checked" >
辅助线<input  id="guideWiresCheckBox" type="checkbox" checked="checked" >
<input type="button" value="清除画布" id="eraseAllButton">
</div>
<!--canvas默认大小300*150-->
<canvas id="canvas" width="800" height="500">
</canvas>
</body>
<!--导入特殊图形路径规划js文件-->
<script type = "text/javascript" src ="mikuCanvasShapePath.js"></script>
<!--导入主要绘图js文件-->
<script type = "text/javascript" src ="mikuCanvasPaintAppMain.js"></script>
</html>

②特殊图形路径规划代码

//虚线
function dashedLinePP(context,x1,y1,x2,y2,dashLength){
//水平长度
var deltaX = x2 - x1;
//垂直长度
var deltaY = y2 - y1;
//虚线数量
var numDashed = Math.floor(
Math.sqrt(deltaX*deltaX+deltaY*deltaY)/dashLength
);

//开始路径规划
context.beginPath();
for(var i=0; i<numDashed;i++){
//这种写法太强大了
//(deltaX/numDashed)是指虚线的长度
context[i%2===0 ? "moveTo":"lineTo"](x1+(deltaX/numDashed)*i,y1+(deltaY/numDashed)*i);
}
}
//圆角矩形
function roundedRectPP(context,cornerX,cornerY,width,height,cornerRadius){
//开始路径规划
context.beginPath();
//设置开始位置(不是顶点是为了不产生小尾巴)
//为了不产生小尾巴做判断
if(width > 0){
context.moveTo(cornerX+cornerRadius,cornerY);
}else{
context.moveTo(cornerX-cornerRadius,cornerY);
}
//右上角
context.arcTo(cornerX+width,cornerY,cornerX+width,cornerY+height,cornerRadius);
//右下角(注意:由于arcTo的移动,当前点已经到:cornerX+width,cornerY+cornerRadius,所以不要再设置moveTo)
context.arcTo(cornerX+width,cornerY+height,cornerX,cornerY+height,cornerRadius);
//左下角
context.arcTo(cornerX,cornerY+height,cornerX,cornerY,cornerRadius);
//左上角
if(width > 0){
context.arcTo(cornerX,cornerY,cornerX+cornerRadius,cornerY,cornerRadius);
}else{
context.arcTo(cornerX,cornerY,cornerX-cornerRadius,cornerY,cornerRadius);
}
}
//网格线
function gridPP(context,stepx,stepy){
//开始路径规划
context.beginPath();
//绘制x轴网格
//注意:canvas在两个像素的边界处画线
//由于定位机制,1px的线会变成2px
//于是要+0.5
for(var i=stepx+0.5;i<context.canvas.width;i=i+stepx){
//开启路径
//context.beginPath();
context.moveTo(i,0);
context.lineTo(i,context.canvas.height);
}
//绘制y轴网格
for(var i=stepy+0.5;i<context.canvas.height;i=i+stepy){
//context.beginPath();
context.moveTo(0,i);
context.lineTo(context.canvas.width,i);
}
};
//坐标轴
function axesPP(context,axesMargin,htSpace,vtSpace,tickLong){
function mikuLoc(locX,locY){
this.x = locX;
this.y = locY;
}
var originLoc = new mikuLoc(axesMargin, context.canvas.height-axesMargin);
var axesW = context.canvas.width  - (axesMargin*2);
var axesH = context.canvas.height - (axesMargin*2);
context.beginPath();
//x,y轴规划
horizontalAxisPP();
verticalAxisPP();
//x,y轴标签规划
verticalAxisTicksPP();
horizontalAxisTicksPP();

function horizontalAxisPP(){
context.moveTo(originLoc.x, originLoc.y);
context.lineTo(originLoc.x + axesW, originLoc.y);
}
function verticalAxisPP(){
context.moveTo(originLoc.x, originLoc.y);
context.lineTo(originLoc.x, originLoc.y - axesH);
}

function verticalAxisTicksPP(){
var deltaX;
//当前垂直tick的y轴坐标
var nowTickY =originLoc.y-vtSpace;
for(var i=1;i<=(axesH/vtSpace);i++){
if(i%5 === 0){
deltaX=tickLong;
}else {
deltaX=tickLong/2;
}
//移动到当前的tick起点
context.moveTo(originLoc.x-deltaX,nowTickY);
context.lineTo(originLoc.x+deltaX,nowTickY);
nowTickY=nowTickY-vtSpace;
}
}
function horizontalAxisTicksPP(){
var deltaY;
var nowTickX = originLoc.x+htSpace;
for(var i=1;i<=(axesW/htSpace);i++){
if(i%5 === 0){
deltaY = tickLong;
}else{
deltaY = tickLong/2;
}
context.moveTo(nowTickX,originLoc.y+deltaY);
context.lineTo(nowTickX,originLoc.y-deltaY);
nowTickX = nowTickX + htSpace;
}
}
};
//辅助定位线
function guideWiresPP(context,x,y){
context.beginPath();
drawHorizontalLine(y);
drawVerticalLine(x);

function drawHorizontalLine(y){
context.moveTo(0,y+0.5);
context.lineTo(context.canvas.width,y+0.5);
}
function drawVerticalLine(x){
context.moveTo(x+0.5,0);
context.lineTo(x+0.5,context.canvas.height);
}
}

③绘图软件主代码

//Vars--------------------------------------------------------
var canvas =document.getElementById("canvas"),
context =canvas.getContext("2d"),
//正在绘制的绘图表面变量
drawingSurfaceImageData,
//鼠标按下相关对象
mousedown = {},
//橡皮筋矩形对象
rubberbandRect = {},
//当前鼠标坐标
loc ={},
//拖动标识变量
dragging = false;

//控件
//擦除画布的控制
var eraseAllButton = document.getElementById("eraseAllButton");
//坐标轴的控制
var axesCheckBox = document.getElementById("axesCheckBox");
//网格线的控制
var gridCheckBox = document.getElementById("gridCheckBox");
//辅助线的控制
var guideWiresCheckBox = document.getElementById("guideWiresCheckBox");
//线条颜色的控制
var strokeColorSelectBox =document.getElementById("strokeColorSelectBox");
//线条样式的控制
var lineTypeSelectBox = document.getElementById("lineTypeSelectBox");
//线条宽度的控制
var lineWidthSelectBox = document.getElementById("lineWidthSelectBox");
//图案填充色控制
var fillColorSelectBox = document.getElementById("fillColorSelectBox");
//辅助函数--------------------------------------------------------------------------
//将窗口坐标转换为Canvas坐标
function windowToCanvas(x,y){
//获取canvas元素的边距对象
var bbox = canvas.getBoundingClientRect();
//返回一个坐标对象
//类似json的一种写法
return {
x : x - bbox.left*(canvas.width/bbox.width),
y : y - bbox.top*(canvas.height/bbox.height)
};
}

//保存当前绘图表面数据
function saveDrawingSurface(){
//从上下文中获取绘图表面数据
drawingSurfaceImageData = context.getImageData(0,0,canvas.width,canvas.height);
}

//还原当前绘图表面
function restoreDrawingSurface(){
//将绘图表面数据还原给上下文
context.putImageData(drawingSurfaceImageData,0,0);
}

//更新橡皮筋矩形
function updateRubberbandRectangle(){
//获得矩形的宽
rubberbandRect.width = Math.abs(loc.x - mousedown.x);
//获得矩形的高
rubberbandRect.height = Math.abs(loc.y - mousedown.y);
//获得矩形顶点的位置(left,top)
//如果鼠标按下的点(起点)在当前点的的左侧
//这里画一下图就懂了
if(loc.x > mousedown.x){
rubberbandRect.left = mousedown.x;
}else{
rubberbandRect.left = loc.x;
}
if(loc.y > mousedown.y){
rubberbandRect.top = mousedown.y;
}else{
rubberbandRect.top = loc.y;
}
}

//绘制橡皮筋矩形的对角线(控制器)
function drawRubberbandShape(){
//获取当前线条类型
var lineType = lineTypeSelectBox.value;
//获取当前线条颜色
var lineColor = strokeColorSelectBox.value;
//获取当前线条宽度
var lineWidth = lineWidthSelectBox.value;
//获取当前填充颜色
var fillColor = fillColorSelectBox.value;

//有改变context画笔属性就要做画笔保护
context.save();
context.strokeStyle = lineColor;
context.lineWidth = lineWidth;
context.fillStyle = fillColor;

//注意路径规划、样式规划分开
if(lineType === "solid"){
drawLineWithRubberbandRect();
}else if(lineType === "dashed"){
drawDashedLineWithRubberbandRect(5);
}else if(lineType === "arc"){
drawArcWithRubberbandRect();
}else if(lineType === "rect"){
drawRectWithRubberbandRect();
}else if(lineType === "roundedRect"){
drawRoundedRectWithRubberbandRect(20);
}
context.restore();
}

//更新橡皮筋矩形+对角线
function updateRubberband(){
updateRubberbandRectangle();
drawRubberbandShape();
}

//初始化函数
function initialization(){
//清除画布
context.clearRect(0,0,canvas.width,canvas.height);
//绘制网格与坐标的颜色是默认的
if(axesCheckBox.checked){
drawAxes(40);
}
if(gridCheckBox.checked){
drawGrid(10,10);
}
}

//实际绘图函数------------------------------------------------------------------------------
//利用橡皮筋矩形绘制直线
function drawLineWithRubberbandRect(){
context.beginPath();
context.moveTo(mousedown.x,mousedown.y);
context.lineTo(loc.x,loc.y);
context.stroke();
}

//利用橡皮筋矩形绘制圆形
function drawArcWithRubberbandRect(){
//圆的半径
var radius;
var h = rubberbandRect.height;
var w = rubberbandRect.width;
//利用勾股定理计算斜边,就是半径
radius=Math.sqrt(h*h+w*w);
//实际绘制
context.beginPath();
context.arc(mousedown.x,mousedown.y,radius,0,Math.PI*2,false);
context.stroke();
context.fill();
}

//利用橡皮筋矩形绘制矩形(就是画自己)
function drawRectWithRubberbandRect(){
context.beginPath();
context.rect(rubberbandRect.left,rubberbandRect.top,rubberbandRect.width,rubberbandRect.height);
context.stroke();
context.fill();
}

//利用橡皮筋矩形绘制虚线
function drawDashedLineWithRubberbandRect(dashLength){
//路线规划
dashedLinePP(context,mousedown.x,mousedown.y,loc.x,loc.y,dashLength);
context.stroke();
}

//利用橡皮筋矩形绘制圆角矩形
function drawRoundedRectWithRubberbandRect(radius){
//用橡皮筋矩形的数据,做圆角矩形的路径规划
roundedRectPP(context,rubberbandRect.left,rubberbandRect.top,rubberbandRect.width,rubberbandRect.height,radius);
context.stroke();
context.fill();
}

//绘制网格线
function drawGrid(stepx,stepy){
//样式设置
context.save();
context.strokeStyle = "lightgray";
context.lineWidth = 0.5;
gridPP(context,stepx,stepy);
context.stroke();
context.restore();
}

//绘制坐标轴
function drawAxes(axesMargin){
context.save();
context.strokeStyle = "#a2a2a2";
context.lineWidth = 1;
axesPP(context,40,10,10,10);
context.stroke();
context.restore();
}

//绘制辅助定位线
function drawGuideWires(x,y){
context.save();
context.strokeStyle = "red";
context.lineWidth = 0.5;
guideWiresPP(context,x,y);
context.stroke();
context.restore();
}

//Event Hander-----------------------------------------------------

canvas.onmousedown = function(e){
loc =windowToCanvas(e.clientX,e.clientY);
e.preventDefault();
saveDrawingSurface();
mousedown.x = loc.x;
mousedown.y = loc.y;
dragging = true;
}

canvas.onmousemove = function(e){
if(dragging){
e.preventDefault();
loc = windowToCanvas(e.clientX,e.clientY);
restoreDrawingSurface();
updateRubberband();
}
if(dragging&&guideWiresCheckBox.checked){
drawGuideWires(loc.x,loc.y);
}
}

canvas.onmouseup = function(e){
loc = windowToCanvas(e.clientX,e.clientY);
restoreDrawingSurface();
updateRubberband();
dragging = false;
}

//需要擦除的操作需要重新初始化
eraseAllButton.onclick = function(e){
context.clearRect(0,0,canvas.width,canvas.height);
initialization();
saveDrawingSurface();
}

axesCheckBox.onchange = function(e){
initialization();
}

gridCheckBox.onchange = function(e){
initialization();
}

//Mian----------------------------------------------

initialization();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐