How to cache a whole layer right before dragstart and revert it back on dragend?

后端 未结 1 1456
抹茶落季
抹茶落季 2021-01-21 19:20

I\'m currently trying to speed my web app for mobile devices a little bit up, but now I\'m stuck at the most important part - caching. How is it possible to cache a entire layer

相关标签:
1条回答
  • 2021-01-21 19:32

    Based on this statement:

    stage.on('mousedown touchstart', function(){ // CACHING})
    

    I'm assuming that on mousedown touchstart you call layer.toImage() or stage.toImage() and you want to drag the new image on that one click/tap.

    1. You can invoke the drag event on the new generated image by using the .startDrag() function: Kinetic.Shape#startDrag

      You can then invoke .stopDrag() on mouseup touchend to stop the drag. Kinetic.Shape#stopDrag

      Something like:

      var image, ox, oy;
      
      stage.on('mousedown touchstart', function(){
        // CACHING
        stage.toImage({
          width: stage.getWidth(),
          height: stage.getHeight(),
          callback: function(img) {
            var image = new Kinetic.Image({
              image: img,
              draggable: true
            });
            ox = image.getX();
            oy = image.getY();
            image.startDrag();
          }            
        });
      });
      
      stage.on('mouseup touchend', function(){
        image.stopDrag();
      
        //Calculate dx, dy to update nodes.
        var newX = image.getX();
        var newY = image.getY();
        var dx = newX-ox;
        var dy = newY-oy;
      
        var children = layer.getChildren();
        for (var i=0; i<children.length; i++) {
          children.setX(children.getX()+dx);
          children.setY(children.getY()+dy);
        }
      
        image.hide(); //or remove() or destroy()
        layer.draw();
      });
      

      Note you need to update your original nodes after dragging the cached layer.

      Another Note I haven't tested the code but I believe you could do something along the lines of what I've got up there.

      Small UPDATE: You also should probably hide() the original layer while dragging the cached layer image! :) And then show() it again when you hide the cached image layer.

    2. Honestly I'm not sure how you would speed up that cache time unless you can predict when the user needs to click/tap the stage to move. I think your suggestion would cost more performance than it would save.

      I'm guessing that the desktop caches the image faster than on your mobile? It might fall into just being a limitation of KineticJS performance on Mobile vs Desktop...

    UPDATE

    Okay, I have an idea for #2, it's not exactly a fix but it might work better for you.

    1. Separate your stage mousedown event with your touchstart event. mousedown will be the same but touchstart we want to handle differently.

    2. On stage touchstart we want to drag the entire stage like normal, but meanwhile run the code for the original mousedown to cache the layer.

    3. When the cached image finishes loading (takes 1-2 seconds you say), use .stopDrag() on the original stage and hide it. At this moment you want to store the current x and y values of the stage, so that you can still calculate dx,dy. Then immediately call .startDrag() on the new cached image and continue on like we did for mousedown.

    How to know when the cached image finishes loading? I think that's what the toImage() callback function is for. If not, than hopefully a javascript onload event will work to determine when the image finishes generating.

    The end result will be that you'll get your slow choppy drag on the stage for touch events UNTIL the image is cached. Then we flip the switch and stop dragging the stage, start dragging the cached image, and then revert/update the stage on touchend.

    Hope that works as a semi-solution to your problem...

    ANOTHER UPDATE

    Okay here's another idea that actually might help your performance!

    If your stage isn't modifying nodes very often, you can pre-cache the stage image so that it's already generated, and .hide() it. Then when you need to drag it, you just need to set the x,y of the cached image to match the stage's current x,y and then .show() the cached image. This will eliminate the time needed to wait/load the cached image when you first start dragging.

    If you do happen to add a node or move a node or anything, after that cache the image. Hopefully this is manageable as we don't want to cache the image too often (drains performance). Again the cached image will be ready for your stage.drag event beforehand.

    The goal is to have the stage cached before you do mousedown touchstart and start dragging. Hopefully this helps.

    0 讨论(0)
提交回复
热议问题