使用 html5 canvas 的更大图像的视口
Viewport from bigger image with html5 canvas
我正在尝试使用较小的 canvas 作为另一个更大的 canvas 的视口。
我真的很喜欢 this 类似问题的解决方案中使用的方法。
他基本上使用 CanvasRenderingContext2D.drawImage()
到 "crop" buffer/offset canvas,然后在较小的 canvas(视口)上显示该部分图像。我正在尝试在此 fiddle: https://jsfiddle.net/avvac0x8/2/ 中实现给定解决方案的更简单版本。但是正如您所看到的,视口与大图像并不完全同步(反之亦然)。
似乎后面提到的解决方案不适用于不同的 canvas 尺寸。所以我需要做到 "canvas-size agnostic".
也许我遗漏了某种缩放计算,但我不知道如何从这里开始,欢迎任何提示。
编辑:
更新了 fiddle 以正常工作:https://jsfiddle.net/avvac0x8/4/。显然,不应缩放原始图像以适应缓冲区 canvas。应该做的是 offset/buffer canvas 应该与原始图像大小相同。
最简单的方法就是再用一个canvas做中间层
这里我会忽略偏移量canvas,因为除非你想显示整个地图,否则不需要它。大概您需要的只是放大的区域。如果您想缩小,只需将完整图像绘制到视口 window(通过向 ctx.drawImage ( img, x, y, viewPort.width, viewPort.height )
提供宽度和高度参数)。但是,您希望确保您的图像被手动裁剪到合适的尺寸,这样图像就不会出现拉伸,或者确保您的 canvas 视口与您使用的图像具有相同的纵横比。
如果您希望背景的裁剪区域(实际查看区域)与视口 window(缩放 in/out 视图的大小不同(小于或大于),则以下方法有效区域 )。请注意,这与实际背景的大小无关。大概裁剪区域和视口 window 都小于背景图像本身。
例如:
// use these to determine where the clipping region lives
var offsetX = 0,
offsetY = 0,
clipWidth = <<yourChosenPixelWidth>>,
clipHeight = <<yourChosenPixelHeight>>,
clip = document.createElement ( "canvas" ),
clipCtx,
viewPort = document.getElementById ( "main-canvas" ),
viewCtx = viewPort.getContext ( "2d" ),
background = new Image (),
// offsetCanvas = document.getElementById ( "offset-canvas" ),
imgLoaded = false;
// configure the offset canvas once
background.src = "http://pixeljoint.com/files/icons/full/map__r1470206141.png";
background.onLoad = function() {
// the fiddle scales the image, here we don't
//offsetCanvas.width = background.width;
//offsetCanvas.height = background.height;
//offsetCtx = offsetCanvas.getContext ( "2d" );
//offsetCtx.drawImage ( background, 0, 0 );
imgLoaded = true;
}
clip.width = clipWidth;
clip.height = clipHeight;
clipCtx = clip.getContext ( "2d" );
function updateViewport () {
if ( imgLoaded ) {
// copy pixels from the background directly
// to the middle layer so we have a "clipped"
// but unscaled image object
//clipCtx.putImageData ( offsetCtx.getImageData ( offsetX, offsetY, clip.width, clip.height ) );
clipCtx.drawImage ( background, offsetX, offsetY );
// this is where rescaling happens
viewCtx.drawImage ( clip, 0, 0, viewPort.width, viewPort.height );
// and you're done!
}
}
我正在尝试使用较小的 canvas 作为另一个更大的 canvas 的视口。 我真的很喜欢 this 类似问题的解决方案中使用的方法。
他基本上使用 CanvasRenderingContext2D.drawImage()
到 "crop" buffer/offset canvas,然后在较小的 canvas(视口)上显示该部分图像。我正在尝试在此 fiddle: https://jsfiddle.net/avvac0x8/2/ 中实现给定解决方案的更简单版本。但是正如您所看到的,视口与大图像并不完全同步(反之亦然)。
似乎后面提到的解决方案不适用于不同的 canvas 尺寸。所以我需要做到 "canvas-size agnostic".
也许我遗漏了某种缩放计算,但我不知道如何从这里开始,欢迎任何提示。
编辑:
更新了 fiddle 以正常工作:https://jsfiddle.net/avvac0x8/4/。显然,不应缩放原始图像以适应缓冲区 canvas。应该做的是 offset/buffer canvas 应该与原始图像大小相同。
最简单的方法就是再用一个canvas做中间层
这里我会忽略偏移量canvas,因为除非你想显示整个地图,否则不需要它。大概您需要的只是放大的区域。如果您想缩小,只需将完整图像绘制到视口 window(通过向 ctx.drawImage ( img, x, y, viewPort.width, viewPort.height )
提供宽度和高度参数)。但是,您希望确保您的图像被手动裁剪到合适的尺寸,这样图像就不会出现拉伸,或者确保您的 canvas 视口与您使用的图像具有相同的纵横比。
如果您希望背景的裁剪区域(实际查看区域)与视口 window(缩放 in/out 视图的大小不同(小于或大于),则以下方法有效区域 )。请注意,这与实际背景的大小无关。大概裁剪区域和视口 window 都小于背景图像本身。
例如:
// use these to determine where the clipping region lives
var offsetX = 0,
offsetY = 0,
clipWidth = <<yourChosenPixelWidth>>,
clipHeight = <<yourChosenPixelHeight>>,
clip = document.createElement ( "canvas" ),
clipCtx,
viewPort = document.getElementById ( "main-canvas" ),
viewCtx = viewPort.getContext ( "2d" ),
background = new Image (),
// offsetCanvas = document.getElementById ( "offset-canvas" ),
imgLoaded = false;
// configure the offset canvas once
background.src = "http://pixeljoint.com/files/icons/full/map__r1470206141.png";
background.onLoad = function() {
// the fiddle scales the image, here we don't
//offsetCanvas.width = background.width;
//offsetCanvas.height = background.height;
//offsetCtx = offsetCanvas.getContext ( "2d" );
//offsetCtx.drawImage ( background, 0, 0 );
imgLoaded = true;
}
clip.width = clipWidth;
clip.height = clipHeight;
clipCtx = clip.getContext ( "2d" );
function updateViewport () {
if ( imgLoaded ) {
// copy pixels from the background directly
// to the middle layer so we have a "clipped"
// but unscaled image object
//clipCtx.putImageData ( offsetCtx.getImageData ( offsetX, offsetY, clip.width, clip.height ) );
clipCtx.drawImage ( background, offsetX, offsetY );
// this is where rescaling happens
viewCtx.drawImage ( clip, 0, 0, viewPort.width, viewPort.height );
// and you're done!
}
}