iOS上的缩放画布似乎使Mobile Safari崩溃

问题描述 投票:3回答:1

我一直遇到一个问题,似乎缩放画布会导致移动Safari浏览器崩溃。崩溃日志表明内存不足,但除此之外似乎不太有帮助。

要重现该问题,请使用捏合缩放手势尽可能地放大,然后移开手指。等待新画布加载。使用捏合缩放手势将画布缩小,然后按住手指直到画布完成平铺。在iPad 3上,按住手指时这似乎崩溃了。

在iPad 1上,如果设置this.numPages = 2,this.numCanvases = 2,this.zoomFactor = 2.5,似乎仍然会发生。

我已经使用各种Android平板电脑进行了测试,但无法重现崩溃,因此它似乎是iOS专用的。在带有在画布上绘制的图像和其他内容的完整代码中,我可以用较少的画布重现此问题。

以前有没有人遇到过这个问题,如果有的话,是否有任何解决方法?我可能在缩小缩放代码方面做错了吗?

这是javascript的精简版:

(function(exports) {
"use strict";

var ReaderControl = function() {
    this.numPages = 2;
    this.numCanvases = 8;
    this.zoomFactor = 5.2;

    this.pageWidth = 479.86;
    this.pageHeight = 621;

    this.isPinching = false;
    this.distRatio = 1;
    this.oldScale = 1;
    this.newScale = 1;
    this.oldPinchCenter = {};

    this.bindEvents();
    this.c = this.createPageWrapper();
    $('body').append(this.c.$e);
};

ReaderControl.prototype = {

    bindEvents: function() {
        this.currentPageZoom = parseFloat(document.documentElement.clientHeight) / this.pageHeight;
        this.currentPageMinZoom = this.currentPageZoom;
        this.currentPageMaxZoom = (800 * 800 * this.zoomFactor) / (this.pageWidth * this.pageHeight * window.devicePixelRatio);

        var tbind = function(func, context) {
            return function() {
                func.apply(context, Array.prototype.slice.call(arguments));
            };
        };

        $(document).bind('touchstart', tbind(this.onTouchStart, this));
        $(document).bind('touchmove', tbind(this.onTouchMove, this));  
        $(document).bind('touchend', tbind(this.onTouchEnd, this));

        document.ontouchmove = function(e) { 
            e.preventDefault();
        };
    },

    createCanvas: function (width, height) {
        var canvas = document.createElement('canvas');

        var cWidth = width * window.devicePixelRatio;
        var cHeight = height * window.devicePixelRatio;
        canvas.setAttribute('width', cWidth);
        canvas.setAttribute('height', cHeight);

        $(canvas).css('width', width);
        $(canvas).css('height', height);                

        var ctx = canvas.getContext("2d");
        ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
        ctx.fillStyle = 'pink';
        ctx.fillRect(0, 0, width, height);
        return canvas;
    },

    createPageWrapper: function() {
        var $wrapper = $("<div></div>");

        var scWidth = this.pageWidth * this.currentPageZoom;
        var scHeight = this.pageHeight * this.currentPageZoom;

        var origWidth = scWidth;
        var origHeight = scHeight;

        var totalWidth = origWidth * this.numPages;
        var maxHeight = origHeight;

        for (var pageNum = 0; pageNum < this.numPages; pageNum++){
            for (var j = 0; j < this.numCanvases; j++) {
                var canvas = this.createCanvas(scWidth, scHeight / this.numCanvases);
                var ctx = canvas.getContext("2d");

                if (pageNum % 2 === 0) {
                    ctx.fillStyle = 'blue';
                    ctx.fillRect(0, 0, scWidth, scHeight);
                }

                $wrapper.append($(canvas));
            }
        }

        $wrapper.css("width", totalWidth + "px");
        $wrapper.css("height", maxHeight + "px");

        var left = (exports.innerWidth - totalWidth) / 2;
        var top = (exports.innerHeight - maxHeight) / 2;

        this.transform($wrapper, left, top);
        return {$e:$wrapper, tX: left, tY: top};
    },

    onTouchStart: function(evt) { 
        if (evt.originalEvent.touches.length > 1) {
            this.isPinching = true;

            var touch0 = evt.originalEvent.touches[0];
            var touch1 = evt.originalEvent.touches[1];

            var x1 = touch1.clientX;
            var y1 = touch1.clientY;
            var x0 = touch0.clientX;
            var y0 = touch0.clientY;

            this.oldPinchCenter.x = (x0 + x1) / 2;
            this.oldPinchCenter.y = (y0 + y1) / 2;            

            this.oldDist = Math.sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1));
        }
    },

    transform: function($e, x, y, scale) {
        scale = scale || 1;

        $e.css('-webkit-transform', 'translate3d(' + x + 'px,' + y + 'px, 0) scale(' + scale + ')');
    },

    onTouchMove: function(evt) {
        var width = this.c.$e.width();
        var height = this.c.$e.height();

        if (evt.originalEvent.touches.length > 1) {
            var touch0 = evt.originalEvent.touches[0];
            var touch1 = evt.originalEvent.touches[1];

            var x1 = touch1.clientX;
            var y1 = touch1.clientY;
            var x0 = touch0.clientX;
            var y0 = touch0.clientY;

            this.newDist = Math.sqrt((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1));
            this.distRatio = this.newDist / this.oldDist;

            var newPinchCenter = {
                x: (x0 + x1) / 2,
                y: (y0 + y1) / 2
            };

            this.newScale = this.distRatio * this.oldScale;

            var actualZoom = this.newScale * this.currentPageZoom;
            if (actualZoom > this.currentPageMaxZoom) {
                this.newScale = this.currentPageMaxZoom / parseFloat(this.currentPageZoom);
            }

            var pcMidX = this.c.tX + width / 2;
            var pcMidY = this.c.tY + height / 2;

            var pcCenter = {
                x: pcMidX, 
                y: pcMidY
            };

            var scX = pcCenter.x - (this.newScale / this.oldScale) * (pcCenter.x - this.oldPinchCenter.x);
            var scY = pcCenter.y - (this.newScale / this.oldScale) * (pcCenter.y - this.oldPinchCenter.y);

            var scaledOldPinchCenter = {
                x: scX, 
                y: scY
            };

            var offsetX = newPinchCenter.x - scaledOldPinchCenter.x;
            var offsetY = newPinchCenter.y - scaledOldPinchCenter.y;
            this.c.tX = this.c.tX + offsetX;
            this.c.tY = this.c.tY + offsetY;

            this.transform(this.c.$e, this.c.tX, this.c.tY, this.newScale);

            this.oldScale = this.newScale;
            this.oldDist = this.newDist;
            this.oldPinchCenter.x = newPinchCenter.x;
            this.oldPinchCenter.y = newPinchCenter.y;
        }
    },

    onTouchEnd: function(evt) {
        if (evt.originalEvent.touches.length === 0) {
            var newPageZoom = this.newScale * this.currentPageZoom;

            if (newPageZoom < this.currentPageMinZoom) {
                newPageZoom = this.currentPageMinZoom;
                this.newScale = newPageZoom / parseFloat(this.currentPageZoom);
                this.oldScale = this.newScale;
            }

            this.c.tX = 31.37;
            this.c.tY = 0;
            this.transform(this.c.$e, this.c.tX, this.c.tY);

            if (this.isPinching) {
                var zoomedIn = newPageZoom > this.currentPageMinZoom;
                var goingToMinZoom = (newPageZoom === this.currentPageMinZoom) && (this.currentPageZoom !== this.currentPageMinZoom);
                var shouldZoom = newPageZoom !== this.currentPageZoom && (goingToMinZoom || zoomedIn);

                if (shouldZoom) {
                    this.currentPageZoom = newPageZoom;

                    this.invisC && this.invisC.$e.remove();
                    this.invisC = this.createPageWrapper();
                    $('body').append(this.invisC.$e);
                    this.c.$e.remove();

                    this.c = this.invisC;
                    this.invisC = null;

                    this.newScale = 1;
                    this.oldScale = 1;
                } 
            }

            this.isPinching = false;
        }
    }
};

exports.ReaderControl = ReaderControl;
})(window);

$(function(){
    window.readerControl = new ReaderControl();
});

这是HTML文件:

<html>
<head>
    <title>Canvas Crash Test</title>
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
    <script src="test.js"></script>
</head>

<body>
</body>
</html>
web-applications mobile-safari html5-canvas css-transforms
1个回答
0
投票

很多年后,我找到了解决方法...

如果使用非标准CSS "zoom" property而不是transform: scale,则不会导致崩溃。

似乎没有等同于转换原点,因此您需要调整定位计算。但是除此之外,它似乎很棒!

© www.soinside.com 2019 - 2024. All rights reserved.