在HTML5中创建可拖动和可缩放的网格 [英] Creating a draggable and scaleable grid in HTML5

查看:114
本文介绍了在HTML5中创建可拖动和可缩放的网格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与其他HTML5 如何创建网格问题不同,我想知道如何使一个可拖动和可伸缩.

Unlike the other HTML5 how to create a grid questions, I'm wondering how to make one draggable and scalable.

绘制网格非常简单:

var c = document.getElementById('canvas');
var ctx = c.getContext('2d');
var width = window.innerWidth;
var height = window.innerHeight;

c.width = width;
c.height = height;

drawGrid(width, height, 40);

function drawGrid(gridWidth, gridHeight, boxSize) {
  ctx.clearRect(0, 0, c.width, c.height);
  ctx.beginPath();
  for (var i = 0; i <= gridWidth; i += boxSize) {
    ctx.moveTo(i, 0);
    ctx.lineTo(i, gridHeight);
  }
  for (var i = 0; i <= gridHeight; i += boxSize) {
    ctx.moveTo(0, i);
    ctx.lineTo(gridWidth, i);
  }
  ctx.strokeStyle = "rgba( 210, 210, 210, 1 )";
  ctx.stroke();
}

html,
body {
  overflow: hidden;
}

#canvas {
  position: absolute;
  top: 0;
  left: 0;
}

<canvas id="canvas"></canvas>

现在要使其可拖动,有很多方法可以实现,但是我专注于创建类似于以下内容的无限移动网格的错觉:

Now to make it draggable, there are many ways of doing it, but I focused on creating the illusion of an infinite moving grid similar to this:

示例图片 (对不起,还没有足够的学分)

