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

时间:2018-10-04 19:29:52

标签: javascript html css canvas transform

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

2 个答案:

答案 0 :(得分:1)

我建议您自己绘制形状,而不是使用变换。

请参见下面的示例代码:

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>
from StringIO import StringIO
from urllib2 import Request, urlopen
from boto.s3.connection import S3Connection, Bucket, Key

def scrape_to_s3(filename, origin_url):
    remote_file = urlopen(Request(origin_url)).read()
    memory_file = StringIO(remote_file)


    conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
    bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME)
    k = Key(bucket)
    k.key = "media/" + filename
    k.set_contents_from_file(memory_file)

答案 1 :(得分:1)

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

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

因此,仅修改此摄像机,并仅更改上下文的变换矩阵即可。

您需要

  • 将上下文转换为第一个形状的原点
  • 根据当前比例值缩放上下文
  • 使上下文在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>

相关问题