HTML5游戏开发(五)

时间:2022-11-17 15:22:29

HTML5游戏开发(五)

一、绘制仪表盘

主用于圆形刻度练习。

(一)绘制基本功能

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>线段</title>
<style>
body {
background: #283c3c;
}

#canvas {
background: #f0fff0;
border: thin solid #FFFFCC;
}

</style>
</head>
<body>
<canvas id='canvas' width='600' height='500'>
</canvas>
<script src="js/meter.js"></script>
</body>
</html>

JavaScript脚本

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
CENTROID_RADIUS = 10, //中心点半径
CENTROID_STROKE_STYLE = 'rgba(0, 0, 0, 0.5)', //中心点样式
CENTROID_FILL_STYLE = 'rgba(80, 190, 240, 0.6)', //中心点填充样式

RING_INNER_RADIUS = 35, //内圆环半径
RING_OUTER_RADIUS = 55, //外圆环半径

ANNOTATIONS_FILL_STYLE = 'rgba(0, 0, 230, 0.9)', //数字标记样式
ANNOTATIONS_TEXT_SIZE = 12, //数据标记字体大小

TICK_WIDTH = 10, //标记线粗细
TICK_LONG_STROKE_STYLE = 'rgba(100, 140, 230, 0.9)',//标记线长线样式
TICK_SHORT_STROKE_STYLE = 'rgba(100, 140, 230, 0.7)',//标记线短线样式

TRACKING_DIAL_STROKING_STYLE = 'rgba(100, 140, 230, 0.5)', //数字标记样式

GUIDEWIRE_STROKE_STYLE = 'goldenrod', //参考线路径样式
GUIDEWIRE_FILL_STYLE = 'rgba(250, 250, 0, 0.6)', //参考线填充样式
//圆的大小
circle = { x: canvas.width/2,
y: canvas.height/2,
radius: 150
};

//-----------------------1、基本功能
//绘制背景网格
function drawGrid(color, stepx, stepy) {
context.save()

context.shadowColor = undefined;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;

context.strokeStyle = color;
context.fillStyle = '#ffffff';
context.lineWidth = 0.5;
context.fillRect(0, 0, context.canvas.width,
context.canvas.height);

for (var i = stepx + 0.5;
i < context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}

for (var i = stepy + 0.5;
i < context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}

context.restore();
}
//绘制参考线
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;

context.textAlign = 'center';
context.textBaseline = 'middle';
drawGrid('lightgray', 10, 10);

//绘制仪表盘
(function drawDial() {
var loc = {x: circle.x, y: circle.y};
})();

(二)绘制中心点与外圆

//绘制仪表盘
(function drawDial() {
var loc = {x: circle.x, y: circle.y};
//绘制中心圆点
drawCentroid();
//绘制外圆环
drawRing();
})();

//------------------------------2、绘制中心点与外圆
//绘制中心圆点
function drawCentroid() {
context.beginPath();
context.save();
context.strokeStyle = CENTROID_STROKE_STYLE;
context.fillStyle = CENTROID_FILL_STYLE;
context.arc(circle.x, circle.y,
CENTROID_RADIUS, 0, Math.PI*2, false);
context.stroke();
context.fill();
context.restore();
}
//绘制外圆环
function drawRingOuterCircle() {
context.shadowColor = 'rgba(0, 0, 0, 0.7)';
context.shadowOffsetX = 3,
context.shadowOffsetY = 3,
context.shadowBlur = 6,
context.strokeStyle = TRACKING_DIAL_STROKING_STYLE;
context.beginPath();
context.arc(circle.x, circle.y, circle.radius +
RING_OUTER_RADIUS, 0, Math.PI*2, true);
context.stroke();
}
//填充外圆环颜色
function drawRing() {
drawRingOuterCircle();

context.strokeStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(circle.x, circle.y,
circle.radius + RING_INNER_RADIUS,
0, Math.PI*2, false);

context.fillStyle = 'rgba(100, 140, 230, 0.1)';
context.fill();
context.stroke();
}

显示效果:
HTML5游戏开发(五)

(三)绘制刻度与数字标记

