我遇到了一个问题,似乎缩放画布会导致移动 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>