【问题标题】:how to convert canvas code for rendering rectangle to svg如何将用于渲染矩形的画布代码转换为 svg
【发布时间】:2015-08-18 20:05:31
【问题描述】:

我有用于拖动和调整矩形大小的画布代码。但我无法将此画布代码转换为 svg。如何将画布代码转换为 svg。

那个 stackoverflow 链接不适合我。

提前致谢。

var canvas = document.getElementById('canvas'),
    ctx = canvas.getContext('2d'),
    rect = {
        x: 150,
        y: 100,
        w: 123,
        h: 58
    },
    handlesSize = 8,
    currentHandle = false,
    drag = false;

function init() {
    canvas.addEventListener('mousedown', mouseDown, false);
    canvas.addEventListener('mouseup', mouseUp, false);
    canvas.addEventListener('mousemove', mouseMove, false);
}

function point(x, y) {
    return {
        x: x,
        y: y
    };
}

function dist(p1, p2) {
    return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}

function getHandle(mouse) {
    if (dist(mouse, point(rect.x, rect.y)) <= handlesSize) return 'topleft';
    if (dist(mouse, point(rect.x + rect.w, rect.y)) <= handlesSize) return 'topright';
    if (dist(mouse, point(rect.x, rect.y + rect.h)) <= handlesSize) return 'bottomleft';
    if (dist(mouse, point(rect.x + rect.w, rect.y + rect.h)) <= handlesSize) return 'bottomright';
    if (dist(mouse, point(rect.x + rect.w / 2, rect.y)) <= handlesSize) return 'top';
    if (dist(mouse, point(rect.x, rect.y + rect.h / 2)) <= handlesSize) return 'left';
    if (dist(mouse, point(rect.x + rect.w / 2, rect.y + rect.h)) <= handlesSize) return 'bottom';
    if (dist(mouse, point(rect.x + rect.w, rect.y + rect.h / 2)) <= handlesSize) return 'right';
    return false;
}

function mouseDown(e) {
    if (currentHandle) drag = true;
    draw();
}

function mouseUp() {
    drag = false;
    currentHandle = false;
    draw();
}

function mouseMove(e) {
    var previousHandle = currentHandle;
    if (!drag) currentHandle = getHandle(point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop));
    if (currentHandle && drag) {
        var mousePos = point(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
        switch (currentHandle) {
            case 'topleft':
                rect.w += rect.x - mousePos.x;
                rect.h += rect.y - mousePos.y;
                rect.x = mousePos.x;
                rect.y = mousePos.y;
                break;
            case 'topright':
                rect.w = mousePos.x - rect.x;
                rect.h += rect.y - mousePos.y;
                rect.y = mousePos.y;
                break;
            case 'bottomleft':
                rect.w += rect.x - mousePos.x;
                rect.x = mousePos.x;
                rect.h = mousePos.y - rect.y;
                break;
            case 'bottomright':
                rect.w = mousePos.x - rect.x;
                rect.h = mousePos.y - rect.y;
                break;

            case 'top':
                rect.h += rect.y - mousePos.y;
                rect.y = mousePos.y;
                break;

            case 'left':
                rect.w += rect.x - mousePos.x;
                rect.x = mousePos.x;
                break;

            case 'bottom':
                rect.h = mousePos.y - rect.y;
                break;

            case 'right':
                rect.w = mousePos.x - rect.x;
                break;
        }
    }
    if (drag || currentHandle != previousHandle) draw();
}

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = 'black';
    ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
    if (currentHandle) {
        var posHandle = point(0, 0);
        switch (currentHandle) {
            case 'topleft':
                posHandle.x = rect.x;
                posHandle.y = rect.y;
                break;
            case 'topright':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y;
                break;
            case 'bottomleft':
                posHandle.x = rect.x;
                posHandle.y = rect.y + rect.h;
                break;
            case 'bottomright':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y + rect.h;
                break;
            case 'top':
                posHandle.x = rect.x + rect.w / 2;
                posHandle.y = rect.y;
                break;
            case 'left':
                posHandle.x = rect.x;
                posHandle.y = rect.y + rect.h / 2;
                break;
            case 'bottom':
                posHandle.x = rect.x + rect.w / 2;
                posHandle.y = rect.y + rect.h;
                break;
            case 'right':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y + rect.h / 2;
                break;
        }
        ctx.globalCompositeOperation = 'xor';
        ctx.beginPath();
        ctx.arc(posHandle.x, posHandle.y, handlesSize, 0, 2 * Math.PI);
        ctx.fill();
        ctx.globalCompositeOperation = 'source-over';
    }
}

