【问题标题】:Viewport from bigger image with html5 canvas带有 html5 画布的更大图像的视口
【发布时间】:2017-02-25 05:22:11
【问题描述】:

我正在尝试使用较小的画布作为另一个更大画布的视口。 我真的很喜欢this 中使用的方法,解决了类似的问题。

他基本上使用CanvasRenderingContext2D.drawImage() 来“裁剪”缓冲区/偏移画布,然后在较小的画布(视口)上显示该部分图像。我正在尝试在这个小提琴中实现给定解决方案的更简单版本:https://jsfiddle.net/avvac0x8/2/。但正如您所见,视口与大图像并不完全同步(反之亦然)。

似乎后面提到的解决方案不适用于不同的画布尺寸。所以我需要让它“与画布大小无关”。

也许我错过了某种缩放计算,但我不知道如何从这里开始,欢迎任何提示。

编辑:

更新了小提琴以正常工作:https://jsfiddle.net/avvac0x8/4/。显然,原始图像不应缩放以适合缓冲区画布。相反,应该做的是偏移/缓冲画布应该与原始图像的大小相同。

【问题讨论】:

    标签: javascript html canvas html5-canvas viewport


    【解决方案1】:

    最简单的方法是使用另一个画布作为中间层。

    这里我将忽略偏移画布,因为除非您想显示整个地图,否则不需要它。大概您需要的只是放大的区域。如果你想缩小,你可以简单地将整个图像绘制到你的视口窗口(通过向ctx.drawImage ( img, x, y, viewPort.width, viewPort.height ) 提供宽度和高度参数)。但是,您要确保您的图像被手动裁剪为适当的大小,这样图像就不会被拉伸,或者确保您的画布视口与您使用的图像具有相同的纵横比。

    如果您希望背景的剪辑区域(实际查看区域)与视口窗口(放大/缩小查看区域)的大小不同(更小或更大),则以下方法有效。请注意,这与实际背景的大小无关。大概剪裁区域和视口窗口都比背景图像本身小。

    例如:

    // 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!
        }
    }
    

    【讨论】:

    • 我觉得我不太明白你的解释,也许你可以用小提琴来详细说明一下?我正在使用以下前提: - 我需要缓冲画布来实际显示当前视口的位置(这正是你所说的“中间层”) - 如果我理解你刚才的建议是我不需要缩放原始图像到画布大小。我真正需要的是有一个与原始图像具有相同宽度/高度的画布。您能否详细说明一下,更新我的小提琴以按照您的建议作为概念证明工作?
    • 尽管我认为这个答案不够清楚。我将检查它是否已被接受,因为它大致了解了真正的问题是什么。我已经编辑了这个问题,所以它包含了一个解决方案的工作示例。非常感谢!
    • @TMG 抱歉回复晚了。很高兴我能帮助你。 :-) 我想指出的一件事是,除非您出于特定原因需要偏移画布,否则图像对象本身在加载后将具有有效的宽度和高度属性,并且可以直接绘制到您的主画布上.无论哪种方式,它的工作原理都是一样的。
    • 完全没问题。我很高兴您的回答为我提供了必要的输入来解决问题。谢谢;)
    猜你喜欢
    • 1970-01-01
    • 2012-05-16
    • 1970-01-01
    • 2012-09-16
    • 1970-01-01
    • 2012-09-28
    • 2012-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多