简体   繁体   中英

Scaling bug with multi-touch Canvas scale with pinch zoom

Using the sample code from Konvajs.org as a base ( https://konvajs.org/docs/sandbox/Multi-touch_Scale_Stage.html ), I have added a large SVG to a layer (4096 x 3444) to experiment with zoom / pan of a vector-based map, base64 encoded SVG in this instance. Initial impressions are good however during testing I experience an odd bug where during a pinch the view of the map would snap to a different location on the map not the area that I centred on.

Here is the code (map base64 code removed due to length):

// by default Konva prevent some events when node is dragging
// it improve the performance and work well for 95% of cases
// we need to enable all events on Konva, even when we are dragging a node
// so it triggers touchmove correctly
Konva.hitOnDragEnabled = true;

var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height,
  draggable: true,
});

var layer = new Konva.Layer();

var triangle = new Konva.RegularPolygon({
  x: 190,
  y: stage.height() / 2,
  sides: 3,
  radius: 80,
  fill: 'green',
  stroke: 'black',
  strokeWidth: 4,
});

var circle = new Konva.Circle({
  x: 380,
  y: stage.height() / 2,
  radius: 70,
  fill: 'red',
  stroke: 'black',
  strokeWidth: 4,
});

let bg = new Konva.Image({
    width: 4096,
    height: 3444
});
layer.add(bg);

var image = new Image();
image.onload = function() {
    bg.image(image);
    layer.draw();
};

image.src = 'data:image/svg+xml;base64,...';

function getDistance(p1, p2) {
  return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}

function getCenter(p1, p2) {
  return {
    x: (p1.x + p2.x) / 2,
    y: (p1.y + p2.y) / 2,
  };
}
var lastCenter = null;
var lastDist = 0;

stage.on('touchmove', function (e) {
  e.evt.preventDefault();
  var touch1 = e.evt.touches[0];
  var touch2 = e.evt.touches[1];

  if (touch1 && touch2) {
    // if the stage was under Konva's drag&drop
    // we need to stop it, and implement our own pan logic with two pointers
    if (stage.isDragging()) {
      stage.stopDrag();
    }

    var p1 = {
      x: touch1.clientX,
      y: touch1.clientY,
    };
    var p2 = {
      x: touch2.clientX,
      y: touch2.clientY,
    };

    if (!lastCenter) {
      lastCenter = getCenter(p1, p2);
      return;
    }
    var newCenter = getCenter(p1, p2);

    var dist = getDistance(p1, p2);

    if (!lastDist) {
      lastDist = dist;
    }

    // local coordinates of center point
    var pointTo = {
      x: (newCenter.x - stage.x()) / stage.scaleX(),
      y: (newCenter.y - stage.y()) / stage.scaleX(),
    };

    var scale = stage.scaleX() * (dist / lastDist);

    stage.scaleX(scale);
    stage.scaleY(scale);

    // calculate new position of the stage
    var dx = newCenter.x - lastCenter.x;
    var dy = newCenter.y - lastCenter.y;

    var newPos = {
      x: newCenter.x - pointTo.x * scale + dx,
      y: newCenter.y - pointTo.y * scale + dy,
    };

    stage.position(newPos);

    lastDist = dist;
    lastCenter = newCenter;
  }
});

stage.on('touchend', function () {
  lastDist = 0;
  lastCenter = null;
});


layer.add(triangle);
layer.add(circle);
stage.add(layer);

I am unsure if this is due to the large size of the image and / or canvas or an inherent flaw in the example code from Konvas.js. This has been tested, with the same results, on 2 models of iPad Pro, iPhone X & 11, Android Pixel 3, 5 and 6 Pro.

Here is the code on codepen as an example: https://codepen.io/mr-jose/pen/WNXgbdG

Any help would be appreciated, thanks!

I faced the same issue and discovered that it was caused by the dragging functionality of the stage. Everytime if (stage.isDragging()) evaluated to true, the jump happened.

For me what worked was setting draggable to false while pinch zooming and back to true on touch end.

stage.on('touchmove', function (e) {
  ...
  if (touch1 && touch2) {
    stage.draggable(false);
    ....
  }
});

stage.on('touchend', function (e) {
  ...
  stage.draggable(true);
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM