Implementing smooth sketching and drawing on the element

前端 未结 7 494
粉色の甜心
粉色の甜心 2021-01-29 20:20

I am trying to create a drawing area with canvas. I am having trouble with making the lines look smooth when drawing curves and I also have changing line thickness in my algorit

相关标签:
7条回答
  • 2021-01-29 20:48

    Seems that you need to use some brushes in your canvas. It's hard to say what kind of brush exactly you need but there is many JS libraries that has already implement brush technology.

    For example did you look at this libraries?

    • Processing.js
    • HTML5-Canvas-Brush-Sketch (demo and article how it works)

    Laso in web you can find many brushes implemented in Mr. Doob Harmony project. For example stringy or Harmony-Brushes project on github.

    0 讨论(0)
  • 2021-01-29 20:50

    Suggest the rendering be done with a chain of bezier curves which surround the curve which is thus filled. (ie end with ctx.fill) Still lots of work to do but hope this helps.

    Adapted a nice demo app for bezier curves

    added it to a fork of your fiddle http://jsfiddle.net/d3zFU/1/

    Code is

    /*
     * Canvas curves example
     *
     * By Craig Buckler,        http://twitter.com/craigbuckler
     * of OptimalWorks.net        http://optimalworks.net/
     * for SitePoint.com        http://sitepoint.com/
     *
     * Refer to:
     * http://blogs.sitepoint.com/html5-canvas-draw-quadratic-curves/
     * http://blogs.sitepoint.com/html5-canvas-draw-bezier-curves/
     *
     * This code can be used without restriction.
     */
    

    (function() {

    var canvas, ctx, code, point, style, drag = null, dPoint;
    
    // define initial points
    function Init(quadratic) {
    
        point = {
            p1: { x:100, y:250 },
            p2: { x:400, y:250 }
        };
    
        if (quadratic) {
            point.cp1 = { x: 250, y: 100 };
        }
        else {
            point.cp1 = { x: 150, y: 100 };
            point.cp2 = { x: 350, y: 100 };
        }
    
        // default styles
        style = {
            curve:    { width: 6, color: "#333" },
            cpline:    { width: 1, color: "#C00" },
            point: { radius: 10, width: 2, color: "#900", fill: "rgba(200,200,200,0.5)", arc1: 0, arc2: 2 * Math.PI }
        }
    
        // line style defaults
        ctx.lineCap = "round";
        ctx.lineJoin = "round";
    
        // event handlers
        canvas.onmousedown = DragStart;
        canvas.onmousemove = Dragging;
        canvas.onmouseup = canvas.onmouseout = DragEnd;
    
        DrawCanvas();
    }
    
    
    // draw canvas
    function DrawCanvas() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
    
        // control lines
        ctx.lineWidth = style.cpline.width;
        ctx.strokeStyle = style.cpline.color;
        ctx.fillStyle = style.cpline.color;
        ctx.beginPath();
        ctx.moveTo(point.p1.x, point.p1.y);
        ctx.lineTo(point.cp1.x, point.cp1.y);
        if (point.cp2) {
            ctx.moveTo(point.p2.x, point.p2.y);
            ctx.lineTo(point.cp2.x, point.cp2.y);
        }
        else {
            ctx.lineTo(point.p2.x, point.p2.y);
        }
        ctx.stroke();
    
        // curve
    ctx.lineWidth = 1 ; //style.curve.width;
        ctx.strokeStyle = style.curve.color;
        ctx.beginPath();
        ctx.moveTo(point.p1.x, point.p1.y);
        if (point.cp2) {
            ctx.bezierCurveTo(point.cp1.x, point.cp1.y, point.cp2.x, point.cp2.y, point.p2.x, point.p2.y);
            ctx.bezierCurveTo(point.cp2.x, point.cp2.y+12, point.cp1.x, point.cp1.y+12, point.p1.x, point.p1.y);
    
        }
        else {
            ctx.quadraticCurveTo(point.cp1.x, point.cp1.y, point.p2.x, point.p2.y);
        }
    //ctx.stroke();
    ctx.fill();
    
        // control points
        for (var p in point) {
            ctx.lineWidth = style.point.width;
            ctx.strokeStyle = style.point.color;
            ctx.fillStyle = style.point.fill;
            ctx.beginPath();
            ctx.arc(point[p].x, point[p].y, style.point.radius, style.point.arc1, style.point.arc2, true);
            ctx.fill();
            ctx.stroke();
        }
    
        ShowCode();
    }
    
    
    // show canvas code
    function ShowCode() {
        if (code) {
            code.firstChild.nodeValue =
                "canvas = document.getElementById(\"canvas\");\n"+
                "ctx = canvas.getContext(\"2d\")\n"+
                "ctx.lineWidth = " + style.curve.width +
                ";\nctx.strokeStyle = \"" + style.curve.color +
                "\";\nctx.beginPath();\n" +
                "ctx.moveTo(" + point.p1.x + ", " + point.p1.y +");\n" +
                (point.cp2 ?
                    "ctx.bezierCurveTo("+point.cp1.x+", "+point.cp1.y+", "+point.cp2.x+", "+point.cp2.y+", "+point.p2.x+", "+point.p2.y+");" :
                    "ctx.quadraticCurveTo("+point.cp1.x+", "+point.cp1.y+", "+point.p2.x+", "+point.p2.y+");"
                ) +
                "\nctx.stroke();"
            ;
        }
    }
    
    
    // start dragging
    function DragStart(e) {
        e = MousePos(e);
        var dx, dy;
        for (var p in point) {
            dx = point[p].x - e.x;
            dy = point[p].y - e.y;
            if ((dx * dx) + (dy * dy) < style.point.radius * style.point.radius) {
                drag = p;
                dPoint = e;
                canvas.style.cursor = "move";
                return;
            }
        }
    }
    
    
    // dragging
    function Dragging(e) {
        if (drag) {
            e = MousePos(e);
            point[drag].x += e.x - dPoint.x;
            point[drag].y += e.y - dPoint.y;
            dPoint = e;
            DrawCanvas();
        }
    }
    
    
    // end dragging
    function DragEnd(e) {
        drag = null;
        canvas.style.cursor = "default";
        DrawCanvas();
    }
    
    
    // event parser
    function MousePos(event) {
        event = (event ? event : window.event);
        return {
            x: event.pageX - canvas.offsetLeft,
            y: event.pageY - canvas.offsetTop
        }
    }
    
    
    // start
    canvas = document.getElementById("canvas");
    code = document.getElementById("code");
    if (canvas.getContext) {
        ctx = canvas.getContext("2d");
        Init(canvas.className == "quadratic");
    }
    

    })();

    0 讨论(0)
  • 2021-01-29 20:57

    I made something like this a while ago and turned it into a jquery plugin. have a look over here, if it's what you're after I'll post a more detailed answer and dig out the simplified jquery version from my archives:

    http://jsfiddle.net/95tft/

    EDIT

    OK, sorry I couldn't do this yesterday:

    Originally the code above was forked from Mr Doob's 'harmony' sketcher over here: http://mrdoob.com/projects/harmony/#ribbon

    (which I think is the best solution). But I kinda broke it down and remade it for my own purposes on another project. I've hacked my own plugin a bit to make it a bit easier still over here:

    http://jsfiddle.net/dh3bj/

    The only thing you might want to change is to change it to work on mousedown/mouseup which should be easy also have a look at the settings at the bottom of the plugin, you should be able to get the effect you want by playing with the brush size, colour, alpha (rgba) etc.

    Hope that helps

    0 讨论(0)
  • 2021-01-29 20:57

    Why don't you use croquis.js?

    It has neat brush implementation like photoshop :)

    And here is Demo which is using croquis.js.

    brush-preview

    0 讨论(0)
  • 2021-01-29 21:01

    Have a look at this code:

    http://jsfiddle.net/aMmVQ/

    What I'm doing is starting a new list of points on mouseDown, then for each mousemove I add a point to the list. Once I get enough points (6 or so) I start drawing quadratic curves, with the control point of the curve being the average of the current point and the next point.

    drawPoints is the bit that works this magic:

    function drawPoints(ctx, points) {
        // draw a basic circle instead
        if (points.length < 6) {
            var b = points[0];
            ctx.beginPath(), ctx.arc(b.x, b.y, ctx.lineWidth / 2, 0, Math.PI * 2, !0), ctx.closePath(), ctx.fill();
            return
        }
        ctx.beginPath(), ctx.moveTo(points[0].x, points[0].y);
        // draw a bunch of quadratics, using the average of two points as the control point
        for (i = 1; i < points.length - 2; i++) {
            var c = (points[i].x + points[i + 1].x) / 2,
                d = (points[i].y + points[i + 1].y) / 2;
            ctx.quadraticCurveTo(points[i].x, points[i].y, c, d)
        }
        ctx.quadraticCurveTo(points[i].x, points[i].y, points[i + 1].x, points[i + 1].y), ctx.stroke()
    }
    
    0 讨论(0)
  • 2021-01-29 21:12

    For those interested in a click version of the code provided by @Alex, I've rewritten his script here:

    http://jsbin.com/aqoqad/3/

    0 讨论(0)
提交回复
热议问题