我想在画布的右下角绘制几个透视转换的矩形(形状(。为此,我使用了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>