Ravendyne Inc

SVGRX on

SVGRX: convert SVG to a bunch of line segments

The library is used to convert SVG vector drawing to an array of line segments with absolute coordinates. Drawing these line segments, i.e. onto HTML canvas, should give you fairly accurate representation of the original SVG document, but without any styling, animations etc.

Here is an example of using the library to parse SVG document and then render line segments, created by the library, onto HTML canvas:

Drawing

Library does not support animations or any other fancy SVG stuff.

Its sole purpose is to extract vector drawing information from a SVG document and present that in a form that is easy to process afterwards.

The main idea behind this library is to create vector drawings in tools like Inkscape, and then extract the paths in a form that can be easily converted into i.e. CNC machine gcode. In the process, all the more or less important information is preserved, i.e. all of the element attributes are preserved

Nevertheless, the library, and internal classes and functions, i.e. Point, Matrix, Bezier etc., could be useful for different projects.

Concept

SVG parsing is done by DOMParser and then the resulting DOM tree is traversed and only nodes and information relevant to the final conversion to an array of line segments are collected.

Phases of the entire process are:

  • parsing SVG and converting it to a tree of SVGRX objects
    • all attributes of SVG nodes are collected
    • for each of SVG tags: svg, g, rect, circle, ellipse, line, polyline, polygon and path an object of corresponding class is created
  • transform matrix for each, if any, is parsed and stored
  • each class parses its attributes and exposes them as properties
  • every node converts itself into an array of Bezier curves of 2-nd (a line), 3-rd (quadratic) and 4-th (cubic) order
  • conversion arrays of Bezier curves are then flattened into an array of line segments using various algorithms
  • you then use the resulting array of line segments to do whatever work you intended with them

The main thing to do, once a svg file (or string) is loaded and parsed, is to call flatten method:

    svg.flatten( new SVGRX.Matrix() )

The method accepts a transformation matrix as parameter. You can leave it out unless you want to translate, rotate, scale, or do something similar with the entire vector drawing before it is converted into a bunch of lines.

Example that loads svg file from server and draws it onto a canvas:

    //
    // SVGRX CODE
    //
    SVGRX.ConvertFromUrl( 'test.svg' )
    // loadedSvg is SVGRX.Svg object
    .then(function( loadedSvg ){
        // current transformation matrix
        // by default it's unit matrix
        let ctm = new SVGRX.Matrix()
        ctm = ctm.translate( guiData.offsetX, guiData.offsetY ).rotate( guiData.rotationAngle )

        // segments -> array of arrays, each of the arrays has SVGRX.Point as elements
        let segments = loadedSvg.flatten( ctm )
        drawSvgOnCanvas( segments )
    })

    //
    // CODE TO DRAW STUFF ON HTML CANVAS
    //
    var drawSvgOnCanvas = function( segments )
    {
        var canvasWidth = 1200
        var canvasHeight = 500
        var canvas = document.getElementById(canvasName)
        canvas.width = canvasWidth
        canvas.height = canvasHeight
        canvas.style.width = canvasWidth
        canvas.style.height = canvasHeight
        var ctx = canvas.getContext('2d')s

        for( let idx = 0; idx < segments.length; idx++ )
        {
            // draw lines
            ctx.lineWidth = 2
            ctx.strokeStyle = '#74b71b'
            ctx.beginPath()

            ctx.moveTo( segments[0].x, segments[0].y )
            for( let idx = 1; idx < segments.length; idx++)
            {
                ctx.lineTo( segments[idx].x, segments[idx].y )
            }

            ctx.stroke()

            // draw line ends as points
            SVGRXTools.drawPoints( ctxA, segments[ idx ], '#30363b' )
            ctx.fillStyle = '#30363b'
            var size = 2
            for( let idx = 0; idx < points.length; idx++)
            {
                ctx.fillRect( points[idx].x - size, points[idx].y - size, size * 2, size * 2 )
            }
        }
    }

You can do the same with SVG as a literal string:

    // javascript template literal, use with pre-processors, i.e. babel
    let svgAsString = `
    <svg>
        <g>
            <path d="M 100,100 L 100,50 50,50 Z" />
        </g>
    </svg>
    `
    // loadedSvg is SVGRX.Svg object
    let loadedSvg = SVGRX.ConvertFromString( svgAsString)

    // current transformation matrix
    // by default it's unit matrix
    let ctm = new SVGRX.Matrix()
    ctm = ctm.translate( guiData.offsetX, guiData.offsetY ).rotate( guiData.rotationAngle )

    // segments -> array of arrays, each of the arrays has SVGRX.Point as elements
    let segments = loadedSvg.flatten( ctm )
    drawSvgOnCanvas( segments )

For more details, checkout the Git repo.