我目前正试图了解在html5中绘制对象时如何进行矩阵变换,但是在多个不同信息源中发现的不同解释引起了一些混淆。我已经找到信息说,为了在html5中为绘制的对象设置动画,如here所示,同时我也看到转换可以通过转换绘制点应用于页面上的单个对象,但是我不确定它是如何工作的。
我找到了一个实现了腿部动画(两行)的代码示例,但它使用了一个函数对象来实现动画,而不使用转换矩阵对其他文件中定义的转换矩阵。代码提供了自己的moveTo()
和lineTo()
(通常与canvas对象一起使用)的实现,在其中它转换传入的点,基于视口重新调整其位置,然后调用canvas& #39;移动到转换点的传递版本。
所以这里有一些混淆点:
1.当setTransform()只能在画布上使用时,在转换矩阵对象上实现新转换函数的目的是什么?
2.像rotate()
和translate()
这样的方法在矩阵对象上被调用而没有传入点,那么这些操作中的任何一个是如何实际应用的?
3.什么时候应该将变换应用于整个画布(如提供的链接中所做的那样)而不是绘制的特定对象,因为它们似乎都可以工作?
我一般只是在寻找对此的一般概述,因为我对这是如何工作感到困惑。示例中的代码如下所示:
<head>
<script src=g.js></script>
<script src=matrix4x4.js></script>
</head>
<body onload=g_start()>
<canvas id=myCanvas1 width=480 height=480></canvas>
<script>
var w, h, g;
function viewport(p) {
return [ w/2 * p[0] + w/2, h/2 - p[1] * w/2 ];
}
function moveTo(p) {
var q = m.transform(p); // APPLY 3D MATRIX TRANFORMATION
var xy = viewport(q); // APPLY VIEWPORT TRANSFORM
g.moveTo(xy[0], xy[1]);
}
function lineTo(p) {
var q = m.transform(p); // APPLY 3D MATRIX TRANFORMATION
var xy = viewport(q); // APPLY VIEWPORT TRANSFORM
g.lineTo(xy[0], xy[1]);
}
myCanvas1.animate = function(_g) {
g = _g;
w = g.canvas.width;
h = g.canvas.height;
g.fillStyle = 'rgb(200,140,255)';
g.beginPath();
g.moveTo(0, 0);
g.lineTo(w, 0);
g.lineTo(w, h);
g.lineTo(0, h);
g.lineTo(0, 0);
g.stroke();
g.fillStyle = 'rgb(128,0,0)';
g.strokeStyle = 'rgb(0,0,0)';
var legBend = .4;
var t = 3 * time;
for (var leg = 0 ; leg < 2 ; leg++) {
var angle = -Math.PI/2 * (1 + Math.sin(time));
console.log(angle);
var sign = (leg == 0) == (angle < -Math.PI/2) ? -1 : 1;
m.identity();
m.rotateY(-Math.PI/2 * (1 + Math.sin(time)));
g.beginPath();
m.translate(0, .5, .1 * sign);
moveTo([0,0,0]); // HIP
m.rotateZ(-.5 * legBend + sign * legBend * Math.cos(t));
m.translate(0, -.5, 0);
lineTo([0,0,0]); // HIP
m.rotateZ(2 * legBend + 2 * legBend * sign * Math.sin(t));
m.translate(0, -.5, 0);
lineTo([0,0,0]); // KNEE
m.translate(-.1, 0, 0);
lineTo([0,0,0]); // KNEE
g.strokeStyle = 'rgb(0,0,0)';
g.lineWidth = 30;
g.stroke();
g.strokeStyle = 'rgb(255,0,0)';
g.lineWidth = 20;
g.stroke();
}
}
</script>
</body>
答案 0 :(得分:1)
重要的html5画布转换概念:
所有画布转换方法(以及.transform
)都相对于当前画布原点进行操作,并且该原点被赋予坐标[0,0]。起始原点位于画布的左上角。 .setTransform
将重置当前画布原点,然后进行相对于该重置原点的转换。
转换不影响现有图纸。因此,fillRect(0,0)后跟translate(5,0)将不会移动已经绘制的rect。现有的rect仍将显示在画布的左上角。
转换会影响新图纸。
translate
方法将原点移动指定的x,y距离。因此translate(5,0)将使画布绘图原点[0,0]距离画布左侧5个像素。因此,翻译(5,0)后跟fillRect(0,0)将导致新的rect显示画布左侧5个像素。
转换实际上转换(移动),旋转,缩放整个画布绘图表面。因此,新图纸不会单独移动,旋转或缩放。 由于整个画布绘图表面已被移动,旋转或缩放,因此新绘图显示为移动,旋转或缩放。
转型是累积的。因此,如果你翻译(5,0)然后翻译(0,50),画布原点[0,0]将是左边5个像素和顶部50个像素。因此,fillRect(0,0)将从左侧5个像素和从顶部50个像素绘制。
所以,回答你的问题:
顺序转换非常有用,因为转换是累积的。所以要塑造一个人的形象&#34;移动&#34;你可以使用转换的累积效果而不必记住它们的最后位置或必须计算它们的新位置。
// the person image will move across the canvas in 5px increments over time
// No need to remember its last location
// No need to calculate its new position
// That's because the canvas internally remembers & calculates its own origin.
for(var i=0;i<20;i++){
context.clearRect(0,0,canvas.width,canvas.height);
context.translate(5,0);
context.drawImage(person,0,0);
// wait 1 second
}
由于所有变换都是相对于当前画布原点坐标,因此您不必为任何变换方法重新指定该坐标 - 画布&#34;记住&#34;它的当前起源。
单个画布图纸不受转换影响。转换移动整个画布和新图纸只是为了骑行#34;。在转换之前存在的任何图形都不会受到后续转换的影响 - 预先存在的图形仍然保留在它们首次绘制的位置。