Холст Android 4+ html5 не перерисовывается

В настоящее время я разрабатываю приложение для Android, используя phonegap. У меня есть холст html5, на котором я рисую и анимирую объекты. Он отлично работает на андроиде 2.3, но на андроиде 4+ он не перерисовывает холст. Я пробовал использовать для своих анимаций как kinetic.js, так и easyl.js/tween.js, и для обеих этих библиотек возникла проблема с невозможностью очистки холста. Мне удалось показать и скрыть div на холсте, но он не работает все время. Я могу только предположить, что это специфичная для Android 4+ ошибка или какая-то функция для повышения производительности холста html5.

Кто-нибудь знает, есть ли какой-то параметр, который я могу изменить, или метод, который я могу вызвать в Android 4 или javascript, который позволил бы мне принудительно перерисовать мой холст html5 во время анимации?

Следует также отметить, что анимации, кажется, работают с easyl.js/tween.js в эмуляторе Google API 4.1 (холст очищается и перерисовывается), но не на телефонах с 4.1.1.

Я провел дополнительное исследование того, что происходит. По сути, кажется, что фигура в самом начале анимации оставляет артефакт, который clearRect не очищает. У меня есть большой круг, который я сжимаю до маленького круга. Анимация все еще происходит, но на большой круг не влияет вызов clearRect на холсте.


person Dan Fischer    schedule 09.10.2012    source источник
comment
Поэтому я придумал, как это исправить. Я до сих пор не знаю первопричину или почему это происходит только в Android 4+. Если я поставлю setTimeout за секунду до того, как впервые нарисую холст. Он больше не оставляет артефактов.   -  person Dan Fischer    schedule 10.10.2012


Ответы (3)


У меня также нет решения для основной проблемы, но я придумал еще один несовершенный обходной путь, который не добавляет задержки в ваш код. Сначала нарисуйте фиктивный объект на холсте. Затем нарисуйте свои анимационные объекты (или перетаскиваемые объекты. Так как это происходит и при перетаскивании). Кажется, что первый нарисованный объект является постоянным (то есть не может быть правильно очищен). С KineticJs я делаю следующее... 1.) создаю сцену, 2.) рисую объект (например, прямоугольник размером со сцену в качестве фона. Обратите внимание, что объект не может быть прозрачным), 3.) добавьте слой на сцену и 4.) запустите layer.draw().

После этого я могу рисовать что угодно на холсте, и в Android он ведет себя нормально. (см. пример ниже. Без фона объект дублируется при первом перетаскивании. Чтобы проверить это, просто установите непрозрачность фона на 0).

Одно предостережение: по моему опыту, это происходит с первым объектом в любом заданном слое. Так что я должен настроить каждый слой на сцене. В зависимости от вашего приложения это может быть или не быть лучше, чем добавление временных задержек в код.

Похоже, это ошибка Android, начиная с Android 4.1.x. В версии 4.0.x ее нет. И это не было исправлено в недавнем обновлении до 4.1.2, разосланном на этой неделе. Подобные проблемы были связаны с настройкой свойства overflow-x в CSS (см. http://code.google.com/p/android/issues/detail?can=2&start=0&num=100&q=&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars&groupby=&sort=&id=35474).

<script>
  window.onload = function() {
    var stage = new Kinetic.Stage({
      container: "container",
      width: 578,
      height: 200
    });

    var boxLayer = new Kinetic.Layer();
    stage.add(boxLayer);
        var background = new Kinetic.Rect({
          x: rectX,
          y: rectY,
          width: 578,
          height: 200,
          fill: "white",
          stroke: "white",
          strokeWidth: 4,
          draggable: false
        });
    boxLayer.add(background)
    boxLayer.draw();


    var rectX = stage.getWidth() / 2 - 50;
    var rectY = stage.getHeight() / 2 - 25;

    var box = new Kinetic.Rect({
      x: rectX,
      y: rectY,
      width: 100,
      height: 50,
      fill: "#00D2FF",
      stroke: "black",
      strokeWidth: 4,
      draggable: true,
      opacity: 1.0            
    });

    boxLayer.add(box);
    boxLayer.draw();


  };

</script>
person user1738934    schedule 13.10.2012

Сегодня я столкнулся с той же проблемой на Android 4.1.1, только моя проблема была еще более надоедливой. Я попробовал обходные пути setTimeout и «нарисовать фиктивный объект», предложенные в других ответах, но проблема все еще сохраняется. После нескольких проб и ошибок я обнаружил, что если я рисую фиктивный объект в течение первых нескольких кадров (первых двух кадров мне было достаточно), то холст впоследствии может быть успешно очищен.

Другая связанная с этим проблема заключается в том, что если я покажу всплывающее окно поверх холста, а затем закрою его, ошибка очистки холста произойдет снова. И на этот раз рисование фиктивных объектов в течение нескольких кадров больше не работает, и что работает для меня, так это сначала изменить размер холста, а затем нарисовать фиктивные объекты в течение нескольких кадров.

Очевидно, что это уродливые обходные пути, но они могут быть полезны другим, столкнувшимся с той же проблемой.

person ylian    schedule 30.10.2012
comment
Вау, спасибо, что опубликовал это. В моем случае я анимировал изображения, и установка изображения после того, как анимация прошла несколько кадров, предотвратила проблему ореолов. - person Booker; 23.04.2013

function drawImage(imageObj) {
    var stage = new Kinetic.Stage({
        container: "container",
        width: wW,
        height: wH
    }),
    timer = null,
    dummys = 1,
    layer = new Kinetic.Layer();

    timer = setInterval( function() {
        if( dummys >= 2 ) {
            clearInterval(timer);
            layer.clear();
            var darthVaderImg = new Kinetic.Image({
                image: imageObj,
                x: stage.getWidth() / 2 - 200 / 2,
                y: stage.getHeight() / 2 - 137 / 2,
                draggable: true
            });
            layer.add(darthVaderImg);
            stage.add(layer);   
        }else{
            var background = new Kinetic.Rect({
              x: 0,
              y: 0,
              width: wW,
              height: wH,
              fill: "white",
              draggable: false
            });
            layer.add(background)
            layer.draw();
            dummys++;
        }
    }, 10 );

}

var wH = window.innerHeight,
    wW = window.innerWidth,
    mCanvas = document.getElementById('container'),
    imageObj = new Image();

$(document).ready(function(){
    mCanvas.style.width = wW;
    mCanvas.style.height = wH;
    imageObj.src = 'img/darth-vader.jpg';
    imageObj.onload = function() {
        drawImage(this);
    };
});

работает как шарм

person Luke Snowden    schedule 27.11.2012