我一直遇到一个问题,似乎缩放画布会导致移动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>
很多年后,我找到了解决方法...
如果使用非标准CSS "zoom" property而不是transform: scale
,则不会导致崩溃。
似乎没有等同于转换原点,因此您需要调整定位计算。但是除此之外,它似乎很棒!