2D变换 - 如何保持位置?



我想在画布的右下角绘制几个透视转换的矩形(形状(。为此,我使用了ctx.transform:ctx.transform(1, 0, -1, 1, 10, 10)

现在我想使用可变scale=n缩放绘图的大小,但仍然将位置保持在正好在这一点上(在中心(。

这是我到目前为止编写的代码。移动滑块会更改形状的位置。我怎样才能避免这种情况?

let canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
$(canvas).appendTo(document.body)
let ctx = canvas.getContext("2d")
let update = function(input) {
let scale = input.value;
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.transform(1, 0, -1, 1, 10, 10)
for (let i = 0; i < 4; i++) {
ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
let layer = {
x: canvas.width + scale * 7 - i * scale,
y: canvas.height - scale * 5 - i * scale,
width: scale * 3,
height: scale * 1.5
}
ctx.fillRect(layer.x, layer.y, layer.width, layer.height)
ctx.strokeRect(layer.x, layer.y, layer.width, layer.height)
}
ctx.resetTransform();
}
$("input").trigger("input")
#canvas {
border: 2px solid red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas"></canvas>
<input oninput="update(this)" type="range" min="1" max="20" />

与其使用变换,我建议您自己绘制形状。

请参阅下面的示例代码:

let canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
$(canvas).appendTo(document.body)
let ctx = canvas.getContext("2d")
function shape(x,y,s) {
var f = s/18
ctx.moveTo(x-10*f, y-60*f);
ctx.lineTo(x-110*f, y-60*f);
ctx.lineTo(x-160*f, y-10*f);
ctx.lineTo(x-60*f, y-10*f);
ctx.lineTo(x-10*f, y-60*f);
ctx.fill();
ctx.stroke();
}
let update = function(input) {
let scale = input.value;
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.lineWidth = Math.min(scale/2, 2);
for (let i = 0; i < 4; i++) {
ctx.beginPath();
ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
shape(canvas.width, canvas.height -i * scale * 1.5, scale)
}
}
$("input").trigger("input")
canvas { border: 1px solid red }
input { position: absolute }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input oninput="update(this)" type="range" min="1" max="20" >
<canvas id="canvas"></canvas>

避免在图纸中进行过多的计算。

所有形状实际上共享相同的恒定宽度和高度,并且相对于堆栈中的前一个形状具有恒定的偏移量。
那里唯一真正的变量是相机的位置。

因此,请仅修改此摄像机,为此,请仅更改上下文的转换矩阵。

您需要

  • 将上下文转换为第一个形状的原点
  • 按当前缩放值缩放上下文
  • Y 轴上将上下文倾斜 -1
  • 使用常量值绘制堆栈

前三个步骤可以在对绝对setTransform方法的单个调用中进行。

参数将是,

setTransform(
scale,    // scale-x
0,        // skew-x
- scale,  // skew-y (we use '- scale' here because skew should be made
// after scale so we need to multiply by scale)
scale,    // scale-y
origin_x, // these should be made before so normal scale is ok
origin_y
)

之后,真正的绘图部分将始终相同。

const canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
const ctx = canvas.getContext("2d")
const input = document.querySelector('input');
function update() {
// some constants about our shapes
const origin_x = 160; // center of all the rects
const origin_y = 160; // bottom of all the shapes
const w = 33; // width of each rect
const h = 16.5; // height of each rect
const offset = 11; // axis offset (* i)
const scale = input.value;

// first reset the transformation matrix
ctx.setTransform(1,0,0,1,0,0);
// so we clear everything
ctx.clearRect(0, 0, canvas.width, canvas.height)
// now we move our context
// so that our origins are in the top - left
// and that we are already scaled and skewed
ctx.setTransform(scale, 0, -scale, scale, origin_x, origin_y);

// from now on, we don't care about the scale
for (let i = 0; i < 4; i++) {
ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
let layer = {
x: -i * offset - w/2,
y: -i * offset,
width: w,
height: h
}
ctx.fillRect(layer.x, layer.y, layer.width, layer.height)
ctx.strokeRect(layer.x, layer.y, layer.width, layer.height)
}
}
input.oninput = update;
input.oninput();
#canvas {
border: 2px solid red
}
input {
display: block;
width: 75vw;
}
<input type="range" min="0.01" max="20" value="1" step="0.001" id="inp"/>
<canvas id="canvas"></canvas>

最新更新