重点:角度与弧度计算,公式为:==角度=180°×弧度÷π==
==弧度=角度×π÷180°==

//绘制仪表盘
(function drawDial() {
var loc = {x: circle.x, y: circle.y};
//绘制中心圆点
drawCentroid();
//绘制外圆环
drawRing();
//绘制刻度
drawTicks();
//绘制标记数字
drawAnnotations();
})();

//----------------------------3、绘制刻度与数字标记
//绘制刻度,标记
function drawTick(angle, radius, cnt) {
//刻度分隔为4份,长的为短的2倍
var tickWidth = cnt % 4 === 0 ? TICK_WIDTH : TICK_WIDTH/2;
context.beginPath();
//绘制起始点
context.moveTo(circle.x + Math.cos(angle) * (radius - tickWidth),
circle.y + Math.sin(angle) * (radius - tickWidth));
//绘制终点
context.lineTo(circle.x + Math.cos(angle) * (radius),
circle.y + Math.sin(angle) * (radius));

context.strokeStyle = TICK_SHORT_STROKE_STYLE;
context.stroke();
}
//绘制所有标记
function drawTicks() {
var radius = circle.radius + RING_INNER_RADIUS, //半径
ANGLE_MAX = 2*Math.PI,//最大角度
ANGLE_DELTA = Math.PI/64;//角度间隔
context.save();
//最大角度,按间隔进行递增
for (var angle = 0, cnt = 0; angle < ANGLE_MAX;
angle += ANGLE_DELTA, cnt++) {
//绘制标记
drawTick(angle, radius, cnt++);
}
context.restore();
}
//绘制数字刻度
function drawAnnotations() {
//数字标记半径
var radius = circle.radius + RING_INNER_RADIUS;
context.save();
//数字标记样式
context.fillStyle = ANNOTATIONS_FILL_STYLE;
//数字标记字体大小与字体样式
context.font = ANNOTATIONS_TEXT_SIZE + 'px Helvetica';
//每循环一次为8分之一 PI增量,2×PI为一个整圆
//数字8将一个圆可以分为16份,改变此数字,可以更变数字显示密度
for (var angle=0; angle < 2*Math.PI; angle += Math.PI/8) {
context.beginPath();
//绘制文本数字 度数为:角度=180°×弧度÷π toFixed四舍五入
context.fillText((angle * 180 / Math.PI).toFixed(0),
circle.x + Math.cos(angle) * (radius - TICK_WIDTH*2),
circle.y - Math.sin(angle) * (radius - TICK_WIDTH*2));
}
context.restore();
}

显示效果:
HTML5游戏开发(五)

(四)绘制指示线与内圆

//绘制仪表盘
(function drawDial() {
var loc = {x: circle.x, y: circle.y};
//绘制中心圆点
drawCentroid();
//绘制指示线
drawCentroidGuidewire(loc);
//绘制外圆环
drawRing();
//绘制内圆 标记线内
drawTickInnerCircle();
//绘制刻度
drawTicks();
//绘制标记数字
drawAnnotations();
})();

//------------------------4、绘制指示线与内圆
function drawCentroidGuidewire(loc) {
var angle = -Math.PI/4,
radius, endpt;

radius = circle.radius + RING_OUTER_RADIUS;

if (loc.x >= circle.x) {
endpt = { x: circle.x + radius * Math.cos(angle),
y: circle.y + radius * Math.sin(angle)
};
}
else {
endpt = { x: circle.x - radius * Math.cos(angle),
y: circle.y - radius * Math.sin(angle)
};
}

context.save();

context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
context.fillStyle = GUIDEWIRE_FILL_STYLE;

context.beginPath();
context.moveTo(circle.x, circle.y);
context.lineTo(endpt.x, endpt.y);
context.stroke();

context.beginPath();
context.strokeStyle = TICK_LONG_STROKE_STYLE;
context.arc(endpt.x, endpt.y, 5, 0, Math.PI*2, false);
context.fill();
context.stroke();

context.restore();
}
//绘制内圆
function drawTickInnerCircle() {
context.save();
context.beginPath();
context.strokeStyle = 'rgba(0, 0, 0, 0.1)';
context.arc(circle.x, circle.y,
circle.radius + RING_INNER_RADIUS - TICK_WIDTH,
0, Math.PI*2, false);
context.stroke();
context.restore();
}

