【问题标题】:Sluggish UI in drawing/sketching web app on Mobile Safari (HTML5 canvas)移动 Safari(HTML5 画布)上绘图/草绘 Web 应用程序中的 UI 缓慢
【发布时间】:2012-03-20 12:05:21
【问题描述】:

我们一直在使用 canvas 元素,但在 Mobile Safari 上遇到了迟缓,而该应用在桌面上运行流畅。

测试应用非常原始。它只是让用户在桌面上使用鼠标或在智能手机上使用手指画一条线。

在 Mobile Safari 中,线条的绘制通常非常生涩。一行的第一位将实时渲染,但其余的直到手指离开屏幕后才会渲染。

有什么想法吗?

代码如下。

HTML:

<!DOCTYPE html>
<html>
   <head>    
            <link rel='stylesheet' href='http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.css' />
            <script src='http://code.jquery.com/jquery-1.6.4.min.js'></script>
            <script src='http://code.jquery.com/mobile/1.0/jquery.mobile-1.0.min.js'></script>            
            <style type='text/css'>
                #canvas { border:1px solid red }
            </style>        
   </head>

   <body>    
            <div id='draw_page' data-role='page'>
               <canvas id="canvas" width="500" height="350"></canvas>
            </div>

            <script type="text/javascript"> 
              $('#draw_page').live('pageinit', function() {
                prep_canvas();
                });
            </script>
   </body>
</html>

JavaScript:

var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
var canvas;
var context;

function prep_canvas() {

canvas = $('#canvas')[0];
context = canvas.getContext("2d");

}

$('#canvas').live('vmousedown', function(e){
  var mouseX = e.pageX - this.offsetLeft;
  var mouseY = e.pageY - this.offsetTop;

  paint = true;
  addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
  redraw();
});


$('#canvas').live('vmousemove', function(e){
  if(paint){
    addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
    redraw();
  }
});


$('#canvas').live('vmouseup', function(e){
  paint = false;
});


function addClick(x, y, dragging)
{
  clickX.push(x);
  clickY.push(y);
  clickDrag.push(dragging);
}


function redraw(){
  canvas.width = canvas.width; // Clears the canvas

  context.strokeStyle = "black";
  context.lineJoin = "round";
  context.lineWidth = 2;

  for(var i=0; i < clickX.length; i++)
  {     
    context.beginPath();
    if(clickDrag[i] && i){
      context.moveTo(clickX[i-1], clickY[i-1]);
     }else{
       context.moveTo(clickX[i]-1, clickY[i]);
     }
     context.lineTo(clickX[i], clickY[i]);
     context.closePath();
     context.stroke();
  }
}

【问题讨论】:

  • 确保您没有在 iPhone 模拟器上进行测试。此外,以全屏模式运行画布或作为通过 PhoneGap 移植的应用程序运行将导致 iOS 5 中的 JavaScript 像 iOS 4 一样运行。
  • 另外,还有一种方法可以使用多层画布来避免必须重绘每一帧中的所有内容,这在移动浏览器中非常麻烦。如果您有两个相互重叠的画布层,您可以经常将当前线绘制到后面的画布上,然后只将线的最新部分绘制到前面的画布上。
  • 希望我能提供更多帮助。看起来这里的答案有一个现场演示,你可以在手机上尝试,我不认为这个人每次都在重绘画布:stackoverflow.com/questions/7478501/…

标签: iphone ios html canvas mobile-safari


【解决方案1】:

