Maximum size of a element

后端 未结 14 1913
粉色の甜心
粉色の甜心 2020-11-22 07:34

I\'m working with a canvas element with a height of 600 to 1000 pixels and a width of several tens or hundreds of thousands of pixels. However, aft

14条回答
  •  时光取名叫无心
    2020-11-22 08:15

    When you are using WebGL canvases, the browsers (including the desktop ones) will impose extra limits on the size of the underlying buffer. Even if your canvas is big, e.g. 16,000x16,000, most browsers will render a smaller (let's say 4096x4096) picture, and scale it up. That might cause ugly pixelating, etc.

    I have written some code to determine that maximum size using exponential search, if anyone ever needs it. determineMaxCanvasSize() is the function you are interested in.

    function makeGLCanvas()
    {
        // Get A WebGL context
        var canvas = document.createElement('canvas');
        var contextNames = ["webgl", "experimental-webgl"];
        var gl = null;
        for (var i = 0; i < contextNames.length; ++i)
        {
            try
            {
                gl = canvas.getContext(contextNames[i], {
                    // Used so that the buffer contains valid information, and bytes can
                    // be retrieved from it. Otherwise, WebGL will switch to the back buffer
                    preserveDrawingBuffer: true
                });
            }
            catch(e) {}
            if (gl != null)
            {
                break;
            }
        }
        if (gl == null)
        {
            alert("WebGL not supported.\nGlobus won't work\nTry using browsers such as Mozilla " +
                "Firefox, Google Chrome or Opera");
            // TODO: Expecting that the canvas will be collected. If that is not the case, it will
            // need to be destroyed somehow.
            return;
        }
    
        return [canvas, gl];
    }
    
    // From Wikipedia
    function gcd(a,b) {
        a = Math.abs(a);
        b = Math.abs(b);
        if (b > a) {var temp = a; a = b; b = temp;}
        while (true) {
            if (b == 0) return a;
            a %= b;
            if (a == 0) return b;
            b %= a;
        }
    }
    
    function isGlContextFillingTheCanvas(gl) {
        return gl.canvas.width == gl.drawingBufferWidth && gl.canvas.height == gl.drawingBufferHeight;
    }
    
    // (See issue #2) All browsers reduce the size of the WebGL draw buffer for large canvases 
    // (usually over 4096px in width or height). This function uses a varian of binary search to
    // find the maximum size for a canvas given the provided x to y size ratio.
    //
    // To produce exact results, this function expects an integer ratio. The ratio will be equal to:
    // xRatio/yRatio.
    function determineMaxCanvasSize(xRatio, yRatio) {
        // This function works experimentally, by creating an actual canvas and finding the maximum
        // value, the browser allows.
        [canvas, gl] = makeGLCanvas();
    
        // Reduce the ratio to minimum
        gcdOfRatios = gcd(xRatio, yRatio);
        [xRatio, yRatio] = [xRatio/gcdOfRatios, yRatio/gcdOfRatios];
    
        // if the browser cannot handle the minimum ratio, there is not much we can do
        canvas.width = xRatio;
        canvas.height = yRatio;
    
        if (!isGlContextFillingTheCanvas(gl)) {
            throw "The browser is unable to use WebGL canvases with the specified ratio: " + 
                xRatio + ":" + yRatio;
        }
    
        // First find an upper bound
        var ratioMultiple = 1;  // to maintain the exact ratio, we will keep the multiplyer that
                                // resulted in the upper bound for the canvas size
        while (isGlContextFillingTheCanvas(gl)) {
            canvas.width *= 2;
            canvas.height *= 2;
            ratioMultiple *= 2;
        }
    
        // Search with minVal inclusive, maxVal exclusive
        function binarySearch(minVal, maxVal) {
            if (minVal == maxVal) {
                return minVal;
            }
    
            middle = Math.floor((maxVal - minVal)/2) + minVal;
    
            canvas.width = middle * xRatio;
            canvas.height = middle * yRatio;
    
            if (isGlContextFillingTheCanvas(gl)) {
                return binarySearch(middle + 1, maxVal);
            } else {
                return binarySearch(minVal, middle);
            }
        }
    
        ratioMultiple = binarySearch(1, ratioMultiple);
        return [xRatio * ratioMultiple, yRatio * ratioMultiple];
    }
    

    Also in a jsfiddle https://jsfiddle.net/1sh47wfk/1/

提交回复
热议问题