mcanvas vs svg vs html5 canvas

2019-08-16 07:31发布

I have tested recently in the mobile browser which has Raphael canvas where we can draw lines etc using tablet.

The speed and precision lacks when using svg to draw on browser for example, the lines breaks in between when drawing even though the touch is not stopped during the move etc.

So I m researching on what is used in the drawing app which are working perfectly for touch screens.

And if we want to have an drawing app on mobile browser which is best canvas or svg or neither as we don't want breaking lines when drawing?

And where I can start research more on drawing api's that used by android for drawing that is used by"pen memo, S2 and other touching apps".

Updated: check this jsfiddle

var canvas = $("#canvas");
paper = Raphael("canvas");
var clicking = false;
var line;
var pathArray = [];

 canvas.bind("mousedown", _mousedownHandler);
 canvas.bind("touchstart", _mousedownHandler);
function _mousedownHandler(event){
     clicking = true;
 // _drawArrowLineBegin(e);
        if(event.type == "touchstart"){
            event.preventDefault(); 
            event = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];
        }
    _drawFreeLineBegin(event);
};

function _mousemoveHandler(event){
 // _drawArrowLineMove(event);
        if(event.type == "touchmove"){
            event.preventDefault(); 
            event = event.originalEvent.touches[0] || event.originalEvent.changedTouches[0];
        }
    _drawFreeLineMove(event);
};
function _mouseupHandler(event){
    clicking = false;
};
function _enableEvents(){
           canvas.bind("mousemove.mmu", _mousemoveHandler);
        canvas.one("mouseup.mmu", _mouseupHandler);
        canvas.bind("touchmove.mmu", _mousemoveHandler);
        canvas.one("touchend.mmu", _mouseupHandler);
};
function _drawArrowLineBegin(e) {
    clicking = true;
        line = paper.path("M" + (e.offsetX || e.clientX) + " " + (e.offsetY || e.clientY) + "L" + (e.offsetX || e.clientX) + " " + (e.offsetY || e.clientY)).attr({stroke:'#FF0000', 'stroke-width': 2, 'arrow-end': 'classic-wide-long'});
    pathArray = line.attr("path");
 _enableEvents();
    }
function _drawArrowLineMove(e){
        if(clicking == false) return;
    if (pathArray[1][1] != undefined) { // not IE 8
        pathArray[1][1] = e.offsetX || e.clientX;
        pathArray[1][2] = e.offsetY || e.clientY;
    } else {
        pathArray = pathArray.replace(/L\d+ \d+$/, "L" + e.offsetX + " " + e.offsetY);
    }

    line.attr({path: pathArray});
}
function _drawFreeLineBegin(e) {
    clicking = true;
       line =  paper.path("M"
                + (e.pageX) + ","
                + (e.pageY)).attr({stroke:'#FF0000', 'stroke-width': 2});
     pathArray = line.attr("path");
_enableEvents();
    }
function _drawFreeLineMove(e){
        if(clicking == false) return;
    line.attr("path",line.attr("path")
                        + "L"
                                    + (e.pageX)
                                    + ","
                                    + (event.pageY));
}

1条回答
等我变得足够好
2楼-- · 2019-08-16 07:55

The issue mentioned regarding speed and performance is more intrinsic to the JavaScript library being used in SVG. In your fiddle, the performance issue in drawing is primarily because of the ever-expanding array of path and the fact that the entire path array is re-processed on every touch move. There is no simple way to fix this than working around it.

I have recreated your implementation with pure Raphael (and no jQuery.) http://jsfiddle.net/shamasis/kUQ7E/

The implementation has two aspects:

  1. It bypasses Raphael's heavy attr function and directly sets the element's path using doodle.node.setAttribute('d', pathstring);
  2. It uses a timeout to ignore touch up and down within a tolerable interval.

The fiddle (as of revision 24) looks like:

Raphael("canvas", function () {
    var win = Raphael._g.win,
        doc = win.document,
        hasTouch = "createTouch" in doc,

        M = "M",
        L = "L",
        d = "d",
        COMMA = ",",
        // constant for waiting doodle stop
        INTERRUPT_TIMEOUT_MS = hasTouch ? 100 : 1,
        // offset for better visual accuracy
        CURSOR_OFFSET = hasTouch ? 0 : -10,

        paper = this,
        path = "", // hold doodle path commands
        // this element draws the doodle
        doodle = paper.path(path).attr({
            "stroke": "rgb(255,0,0)"
        }),

        // this is to capture mouse movements
        tracker = paper.rect(0, 0, paper.width, paper.height).attr({
            "fill": "rgb(255,255,255)",
            "fill-opacity": "0.01"
        }),
        active = false, // flag to check active doodling
        repath = false, // flag to check if a new segment starts
        interrupt; // this is to connect jittery touch

    tracker.mousedown(function () {
        interrupt && (interrupt = clearTimeout(interrupt));
        active = true;
        repath = true;
    });

    tracker.mousemove(function (e, x, y) {
        // do nothing if doodling is inactive
        if (!active) {
            return;
        }

        // Fix for Raphael's touch xy bug
        if (hasTouch && 
                (e.originalEvent.targetTouches.length === 1)) {
            x = e.clientX + 
                (doc.documentElement.scrollTop || doc.body.scrollTop || 0);
            y = e.clientY + 
                (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0);
            e.preventDefault();
        }

        // Insert move command for a new segment
        if (repath) {
            path += M + (x + CURSOR_OFFSET) + COMMA + 
                    (y + CURSOR_OFFSET);
            repath = false;
        }
        path += L + (x + CURSOR_OFFSET) + COMMA + 
                (y + CURSOR_OFFSET); // append line point

        // directly access SVG element and set path
        doodle.node.setAttribute(d, path);
    });

    // track window mouse up to ensure mouse up even outside
    // paper works.
    Raphael.mouseup(function () {
        interrupt && (interrupt = clearTimeout(interrupt));
        // wait sometime before deactivating doodle
        interrupt = setTimeout(function () {
            active = false;
        }, INTERRUPT_TIMEOUT_MS);
    });
});
查看更多
登录 后发表回答