init();
draw();

这里是在画布中渲染矩形的小提琴链接:

http://jsfiddle.net/BaliBalo/9HXMG/

【问题讨论】:

  • 从头开始重写。 svg 是一种 XML 标记语言,而 canvas 是一种像素绘图上下文。您应该像使用 HTML 元素一样编写 svg 代码。
  • 据我记忆,将 Canvas 转换为 SVG 是不可能的。反之亦然。
  • @Kaiido 你所说的是正确的。但我不知道如何将这个画布上下文更改为 html 元素。

标签: javascript html canvas svg


【解决方案1】:

将其转换为 SVG 非常简单。

唯一的小问题是我们必须添加一些处理以适应矩形宽度或高度为负数的情况。 Canvas2D 不介意,但 SVG 会。

此外,在绘制拖动手柄时,没有一种简单的方法可以模拟 XOR 操作。所以我只是把它们变成了纯蓝色。

var canvas = document.getElementById('canvas'),
    rect = {
        x: 150,
        y: 100,
        w: 123,
        h: 58
    },
    handlesSize = 8,
    currentHandle = false,
    drag = false
    svgns = 'http://www.w3.org/2000/svg';

function init() {
    canvas.addEventListener('mousedown', mouseDown, false);
    canvas.addEventListener('mouseup', mouseUp, false);
    canvas.addEventListener('mousemove', mouseMove, false);
}

function point(x, y) {
    return {
        x: x,
        y: y
    };
}

function dist(p1, p2) {
    return Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
}

function getHandle(mouse) {
    if (dist(mouse, point(rect.x, rect.y)) <= handlesSize) return 'topleft';
    if (dist(mouse, point(rect.x + rect.w, rect.y)) <= handlesSize) return 'topright';
    if (dist(mouse, point(rect.x, rect.y + rect.h)) <= handlesSize) return 'bottomleft';
    if (dist(mouse, point(rect.x + rect.w, rect.y + rect.h)) <= handlesSize) return 'bottomright';
    if (dist(mouse, point(rect.x + rect.w / 2, rect.y)) <= handlesSize) return 'top';
    if (dist(mouse, point(rect.x, rect.y + rect.h / 2)) <= handlesSize) return 'left';
    if (dist(mouse, point(rect.x + rect.w / 2, rect.y + rect.h)) <= handlesSize) return 'bottom';
    if (dist(mouse, point(rect.x + rect.w, rect.y + rect.h / 2)) <= handlesSize) return 'right';
    return false;
}

function mouseDown(e) {
    if (currentHandle) drag = true;
    draw();
}

function mouseUp() {
    drag = false;
    currentHandle = false;
    draw();
}

function mouseMove(e) {
    var previousHandle = currentHandle;
    var svgPos = this.getBoundingClientRect();
    if (!drag) currentHandle = getHandle(point(e.pageX - svgPos.left, e.pageY - svgPos.top));
    if (currentHandle && drag) {
        var mousePos = point(e.pageX - svgPos.left, e.pageY - svgPos.top);
        switch (currentHandle) {
            case 'topleft':
                rect.w += rect.x - mousePos.x;
                rect.h += rect.y - mousePos.y;
                rect.x = mousePos.x;
                rect.y = mousePos.y;
                break;
            case 'topright':
                rect.w = mousePos.x - rect.x;
                rect.h += rect.y - mousePos.y;
                rect.y = mousePos.y;
                break;
            case 'bottomleft':
                rect.w += rect.x - mousePos.x;
                rect.x = mousePos.x;
                rect.h = mousePos.y - rect.y;
                break;
            case 'bottomright':
                rect.w = mousePos.x - rect.x;
                rect.h = mousePos.y - rect.y;
                break;

            case 'top':
                rect.h += rect.y - mousePos.y;
                rect.y = mousePos.y;
                break;

            case 'left':
                rect.w += rect.x - mousePos.x;
                rect.x = mousePos.x;
                break;

            case 'bottom':
                rect.h = mousePos.y - rect.y;
                break;

            case 'right':
                rect.w = mousePos.x - rect.x;
                break;
        }
    }
    if (drag || currentHandle != previousHandle) draw();
}

