使每个画布线可拖放

tak*_*tak 2 html javascript jquery canvas

我可以在画布上画一些线。我想让每一行都可以拖动和放置。

但是,它是通过将不同行的位置存储在数组中来实现的,如何使它们中的每一个都像一个可拖放的实例?还是我弄错了?

你可以在这里查看代码

var storedLines = []

http://jsfiddle.net/m1erickson/NnZ7a/

非常感谢!

Bli*_*n67 8

画布可拖动。

要制作可拖动的线,您需要保留一组端点和一组线作为端点的索引。

然后,当用户在端点或线附近单击并拖动时,您只需根据鼠标移动的量更新端点。

一个点、一条线和一些列表

首先创建一个简单的点结构

const Point2 = (x,y) => ({x,y});  // creates a point
Run Code Online (Sandbox Code Playgroud)

然后是一个包含点数、添加点数以及您可能需要的其他内容的列表。

const list = {
    items : null,
    add(item) { this.items.push(item); return item },
    eachItem(callback) { 
        var i;
        while(i < this.items.length){
             callback(this.items[i],i);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后从列表结构创建一个点列表

function createList(extend){
    return Object.assign({},list,{items : []},extend);
}

const points = createList();
Run Code Online (Sandbox Code Playgroud)

线是一组点索引

const Line = (p1,p2) => ({p1,p2});
const lines = createList();
Run Code Online (Sandbox Code Playgroud)

寻找最近的

要从鼠标坐标中选择一个点,您需要找到离鼠标最近的点。

// this will extend the points list
function getClosestPoint(from ,minDist) {
    var closestPoint;
    this.eachItem(point => {
        const dist = Math.hypot(from.x - point.x, from.y - point.y);
        if(dist < minDist){
            closestPoint = point;
            minDist = dist;
        }
    });
    return closestPoint;
}
Run Code Online (Sandbox Code Playgroud)

线路也是如此,但这并不那么简单。您需要一个函数来查找点与线段的距离。

function distanceLineFromPoint(line,point){
    const lx = points.items[line.p1].x;
    const ly = points.items[line.p1].y;
    const v1x = points.items[line.p2].x - lx;
    const v1y = points.items[line.p2].y - ly;
    const v2x = point.x - lx;
    const v2y = point.y - ly;
    // get unit dist of closest point
    const u = (v2x * v1x + v2y * v1y)/(v1y * v1y + v1x * v1x);
    if(u >= 0 && u <= 1){  // is the point on the line
        return Math.hypot(lx + v1x * u - point.x, ly + v1y * u - point.y);
    } else if ( u < 0 ) {  // point is before start
        return Math.hypot(lx - point.x, ly - point.y);
    }
    // point is after end of line
    return Math.hypot(points.items[line.p2].x - point.x, points.items[line.p2].y - point.y);
}

// this will extend the lines list
function getClosestline(from ,minDist) {
    var closestLine;
    this.eachItem(line => {
        const dist = distanceLineFromPoint(line,from);
        if(dist < minDist){
            closestLine = line;
            minDist = dist;
        }
    });
    return closestLine;
}
Run Code Online (Sandbox Code Playgroud)

使用这些函数,我们应该扩展列表对象,以便使用扩展重新创建它们。

 const points = createList({getClosest : getClosestPoint});
 const lines = createList({getClosest : getClosestline});
Run Code Online (Sandbox Code Playgroud)

然后剩下的就是实现一个鼠标界面和一个渲染功能。您可以添加可拖动的点和连接它们的线。如果在一条线或点附近单击,则可以拖动它们。该片段显示了其余部分。

用户反馈很重要

显示正确的用户反馈也很重要。您需要设置光标、工具提示(通过 canvas.style.cursor 和 canvas.title)并突出显示将受到影响的对象,以便用户知道将发生什么操作以及单击和拖动时会发生什么。

此外,您应该将鼠标事件设置为文档而不是画布,因为这将捕获鼠标拖动,允许用户在您仍然获得 mouseup 和移动事件的同时拖动到画布之外。

创建并拖动点和线。

const Point2 = (x,y) => ({x,y});  // creates a point
Run Code Online (Sandbox Code Playgroud)
const list = {
    items : null,
    add(item) { this.items.push(item); return item },
    eachItem(callback) { 
        var i;
        while(i < this.items.length){
             callback(this.items[i],i);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
function createList(extend){
    return Object.assign({},list,{items : []},extend);
}

const points = createList();
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢,解释很清楚,解决方案很棒。感谢! (2认同)