假设我有一个像这样的简单画布元素: HTML:
function oval(context, x, y, w, h)
{
context.save();
context.beginPath();
context.translate(x, y);
context.scale(w/2, h/2);
context.arc(1, 1, 1, 0, 2*Math.PI, false);
context.closePath();
context.restore();
}
function drawCanvas(canvasId)
{
//// General Declarations
var canvas = document.getElementById(canvasId);
var context = canvas.getContext('2d');
//// Color Declarations
var blackColor = 'rgba(0, 0, 0, 1)';
var color = 'rgba(0, 109, 73, 1)';
var color2 = 'rgba(255, 255, 87, 1)';
//// Group
//// Oval Drawing
oval(context, 76.5, 64.5, 47, 47);
context.fillStyle = color;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
//// Star Drawing
context.beginPath();
context.moveTo(100, 74.5);
context.lineTo(104.76, 81.45);
context.lineTo(112.84, 83.83);
context.lineTo(107.7, 90.5);
context.lineTo(107.94, 98.92);
context.lineTo(100, 96.1);
context.lineTo(92.06, 98.92);
context.lineTo(92.3, 90.5);
context.lineTo(87.16, 83.83);
context.lineTo(95.24, 81.45);
context.closePath();
context.fillStyle = color2;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
}
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="scripts/canvas.js"></script>
<script>
window.onload = function()
{
drawCanvas('mainCanvas');
};
</script>
</head>
<body style="margin: 0px;">
<canvas id="mainCanvas" width="300" height="200"></canvas>
</body>
</html>
此时我在canvas元素中单独定义了两个形状。我希望能够将这两个项目移动为一个(就好像它是一个带有星星的球)点击时。我看到画布支持transform
。这是让画布元素从点击移动的最佳方式吗?
答案 0 :(得分:1)
@ Blindman67有正确的想法:同时绘制圆形和星形 - 从而创建一个组。
您的代码中唯一的问题是您已经对星座符号进行了硬编码。要使用硬编码坐标,您可以“标准化”星形坐标,以便星形以[0,0]为中心。 context.translate(x,y)
方法将画布原点[0,0]移动到x,y - 有效地将星形中心点移动到画布[0,0]。如果您想学习如何使用相对坐标(而不是硬编码坐标)绘制星星,请查看this Q&A。
以下是示例代码和演示,可以在圆圈中为您的群组设置动画
您可以使用代码中的drawGroup
功能在任何x,y
//// General Declarations
var canvas=document.getElementById("canvas");
var context = canvas.getContext('2d');
var cw=canvas.width;
var ch=canvas.height;
//// Color Declarations
var blackColor = 'rgba(0, 0, 0, 1)';
var color = 'rgba(0, 109, 73, 1)';
var color2 = 'rgba(255, 255, 87, 1)';
//
var centerX=150;
var centerY=150;
var radius=20;
var animationRadius=50;
var animationAngle=0;
requestAnimationFrame(animate);
function animate(time){
var x=centerX+animationRadius*Math.cos(animationAngle);
var y=centerY+animationRadius*Math.sin(animationAngle);
context.clearRect(0,0,canvas.width,canvas.height);
drawGroup(x,y,radius);
animationAngle+=Math.PI/60;
requestAnimationFrame(animate);
}
function drawGroup(centerX,centerY,radius){
// Oval
oval(centerX,centerY,radius);
context.fillStyle = color;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
// star
star(centerX,centerY,radius);
context.fillStyle = color2;
context.fill();
context.strokeStyle = blackColor;
context.lineWidth = 1;
context.stroke();
}
function oval(x,y,r){
context.beginPath();
context.arc(x,y,r,0,2*Math.PI);
context.closePath();
}
function star(x,y,r){
var w=112.84-87.16;
var h=98.92-74.5;
// normalize fixed star coordinates by moving
// the center of the star to [0,0] with context.translate
context.translate(-87.16-w/2,-74.5-h/2);
// now move to x,y
context.translate(x,y);
// draw the star
context.beginPath();
context.moveTo(100, 74.5);
context.lineTo(104.76, 81.45);
context.lineTo(112.84, 83.83);
context.lineTo(107.7, 90.5);
context.lineTo(107.94, 98.92);
context.lineTo(100, 96.1);
context.lineTo(92.06, 98.92);
context.lineTo(92.3, 90.5);
context.lineTo(87.16, 83.83);
context.lineTo(95.24, 81.45);
context.closePath();
// always clean up, reverse the translate
context.setTransform(1,0,0,1,0,0);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; margin:0 auto; }
<canvas id="canvas" width=300 height=300></canvas>
答案 1 :(得分:1)
你可以在注释中指出保存/恢复对中的转换,因为它们将以与堆栈相同的方式存储画布状态,包括当前转换矩阵(推/弹) - (伪):
ctx.save();
ctx.transform(..); // transform context
// draw something
ctx.save();
ctx.transform(..); // transform context again
// draw something relative to previous transform
ctx.restore(); // we're back to first transform
ctx.restore(); // we're back to original transform
在这种情况下,您可能只使用外部保存/恢复对。
另一种方法是将路径存储在Path2D对象中。这些可以重复使用,你可以在填充/抚摸它们之前转换上下文:
var p = new Path2D();
p.moveTo(x, y);
p.lineTo(x, y);
// ... etc.
然后:
ctx.transform(x, y); // some transform
ctx.fill(p); // fill path
如果形状有多种颜色等,您可能需要定义多个路径。此方法的好处是性能稍高,因为您只需要为每个部件定义一次形状。
第三种方法是将您的路径绘制到离屏画布上,然后使用简单的x / y偏移将画布作为图像绘制回主画布,而无需变换。这是最快的方法,但要求您存储位图(在这种情况下,它不应该有任何明显的影响)。
制作离屏画布:
var oc = document.createElement("canvas");
var oCtx = oc.getContext("2d");
oc.width = someSizeMatchingShapeWidth;
oc.height = someSizeMatchingShapeHeight;
// draw path once into canvas `oc` uing `oCtx` for context
然后是你的主画布:
context.drawImage(oc, x, y);