显示效果:
HTML5游戏开发(五)

二、贝塞尔曲线

  贝塞尔曲线最初是由法国物理学家与数学家Paul de Casteljau发明的。曲线的核心定义:起始点、终止点(也称锚点)、控制点。然而贝塞尔曲线的得名,却是由于 1962 年另一位就职于雷诺的法国工程师皮埃尔·贝塞尔的广泛宣传。他使用这种只需要很少的控制点就能够生成复杂平滑曲线的方法,来辅助汽车车体的工业设计。
贝塞尔曲线分为两种:平方贝塞尔曲线和立方贝赛尔曲线。

(一)二次方贝塞尔曲线

二次方贝塞尔曲线就是只向一个方向弯曲的简单曲线。

参数 描述
cpx 贝塞尔控制点的 x 坐标
cpy 贝塞尔控制点的 y 坐标
x 结束点的 x 坐标
y 结束点的 y 坐标

1、简单对号

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贝塞尔曲线</title>
<style>
body {
background: #283c3c;
}

#canvas {
background: #f0fff0;
border: thin solid #FFFFCC;
}

</style>
</head>
<body>
<canvas id='canvas' width='400' height='300'>
</canvas>
<script src="js/Bezier01.js"></script>
</body>
</html>

JS脚本

var context = document.getElementById('canvas').getContext('2d');
//填充样式
context.fillStyle = 'cornflowerblue';
//轮廓样式
context.strokeStyle = 'yellow';
//阴影颜色
context.shadowColor = 'rgba(50, 50, 50, 1.0)';
context.shadowOffsetX = 2;
context.shadowOffsetY = 2;
context.shadowBlur = 4;
//线粗细
context.lineWidth = 20;
//线帽为圆
context.lineCap = 'round';

context.beginPath();
context.moveTo(120.5, 130);
//贝塞尔曲线绘制
context.quadraticCurveTo(150.8, 130, 160.6, 150.5);
context.quadraticCurveTo(190, 250.0, 210.5, 160.5);
context.quadraticCurveTo(240, 100.5, 290, 70.5);
context.stroke();

显示效果:
HTML5游戏开发(五)

2、箭头绘制

其中,红点为控制点,蓝色点为终点。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贝塞尔曲线</title>
<style>
body {
background: #283c3c;
}

#canvas {
background: #f0fff0;
border: thin solid #FFFFCC;
}

</style>
</head>
<body>
<canvas id='canvas' width='400' height='300'>
</canvas>
<script src="js/Bezier01.js"></script>
</body>
</html>

JS脚本:

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
ARROW_MARGIN = 30, //箭头边距
POINT_RADIUS = 7, //圆点半径
//所有绘制点
points = [{
x: canvas.width - ARROW_MARGIN,
y: canvas.height - ARROW_MARGIN
},

{
x: canvas.width - ARROW_MARGIN * 2,
y: canvas.height - ARROW_MARGIN
},

{
x: POINT_RADIUS,
y: canvas.height / 2
},

{
x: ARROW_MARGIN,
y: canvas.height / 2 - ARROW_MARGIN
},

{
x: canvas.width - ARROW_MARGIN,
y: ARROW_MARGIN
},

{
x: canvas.width - ARROW_MARGIN,
y: ARROW_MARGIN * 2
},
];

//绘制圆点
function drawPoint(x, y, strokeStyle, fillStyle) {
context.beginPath();
context.fillStyle = fillStyle;
context.strokeStyle = strokeStyle;
context.lineWidth = 0.5;
context.arc(x, y, POINT_RADIUS, 0, Math.PI * 2, false);
context.fill();
context.stroke();
}
//绘制贝塞尔曲线的点
function drawBezierPoints() {
var i,
strokeStyle,
fillStyle;
//获取数组中的所有点
for(i = 0; i < points.length; ++i) {
//点的样式
fillStyle = i % 2 === 0 ? 'red' : 'blue',
strokeStyle = i % 2 === 0 ? 'red' : 'blue';
context.font="16px Helvetica"
context.fillText(i+1,points[i].x+8, points[i].y);
//绘制点
drawPoint(points[i].x, points[i].y,
strokeStyle, fillStyle);
}
}
//绘制箭头
function drawArrow() {
context.strokeStyle = '#2B334A';
context.fillStyle = 'cornflowerblue';
//起点
context.moveTo(canvas.width - ARROW_MARGIN,
ARROW_MARGIN * 2);
//绘制路径
context.lineTo(canvas.width - ARROW_MARGIN,
canvas.height - ARROW_MARGIN * 2);
//第一个控制点与结束点
context.quadraticCurveTo(points[0].x, points[0].y,
points[1].x, points[1].y);
//第二个路径
context.lineTo(ARROW_MARGIN,
canvas.height / 2 + ARROW_MARGIN);
//第二个控制点与结束点,起点将以第个路径的点为起点
context.quadraticCurveTo(points[2].x, points[2].y,
points[3].x, points[3].y);
//第三个绘制
context.lineTo(canvas.width - ARROW_MARGIN * 2,
ARROW_MARGIN);

context.quadraticCurveTo(points[4].x, points[4].y,
points[5].x, points[5].y);
context.fill();
context.stroke();
}

//清空画布
context.clearRect(0, 0, canvas.width, canvas.height);
//绘制箭头
drawArrow();
drawBezierPoints();

显示效果:
HTML5游戏开发(五)

(二)三次方贝塞尔曲线

三次方贝塞尔曲线可以向两个方向弯曲。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>贝塞尔曲线</title>
<style>
body {
background: #283c3c;
}

#canvas {
background: #f0fff0;
border: thin solid #FFFFCC;
}

</style>
</head>
<body>
<canvas id='canvas' width='400' height='300'>
</canvas>
<script src="js/Bezier02.js"></script>
</body>
</html>

JS脚本

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
//定义终点
endPoints = [
{ x: 100, y: 70 },
{ x: 320, y: 270 },
],
//定义控制点
controlPoints = [
{ x: 100, y: 250 },
{ x: 360, y: 70 },
];

//贝塞尔曲线绘制
function drawBezierCurve() {
context.strokeStyle = 'blue';
context.fillStyle = 'yellow';

context.beginPath();
context.moveTo(endPoints[0].x, endPoints[0].y);
context.bezierCurveTo(controlPoints[0].x, controlPoints[0].y,
controlPoints[1].x, controlPoints[1].y,
endPoints[1].x, endPoints[1].y);
context.stroke();
}
//终点
function drawEndPoints() {
context.strokeStyle = 'blue';
context.fillStyle = 'blue';

endPoints.forEach( function (point) {
context.beginPath();
context.arc(point.x, point.y, 5, 0, Math.PI*2, false);
context.stroke();
context.fill();
});
}
//绘制控制点
function drawControlPoints() {
context.strokeStyle = 'yellow';
context.fillStyle = 'red';

controlPoints.forEach( function (point) {
context.beginPath();
context.arc(point.x, point.y, 5, 0, Math.PI*2, false);
context.stroke();
context.fill();
});
}
//绘制控制点
drawControlPoints();
//绘制终点
drawEndPoints();
//绘制贝塞尔曲线
drawBezierCurve();

最终显示:
HTML5游戏开发(五)

(四)编辑贝塞尔曲线

1、基本功能

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>编辑贝塞尔曲线</title>
<style>
body {
background: #eeeeee;
}

.floatingControls {
position: absolute;
left: 150px;
top: 100px;
width: 300px;
padding: 20px;
border: thin solid rgba(0, 0, 0, 0.3);
background: rgba(0, 0, 200, 0.1);
color: blue;
font: 14px Arial;
-webkit-box-shadow: rgba(0, 0, 0, 0.2) 6px 6px 8px;
box-shadow: rgba(0, 0, 0, 0.2) 6px 6px 8px;
display: none;
}

.floatingControls p {
margin-top: 0px;
margin-bottom: 20px;
}

