将可见网络复制到另一个画布

问题描述

我正在实施一个“放大镜”,即。跟随鼠标指针的“放大镜”。可视网络图的一部分在放大镜中放大显示(这样您就可以在不放大整个网络的情况下看到细节)。我通过创建一个与可见网络具有相同节点和边缘以及相同视点的屏幕外可见网络来做到这一点,但规模是其三倍。然后我使用 canvas drawImage 将这个较大网络的一部分画布复制到一个 div 中,该 magicNumber 浮动在可见网络上方,并以鼠标指针为中心。这一切都很好,只是我在将放大的图像与正在放大的可见地图部分对齐时遇到了问题。

在我的第一次尝试中,放大显示的地图部分与可见地图上鼠标指针的位置相距很远。但是在一个乏味的实验过程中,我设法确定我需要一个乘数(我在下面的代码中将其称为 .magnifier { display: none; position: absolute; border: 1px black solid; Box-shadow: 5px 5px 10px #1e1e1e; border-radius: 50%; z-index: 5000; } )来使其大致正确,即,放大镜显示指针下的网络位。我希望这个神奇的数字在 vis-network 中实际上是某个常数,但我无法想象它会是什么 - 正确的值可能不完全是我通过实验获得的 1.92。

因此我的问题是:这个数字应该是什么,它是什么意思?

这里有一个 MVE https://codepen.io/micrology/pen/eYBbKVX

这是我的代码的摘录 - 首先是放大镜的 CSS,然后是 JavaScript:

    const magSize = 300; // diameter of loupe
    const magnification = 3; // magnification
    let main = elem('main');  // div holding the visible network
    let mainRect = main.getBoundingClientRect();
    let magnifier = document.createElement('canvas');  // the 'magnifying glass'
    magnifier.width = magSize;
    magnifier.height = magSize;
    magnifier.className = 'magnifier';
    let magnifierCtx = magnifier.getContext('2d');
    magnifierCtx.fillStyle = 'white';
    main.appendChild(magnifier);
    let bigNetPane = null;
    let bigNetwork = null;
    let bigNetCanvas = null;
    const magicNumber = 1.92;  / the mysterIoUs magic number

// the loupe pops up when the user holds down the SHIFT key and moves the mouse

    window.addEventListener('keydown',(e) => {
        if (e.shiftKey) createMagnifier();
    });
    window.addEventListener('mousemove',(e) => {
        if (e.shiftKey) showMagnifier(e);
    });
    window.addEventListener('keyup',(e) => {
        if (e.key == 'Shift') closeMagnifier();
    });

    function createMagnifier() {
        if (bigNetPane) {
            bigNetwork.destroy();
            bigNetPane.remove();
        }
        // the triple sized version of the netowrk is generated inside the bigNetPane div,which is off screen
        bigNetPane = document.createElement('div');
        bigNetPane.id = 'big-net-pane';
        bigNetPane.style.position = 'absolute';
        bigNetPane.style.top = '-9999px';
        bigNetPane.style.left = '-9999px';
        bigNetPane.style.width = `${netPane.offsetWidth * magnification}px`;
        bigNetPane.style.height = `${netPane.offsetHeight * magnification}px`;
        main.appendChild(bigNetPane);
        bigNetwork = new Network(bigNetPane,data,options);
        bigNetCanvas = bigNetPane.firstElementChild.firstElementChild;
        bigNetwork.moveto({
            position: network.getViewPosition(),scale: magnification * network.getScale(),});
        main.style.cursor = 'none';
        magnifier.style.display = 'none';
    }

    function showMagnifier(e) {
        e.preventDefault();
        if (bigNetCanvas == null) createMagnifier(e);
        magnifierCtx.fillRect(0,magSize,magSize);
// this is where the magicNumber is required to line up the enlarged image with where the pointer is
        magnifierCtx.drawImage(
            bigNetCanvas,(e.x - mainRect.x) * magicNumber * magnification,(e.y - mainRect.y) * magicNumber * magnification,magSize
        );
        magnifier.style.top = e.clientY - mainRect.y - magSize / 2 + 'px';
        magnifier.style.left = e.clientX - mainRect.x - magSize / 2 + 'px';
        magnifier.style.display = 'block';
    }


    function closeMagnifier() {
        if (bigNetPane) {
            bigNetwork.destroy();
            bigNetPane.remove();
        }
        main.style.cursor = 'default';
        magnifier.style.display = 'none';
    }
watch

解决方法

我现在已经开始工作了。 CodePen 演示已经过编辑,因此现在可以正常工作。更正后的代码片段(与问题中的代码进行比较)是:

const magSize = 300; // diameter of loupe
const magnification = 3; // magnification
const halfMagSize = magSize / 2.0;
let main = elem("mynetwork");
let mainRect = main.getBoundingClientRect();
let magnifier = document.createElement("canvas");
magnifier.width = magSize;
magnifier.height = magSize;
magnifier.className = "magnifier";
let magnifierCtx = magnifier.getContext("2d");
magnifierCtx.fillStyle = "white";
main.appendChild(magnifier);
let bigNetPane = null;
let bigNetwork = null;
let bigNetCanvas = null;
let netPaneCanvas = container.firstElementChild.firstElementChild;

window.addEventListener("keydown",(e) => {
  if (e.shiftKey) createMagnifier();
});
window.addEventListener("mousemove",(e) => {
  if (e.shiftKey) showMagnifier(e);
});
window.addEventListener("keyup",(e) => {
  if (e.key == "Shift") closeMagnifier();
});

function showMagnifier(e) {
  e.preventDefault();
  if (bigNetCanvas == null) createMagnifier(e);
  magnifierCtx.fillRect(0,magSize,magSize);
  magnifierCtx.drawImage(
    bigNetCanvas,((e.clientX - mainRect.x) * bigNetCanvas.width) /
      netPaneCanvas.clientWidth -
      halfMagSize,((e.clientY - mainRect.y) * bigNetCanvas.height) /
      netPaneCanvas.clientHeight -
      halfMagSize,magSize
  );
  magnifier.style.top = e.clientY - halfMagSize + "px";
  magnifier.style.left = e.clientX - halfMagSize + "px";
  magnifier.style.display = "block";
}

function createMagnifier() {
  if (bigNetPane) {
    bigNetwork.destroy();
    bigNetPane.remove();
  }
  network.storePositions();
  bigNetPane = document.createElement("div");
  bigNetPane.id = "big-net-pane";
  bigNetPane.style.position = "absolute";
  bigNetPane.style.top = "-9999px";
  bigNetPane.style.left = "-9999px";
  bigNetPane.style.width = `${main.offsetWidth * magnification}px`;
  bigNetPane.style.height = `${main.offsetHeight * magnification}px`;
  main.appendChild(bigNetPane);
  bigNetwork = new vis.Network(bigNetPane,data,{
    physics: { enabled: false }
  });
  bigNetCanvas = bigNetPane.firstElementChild.firstElementChild;
  bigNetwork.moveTo({
    position: network.getViewPosition(),scale: network.getScale() * magnification,animation: false
  });
  main.style.cursor = "none";
  magnifier.style.display = "none";
}
function closeMagnifier() {
  if (bigNetPane) {
    bigNetwork.destroy();
    bigNetPane.remove();
  }
  main.style.cursor = "default";
  magnifier.style.display = "none";
}