function draw() {
    //ctx.clearRect(0, 0, canvas.width, canvas.height);
    while (canvas.firstChild) {
        canvas.removeChild(canvas.firstChild);
    }
    //ctx.fillStyle = 'black';
    //ctx.fillRect(rect.x, rect.y, rect.w, rect.h);
    var svgrect = document.createElementNS(svgns, 'rect');
    svgrect.setAttribute('x', Math.min(rect.x, rect.x+rect.w));
    svgrect.setAttribute('y', Math.min(rect.y, rect.y+rect.h));
    svgrect.setAttribute('width', Math.abs(rect.w));
    svgrect.setAttribute('height', Math.abs(rect.h));
    canvas.appendChild(svgrect);

    if (currentHandle) {
        var posHandle = point(0, 0);
        switch (currentHandle) {
            case 'topleft':
                posHandle.x = rect.x;
                posHandle.y = rect.y;
                break;
            case 'topright':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y;
                break;
            case 'bottomleft':
                posHandle.x = rect.x;
                posHandle.y = rect.y + rect.h;
                break;
            case 'bottomright':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y + rect.h;
                break;
            case 'top':
                posHandle.x = rect.x + rect.w / 2;
                posHandle.y = rect.y;
                break;
            case 'left':
                posHandle.x = rect.x;
                posHandle.y = rect.y + rect.h / 2;
                break;
            case 'bottom':
                posHandle.x = rect.x + rect.w / 2;
                posHandle.y = rect.y + rect.h;
                break;
            case 'right':
                posHandle.x = rect.x + rect.w;
                posHandle.y = rect.y + rect.h / 2;
                break;
        }
        //ctx.globalCompositeOperation = 'xor';
        //ctx.beginPath();
        //ctx.arc(posHandle.x, posHandle.y, handlesSize, 0, 2 * Math.PI);
        //ctx.fill();
        //ctx.globalCompositeOperation = 'source-over';
        var circ = document.createElementNS(svgns, 'circle');
        circ.setAttribute('cx', posHandle.x);
        circ.setAttribute('cy', posHandle.y);
        circ.setAttribute('r', handlesSize);
        circ.setAttribute('fill', 'blue');
        canvas.appendChild(circ);
    }
}

init();
draw();
&lt;svg id="canvas" width="500" height="500"&gt;&lt;/svg&gt;

【讨论】:

  • 另外,直接翻译似乎不是一个好主意,我的意思是画布意味着执行大量重绘,但在这里,您正在创建和删除很多元素。在浏览器执行garbageCollection之前,那些不会填充内存吗?只创建一次这 7 个元素,然后在拖动时更改它们的 x y 属性(以及 rect 的 widthheight)不是更好吗?
  • 是的,它可以改进。理想情况下,它会更新元素而不是重新创建它们。我想让 OP 保持简单。
  • 是的,它在 Firefox 和 IE 中也不起作用。如何更改适用于所有浏览器的代码
  • offsetLeft 仅适用于 HTML 元素。你依赖于一个 Chrome 错误 w3.org/TR/cssom-view/#extensions-to-the-htmlelement-interface
  • 实际上在此代码画布中创建了基于矩形的矩形。但我想在 svg 中绘制矩形。像这样。
猜你喜欢
  • 1970-01-01
  • 2017-07-30
  • 1970-01-01
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 2018-05-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多