#controls {
position: absolute;
left: 25px;
top: 25px;
}

#canvas {
background: #f0fff0;
cursor: pointer;
margin-left: 10px;
margin-top: 10px;
-webkit-box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.5);
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.5);
}

</style>
</head>
<body>
<canvas id='canvas' width='605' height='400'>
</canvas>
<div id='controls'>
连框颜色:
<select id='strokeStyleSelect'>
<option value='red'></option>
<option value='green'>绿</option>
<option value='blue'></option>
<option value='orange'></option>
<option value='cornflowerblue' selected>菊蓝</option>
<option value='goldenrod'> 鲜黄</option>
<option value='navy'>深蓝</option>
<option value='purple'>紫色</option>
</select>
参考线: <input id='guidewireCheckbox' type='checkbox' checked/>
<input id='eraseAllButton' type='button' value='擦除所有' />
</div>
<div id='instructions' class='floatingControls'>
<p>拖拽结束点与控制点改变曲线形状.</p>
<p>当你完成绘制后,点击外边结束绘制。</p>
<input id='instructionsOkayButton' type='button' value='确定' autofocus/>
<input id='instructionsNoMoreButton' type='button' value='不再显示' />
</div>
<script src='js/BezierEdit.js'></script>
</body>
</html>

JS脚本:

var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d'),
eraseAllButton = document.getElementById('eraseAllButton'), //擦除所有
strokeStyleSelect = document.getElementById('strokeStyleSelect'), //线条颜色
guidewireCheckbox = document.getElementById('guidewireCheckbox'), //是否显示参考线
instructions = document.getElementById('instructions'), //显示提示信息层
instructionsOkayButton = document.getElementById('instructionsOkayButton'), //提示信息确定按钮
instructionsNoMoreButton = document.getElementById('instructionsNoMoreButton'), //不再提示信息按钮

showInstructions = true,//提示信息
//网格颜色
GRID_STROKE_STYLE = 'lightblue',
GRID_SPACING = 10,
//控制点参数
CONTROL_POINT_RADIUS = 5,
CONTROL_POINT_STROKE_STYLE = 'blue',
CONTROL_POINT_FILL_STYLE = 'rgba(255, 255, 0, 0.5)',
//结束点参数
END_POINT_STROKE_STYLE = 'navy',
END_POINT_FILL_STYLE = 'rgba(0, 255, 0, 0.5)',
//参考线样式
GUIDEWIRE_STROKE_STYLE = 'rgba(0,0,230,0.4)',

drawingImageData, // 图像数据存储--按下鼠标事件

mousedown = {}, // 光标位置--鼠标事件
rubberbandRect = {}, // 鼠标移动事件的不断更新

dragging = false, // 如果为真,用户可以拖动鼠标标
draggingPoint = false, // 结束点或控制点的拖动

endPoints = [ {}, {} ], //结束点坐标
controlPoints = [ {}, {} ], //控制点坐标
editing = false, //如果为真用户可以编辑曲线
//获取参考线值
guidewires = guidewireCheckbox.checked;

//------------------1、基本功能
//绘制网格
function drawGrid(color, stepx, stepy) {
context.save()
context.strokeStyle = color;
context.lineWidth = 0.5;
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
for (var i = stepx + 0.5; i < context.canvas.width; i += stepx) {
context.beginPath();
context.moveTo(i, 0);
context.lineTo(i, context.canvas.height);
context.stroke();
}
for (var i = stepy + 0.5; i < context.canvas.height; i += stepy) {
context.beginPath();
context.moveTo(0, i);
context.lineTo(context.canvas.width, i);
context.stroke();
}
context.restore();
}
//坐标转换
function windowToCanvas(x, y) {
var bbox = canvas.getBoundingClientRect();
return { x: x - bbox.left * (canvas.width / bbox.width),
y: y - bbox.top * (canvas.height / bbox.height)
};
}
context.strokeStyle = strokeStyleSelect.value;
drawGrid(GRID_STROKE_STYLE, GRID_SPACING, GRID_SPACING);

2、贝塞尔曲线绘制