Example Image (Sorry, don't have enough credits yet)

当图形向右移动时,画布大小中隐藏的线将移回开头,反之亦然.我不太确定如何使用鼠标移动网格以及缩放比例.与SVG不同,缩放时线条趋于模糊. 创建网格无限移动并缩放的最快方法是什么?

As the graph moves toward the right, the lines that are hidden from the canvas size are moved back to the beginning, and vice versa. I'm not too sure how to go about moving the grid with the mouse, as well as the scaling. The lines tend to blur when scaled unlike SVGs. What's the quickest way of creating a grid to move around infinitely and scale?

编辑: 我采用了类似的方法来移动网格,并使用图像模式填充屏幕.

EDIT: I took a similar approach to move the grid around using an image pattern to fill the screen.

var c = document.getElementById("canvas"),
  ctx = c.getContext("2d");
var width = window.innerWidth;
var height = window.innerHeight;
var itemIsSelected = false;
var clicked = function(e) {
  var x = e.pageX;
  var y = e.pageY;
}

draw(width, height);
draggable('#app');

function draw(width, height) {
  c.width = width;
  c.height = height;
  generateBackground();
}

function draggable(item) {
  var isMouseDown = false;
  document.onmousedown = function(e) {
    e.preventDefault();
    clicked.x = e.pageX;
    clicked.y = e.pageY;
    $(item).css('cursor', 'all-scroll');
    isMouseDown = true;
  };
  document.onmouseup = function(e) {
    e.preventDefault();
    isMouseDown = false;
    $(item).css('cursor', 'default');
  };
  document.onmousemove = function(e) {
    e.preventDefault();
    if (isMouseDown == true) {
      var mouseX = e.pageX;
      var mouseY = e.pageY;
      generateBackground(mouseX, mouseY, clicked.x, clicked.y);
    }
  };
}

function generateBackground(x, y, initX, initY) {
  distanceX = x - initX;
  distanceY = y - initY;
  ctx.clearRect(0, 0, c.width, c.height);
  var bgImage = document.getElementById("bg")
  var pattern = ctx.createPattern(bgImage, "repeat");
  ctx.rect(0, 0, width, height);
  ctx.fillStyle = pattern;
  ctx.fill();
  ctx.translate(Math.sqrt(distanceX), Math.sqrt(distanceY));
}

html,
body {
  overflow: hidden;
}

#canvas {
  top: 0;
  left: 0;
  position: absolute;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas"></canvas>
<img src="https://i.imgur.com/2MupHjw.png" id="bg" hidden>

此方法不允许我向左或向上滚动.它也可以加速一定距离后的拖动,并且不能很好地处理负向运动.

This method does not allow me to scroll left or up. It also speeds up the dragging after a distance and does not deal with negative motion well.

推荐答案

平移和缩放

我没有太多的常规,所以代码将不得不做大部分解释.

Pan and Zoom

I dont have much tine so the code will have to do most of the explaining.

下面的示例使用鼠标和鼠标滚轮进行平移和缩放.

The example below pans and zooms using the mouse and mouse wheel.

对象panZoom保存有关缩放(scale)和平移位置(xy)的信息

The object panZoom holds the information regarding the zoom (scale) and pan position (x, y)

要平移,只需使用鼠标位置更改来更改panZoom xy位置.您无需缩放鼠标移动,因为它们不会受到缩放的影响.

To pan just use the change in mouse position to change the panZoom x, y position. You dont need to scale the mouse movements as they are not effected by the zoom.

通过功能panZoom.scaleAt(x,y,scale)进行缩放,其中xy是鼠标位置,scaleBy是缩放比例的量.例如,panZoom.scaleAt(100,100, 2)将在100,100位置放大2倍,而panZoom.scaleAt(100,100, 1/2)将在相同位置放大2倍.有关更多详细信息,请参见update函数.

The zoom is via a function panZoom.scaleAt(x,y,scale) where x, y is the mouse position and scaleBy is the amount to scale the scale by. Eg panZoom.scaleAt(100,100, 2) will zoom in 2 times at position 100,100 and panZoom.scaleAt(100,100, 1/2) will zoom out 2 times at the same position. See update function for more details.

要绘制panZoom坐标系,您需要调用函数panZoom.apply,该函数设置上下文转换以匹配panZoom的设置.函数drawGrid是一个示例.它会绘制一个网格以适合当前的平移和缩放.

To draw in the panZoom coordinate system you need to call the function panZoom.apply which sets the context transform to match panZoom's settings. The function drawGrid is an example. It draws a grid to fit the current pan and zoom.

请注意,要恢复正常的屏幕坐标,只需调用ctx.setTransform(1,0,0,1,0,0)即可,如果要清除画布,则需要执行此操作.

Note that to restore the normal screen coordinates just call ctx.setTransform(1,0,0,1,0,0) which you will need to do if you want to clear the canvas.

const ctx = canvas.getContext("2d");
requestAnimationFrame(update);
const mouse  = {x : 0, y : 0, button : false, wheel : 0, lastX : 0, lastY : 0, drag : false};


function mouseEvents(e){
    const bounds = canvas.getBoundingClientRect();
    mouse.x = e.pageX - bounds.left - scrollX;
    mouse.y = e.pageY - bounds.top - scrollY;
    mouse.button = e.type === "mousedown" ? true : e.type === "mouseup" ? false : mouse.button;
    if(e.type === "wheel"){
        mouse.wheel += -e.deltaY;
        e.preventDefault();
    }
}
["mousedown", "mouseup", "mousemove", "wheel"].forEach(name => document.addEventListener(name,mouseEvents));


const panZoom = {
    x : 0,
    y : 0,
    scale : 1,
    apply() { ctx.setTransform(this.scale, 0, 0, this.scale, this.x, this.y) },
    scaleAt(x, y, sc) {  // x & y are screen coords, not world
        this.scale *= sc;
        this.x = x - (x - this.x) * sc;
        this.y = y - (y - this.y) * sc;
    },
}

function drawGrid(){
    const scale = 1 / panZoom.scale;
    var gridScale = 2 ** (Math.log2(128 * scale) | 0);
    var size = Math.max(w, h) * scale + gridScale * 2;
    var x = ((-panZoom.x * scale - gridScale) / gridScale | 0) * gridScale;
    var y = ((-panZoom.y * scale - gridScale) / gridScale | 0) * gridScale;
    panZoom.apply();
    ctx.lineWidth = 1;
    ctx.strokeStyle = "black";
    ctx.beginPath();
    for (i = 0; i < size; i += gridScale) {
        ctx.moveTo(x + i, y);
        ctx.lineTo(x + i, y + size);
        ctx.moveTo(x, y + i);
        ctx.lineTo(x + size, y + i);
    }
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset the transform so the lineWidth is 1
    ctx.stroke();
}   


var w = canvas.width;
var h = canvas.height;
function update(){
    ctx.setTransform(1, 0, 0, 1, 0, 0); // reset transform
    ctx.globalAlpha = 1;           // reset alpha
    if (w !== innerWidth || h !== innerHeight) {
        w = canvas.width = innerWidth;
        h = canvas.height = innerHeight;
    } else {
        ctx.clearRect(0, 0, w, h);
    }
    if (mouse.wheel !== 0) {
        let scale = 1;
        scale = mouse.wheel < 0 ? 1 / 1.01 : 1.01;
        mouse.wheel *= 0.8;
        if(Math.abs(mouse.wheel) < 1){
            mouse.wheel = 0;
        }
        panZoom.scaleAt(mouse.x, mouse.y, scale); //scale is the change in scale
    }
    if(mouse.button){
       if(!mouse.drag){
          mouse.lastX = mouse.x;
          mouse.lastY = mouse.y;
          mouse.drag = true;
       } else {
          panZoom.x += mouse.x - mouse.lastX;
          panZoom.y += mouse.y - mouse.lastY;
          mouse.lastX = mouse.x;
          mouse.lastY = mouse.y;
       }
    }else if(mouse.drag){
        mouse.drag = false;
    }
    drawGrid();
    requestAnimationFrame(update);
}

canvas { position : absolute; top : 0px; left : 0px; }

<canvas id="canvas"></canvas>

这篇关于在HTML5中创建可拖动和可缩放的网格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