我遵循了这个:http://dev.opera.com/articles/view/html5-canvas-painting/,它在电话上流畅地工作(你会看到 img_update() 的注释行,它在 BumbleB2na 提到的两个画布方法中使用......但我没有使用任何形状,只是线条,所以省略)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, user-scalable=no,initial-scale = 1.0">
<link rel="apple-touch-icon" href="touch-icon-iphone.png" />
<link rel="apple-touch-icon" sizes="72x72" href="touch-icon-ipad.png" />
<link rel="apple-touch-icon" sizes="114x114" href="touch-icon-iphone4.png" />
<link rel="apple-touch-startup-image" href="startup-iphone.png">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<title>Untitled Document</title>
<style type="text/css">
body {background:#ccc; margin:0; padding:0}
html {margin:0; padding:0;}
#container { position: relative; margin:0; padding:0px; }
#canvas { border: 1px solid #000; background-color:#FFF; position:relative; width:298px; margin-left:11px; margin-top:5px; }
</style>
</head>

<body onload="listen()">
<div id="container">
    <canvas id="canvas" width="298" height="298">
    </canvas><br/>
    <button onclick="clearImage()">Clear</button>
    </div>
</body>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
if(canvas){var context= canvas.getContext('2d');}
var tool;
tool = new tool_pencil();

document.body.addEventListener('touchmove',function(event){ event.preventDefault(); },false);
function listen(){
    canvas = document.getElementById('canvas'); 
    if(canvas){
        context= canvas.getContext('2d');
        context.fillStyle = "rgb(255,255,255)";  
        context.fillRect(0, 0, canvas.width, canvas.height);
        iphone = ((window.navigator.userAgent.match('iPhone'))||(window.navigator.userAgent.match('iPod')))?true:false;
        ipad = (window.navigator.userAgent.match('iPad'))?true:false;
        if(iphone||ipad){
            canvas.addEventListener('touchstart', ev_canvas, false);
            canvas.addEventListener('touchend', ev_canvas, false);
            canvas.addEventListener('touchmove', ev_canvas, false);
        }
        else{
            canvas.addEventListener('mousedown', ev_canvas, false);
            canvas.addEventListener('mousemove', ev_canvas, false);
            canvas.addEventListener('mouseup',   ev_canvas, false);
        }
    }
}

function tool_pencil () {
    var tool = this;
    this.started = false;
    this.mousedown = function (ev) {
        context.beginPath();
        context.moveTo(ev._x, ev._y);
        tool.started = true;
    };

    this.mousemove = function (ev) {
        if (tool.started) {
            context.lineTo(ev._x, ev._y);
            context.stroke();
        }
    };

    this.mouseup = function (ev) {
        if (tool.started) {
            tool.mousemove(ev);
            tool.started = false;
            //img_update();
        }
    };
    this.touchstart = function (ev) {
        ev.preventDefault();
        context.beginPath();
        context.moveTo(ev._x, ev._y);
        tool.started = true;
    };

    this.touchmove = function (ev) {
        ev.preventDefault();
        if (tool.started) {
            context.lineTo(ev._x, ev._y);
            context.stroke();
        }
    };

    this.touchend = function (ev) {
        ev.preventDefault();
        if (tool.started) {
            tool.started = false;
        }
    };
}

// The general-purpose event handler. This function just determines the mouse position relative to the canvas element.
function ev_canvas (ev) {
    iphone = ((window.navigator.userAgent.match('iPhone'))||(window.navigator.userAgent.match('iPod')))?true:false;
    ipad = (window.navigator.userAgent.match('iPad'))?true:false;
    if (((iphone)||(ipad))&&(ev.touches[0])){ //iPad
        ev._x = ev.touches[0].clientX;
        ev._y = ev.touches[0].clientY;
    }
    else if (ev.layerX || ev.layerX == 0) { // Firefox
        ev._x = ev.layerX;
        ev._y = ev.layerY;
    }
    else if (ev.offsetX || ev.offsetX == 0) { // Opera
        ev._x = ev.offsetX;
        ev._y = ev.offsetY;
    }
  // Call the event handler of the tool.
    var func = tool[ev.type];
    if (func) {
        func(ev);
    }
}

function clearImage(){
    var yes=confirm('Clear drawing?');
    if(yes){
        context.clearRect(0, 0, canvas.width, canvas.height);
        context.fillStyle = "rgb(255,255,255)";  
        context.fillRect(0, 0, canvas.width, canvas.height);
    }
}

</script>
</html>

【讨论】:

  • 完美运行!顺便说一句,你是怎么找到这个的?希望下次我能自己找到答案。 :)
  • 我想我已经搜索了“画布绘画程序”或类似的东西......但后来我对触摸事件进行了自己的调整。很高兴它有帮助
  • 嗨@RobotWoods,你知道我们如何平滑铅笔工具绘制的线条吗?除非用户画出完美的直线,否则会出现锯齿状和略微模糊,这意味着不可能画出平滑的圆或曲线。
  • 嗯,它们不在我的实现中,您是否还有很多其他进程可能会减慢触摸移动事件的触发(更少的点==更多锯齿状),因为模糊,也许尝试调整宽度? byteblocks.com/post/2011/06/18/HTML5-Canvas-Line-Width.aspx
  • 不,不会因额外进程而减慢速度。即使在您基于代码编写的原始演示中也会发生这种情况...
猜你喜欢
  • 2012-07-05
  • 2013-12-06
  • 1970-01-01
  • 2015-12-03
  • 2016-09-16
  • 2017-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多