//--------------------------2、贝塞尔曲线绘制
//保存绘制
function saveDrawingSurface() {
drawingImageData = context.getImageData(0, 0,
canvas.width, canvas.height);
}
//恢复绘制
function restoreDrawingSurface() {
context.putImageData(drawingImageData, 0, 0);
}

//橡皮圈更新绘制
function updateRubberbandRectangle(loc) {
rubberbandRect.width = Math.abs(loc.x - mousedown.x);
rubberbandRect.height = Math.abs(loc.y - mousedown.y);

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 drawBezierCurve() {
context.beginPath();
context.moveTo(endPoints[0].x, endPoints[0].y);
context.bezierCurveTo(controlPoints[0].x, controlPoints[0].y,
controlPoints[1].x, controlPoints[1].y,
endPoints[1].x, endPoints[1].y);
context.stroke();
}
//更新结束点与控制点
function updateEndAndControlPoints() {
//结束点坐标
endPoints[0].x = rubberbandRect.left;
endPoints[0].y = rubberbandRect.top;

endPoints[1].x = rubberbandRect.left + rubberbandRect.width;
endPoints[1].y = rubberbandRect.top + rubberbandRect.height
//控制点坐标
controlPoints[0].x = rubberbandRect.left;
controlPoints[0].y = rubberbandRect.top + rubberbandRect.height

controlPoints[1].x = rubberbandRect.left + rubberbandRect.width;
controlPoints[1].y = rubberbandRect.top;
}
//绘制结束点与控制点小圆点
function drawRubberbandShape(loc) {
updateEndAndControlPoints();
drawBezierCurve();
}
//更新橡皮圈
function updateRubberband(loc) {
updateRubberbandRectangle(loc);
drawRubberbandShape(loc);
}

3、绘制结束点与控制点

//-------------------------3、绘制结束点与控制点
//绘制控制点
function drawControlPoint(index) {
context.beginPath();
context.arc(controlPoints[index].x, controlPoints[index].y,
CONTROL_POINT_RADIUS, 0, Math.PI*2, false);
context.stroke();
context.fill();
}
//绘制控制点
function drawControlPoints() {
context.save();
context.strokeStyle = CONTROL_POINT_STROKE_STYLE;
context.fillStyle = CONTROL_POINT_FILL_STYLE;

drawControlPoint(0);
drawControlPoint(1);

context.stroke();
context.fill();
context.restore();
}
//绘制结束点
function drawEndPoint(index) {
context.beginPath();
context.arc(endPoints[index].x, endPoints[index].y,
CONTROL_POINT_RADIUS, 0, Math.PI*2, false);
context.stroke();
context.fill();
}
//绘制结束点
function drawEndPoints() {
context.save();
context.strokeStyle = END_POINT_STROKE_STYLE;
context.fillStyle = END_POINT_FILL_STYLE;

drawEndPoint(0);
drawEndPoint(1);

context.stroke();
context.fill();
context.restore();
}
//绘制控制点与结束点
function drawControlAndEndPoints() {
drawControlPoints();
drawEndPoints();
}
//光标结束点
function cursorInEndPoint(loc) {
var pt;
endPoints.forEach( function(point) {
context.beginPath();
context.arc(point.x, point.y,
CONTROL_POINT_RADIUS, 0, Math.PI*2, false);

if (context.isPointInPath(loc.x, loc.y)) {
pt = point;
}
});
return pt;
}
//光标在控制点
function cursorInControlPoint(loc) {
var pt;
//查找控制点
controlPoints.forEach( function(point) {
context.beginPath();
context.arc(point.x, point.y,
CONTROL_POINT_RADIUS, 0, Math.PI*2, false);
//重点通过 isPointInPath 判定鼠标点击的点是否在路径中,如果
//不在则认为编辑结束
if (context.isPointInPath(loc.x, loc.y)) {
pt = point;
}
});
return pt;
}
//更新拖拽点
function updateDraggingPoint(loc) {
draggingPoint.x = loc.x;
draggingPoint.y = loc.y;
}

4、绘制参考线

//-----------------------4、绘制参考线
//绘制水平线
function drawHorizontalGuidewire (y) {
context.beginPath();
context.moveTo(0, y + 0.5);
context.lineTo(context.canvas.width, y + 0.5);
context.stroke();
}
//绘制垂直线
function drawVerticalGuidewire (x) {
context.beginPath();
context.moveTo(x + 0.5, 0);
context.lineTo(x + 0.5, context.canvas.height);
context.stroke();
}
//绘制参考线
function drawGuidewires(x, y) {
context.save();
context.strokeStyle = GUIDEWIRE_STROKE_STYLE;
context.lineWidth = 0.5;
drawVerticalGuidewire(x);
drawHorizontalGuidewire(y);
context.restore();
}

5、绘制曲线事件

//------------------------5、绘制曲线事件
//鼠标按下事件
canvas.onmousedown = function (e) {
//坐标转换
var loc = windowToCanvas(e.clientX, e.clientY);
e.preventDefault();
//可编辑,默认
if (!editing) {
//保存画布
saveDrawingSurface();
mousedown.x = loc.x;
mousedown.y = loc.y;
//更新橡皮圈
updateRubberbandRectangle(loc);
//改变可拖拽状态
dragging = true;
}
else {
console.log("----------------"+editing+draggingPoint)
//获取控制点光标位置
draggingPoint = cursorInControlPoint(loc);
//如果光标不在控制点上,则获取光标是否在结束点上
if (!draggingPoint) {
//获取结束点--光标位置
draggingPoint = cursorInEndPoint(loc);
}
}
};
//鼠标移动
canvas.onmousemove = function (e) {
var loc = windowToCanvas(e.clientX, e.clientY);
//如果可以拖拽
if (dragging || draggingPoint) {
console.log("&&&&&"+draggingPoint)
e.preventDefault();
//恢复画布
restoreDrawingSurface();
//如果启用了参考线,则绘制参考线
if(guidewires) {
drawGuidewires(loc.x, loc.y);
}
}
//如果拖拽为空
if (dragging) {
//更新绘制
updateRubberband(loc);
drawControlAndEndPoints();
}
else if (draggingPoint) {
//f进行贝塞尔曲线绘制
updateDraggingPoint(loc);
drawControlAndEndPoints();
drawBezierCurve();
}
};
/**
* 释放鼠标
* @param {Object} e
*/

canvas.onmouseup = function (e) {
//坐标转换
loc = windowToCanvas(e.clientX, e.clientY);
//恢复画布
restoreDrawingSurface();
//如果可编辑为false ,默认
if (!editing) {
//进行贝塞尔曲线绘制
updateRubberband(loc);
//绘制结束点与控制点
drawControlAndEndPoints();
dragging = false;
//更改编辑状态
editing = true;
//显示提示信息
if (showInstructions) {
instructions.style.display = 'inline';
}
}
else {

//如果光标在结束点与控制点上,继续绘制 ,否则将可编辑设置为false,结束绘制
if (draggingPoint) drawControlAndEndPoints();
else editing = false;
//绘制曲线
drawBezierCurve();
//结束绘制,让所有条件不成立
draggingPoint = undefined;
}
};

6、控制事件

//--------------------6、控制事件
//擦 除所有事件
eraseAllButton.onclick = function (e) {
//清空画布
context.clearRect(0, 0, canvas.width, canvas.height);
//重绘网格
drawGrid(GRID_STROKE_STYLE, GRID_SPACING, GRID_SPACING);
//保存画两点
saveDrawingSurface();
//改变所有状态为默认
editing = false;
dragging = false;
draggingPoint = undefined;
};
//--------------------------------
//改变线条事件
strokeStyleSelect.onchange = function (e) {
context.strokeStyle = strokeStyleSelect.value;
};
//参考线事件
guidewireCheckbox.onchange = function (e) {
guidewires = guidewireCheckbox.checked;
};

7、信息提示

//-----------------------------7、提示信息事件
//提示信息确定事件
instructionsOkayButton.onclick = function (e) {
instructions.style.display = 'none';
};
//提示信息不南显示事件
instructionsNoMoreButton.onclick = function (e) {
instructions.style.display = 'none';
showInstructions = false;
};

显示效果:
HTML5游戏开发(五)