SVG Editor

Vector graphics editor with raster-to-SVG auto-tracing, element manipulation, zoom control, and export to SVG or high-resolution PNG.

Live Demo

<iframe id="se-demo" src="/online/webapp/svg-editor" width="100%" height="500" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('se-demo', 'seSocket');</script>

Embed

<iframe src="https://sgapps.io/online/webapp/svg-editor"
    width="100%" height="600" frameborder="0"></iframe>

Open with an SVG File

<iframe src="https://sgapps.io/online/webapp/svg-editor/url/aHR0cHM6Ly9leGFtcGxlLmNvbS9pY29uLnN2Zw=="
    width="100%" height="600" frameborder="0"></iframe>

Events Reference


loadSvgImage -- Load SVG Source

Loads an SVG document from a string into the editor. Use this to programmatically set the SVG content.

Arg Type Description
svgString string Raw SVG markup
callback function (err)

socket.fire("webapp::instance::request", "loadSvgImage",
    '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
    '<circle cx="100" cy="100" r="80" fill="coral" />' +
    '<text x="100" y="110" text-anchor="middle" fill="white" font-size="24">Hello</text>' +
    '</svg>',
    function (err) { console.log("SVG loaded"); }
);

<button onclick="window._ws('seSocket')&&window.seSocket.fire('webapp::instance::request','loadSvgImage','<svg xmlns='http://www.w3.org/2000/svg' width='300' height='200'><rect width='300' height='200' fill='#4a6cf7' rx='10'/><circle cx='150' cy='100' r='60' fill='#fff3'/><text x='150' y='108' text-anchor='middle' fill='white' font-size='20'>SGApps</text></svg>')">Try: Load Sample SVG</button>


loadRasterImage -- Import Raster Image

Imports a raster image (PNG, JPEG, etc.) and auto-traces it to SVG vectors using the ImageTracer algorithm. The result replaces the current editor content.

Arg Type Description
imageBase64 string Base64 image data
callback function (err)
options object (optional) &#x7B; numberofcolors, mincolorratio, linefilter &#x7D;

socket.fire("webapp::instance::request", "loadRasterImage",
    "data:image/png;base64,iVBORw0KGgo...",
    function (err) { console.log("Traced"); },
    { numberofcolors: 16, mincolorratio: 3, linefilter: true }
);

getSVGSource -- Get SVG Source

Returns the current SVG source as a string. This is the most common way to extract the edited content.

socket.fire("webapp::instance::request", "getSVGSource", function (err, svgString) {
    console.log("SVG source:", svgString.length, "bytes");
});

<button onclick="window._ws('seSocket')&&window.seSocket.fire('webapp::instance::request','getSVGSource',function(e,s){if(s)alert('SVG length: '+s.length+' bytes\n\n'+s.substring(0,300)+'...')})">Try: Get SVG Source</button>

getSVGDynamicSource, getSVGAbsoluteSource -- Alternative Export

socket.fire("webapp::instance::request", "getSVGAbsoluteSource", function (err, svg) {
    // SVG with absolute path coordinates
});

generateRasterImage -- Export as PNG

Renders the current SVG to a high-resolution PNG (scaled to 3500px) and returns it as a base64 data URL.

socket.fire("webapp::instance::request", "generateRasterImage", function (err, pngDataUrl) {
    var img = document.createElement('img');
    img.src = pngDataUrl;
    document.body.appendChild(img);
});

<button onclick="window._ws('seSocket')&&window.seSocket.fire('webapp::instance::request','generateRasterImage',function(e,d){if(d){var i=document.createElement('img');i.src=d;i.style.maxHeight='120px';document.getElementById('se-png-result').innerHTML='';document.getElementById('se-png-result').appendChild(i);}})">Try: Export PNG</button><div id="se-png-result" style="margin:8px 0; min-height:20px;"></div>


editor:currentElement:getAttribute -- Get Element Attributes

Reads attributes from the currently selected SVG element.

Arg Type Description
attrs Array Attribute names to read (e.g., [&#x22;fill&#x22;, &#x22;stroke&#x22;, &#x22;stroke-width&#x22;])
callback function (err, values: object)

socket.fire("webapp::instance::request", "editor:currentElement:getAttribute",
    ["fill", "stroke", "opacity"],
    function (err, attrs) { console.log(attrs); }
);

editor:currentElement:setAttribute -- Set Element Attributes

Sets attributes on the selected element. Pass null as a value to remove an attribute.

Arg Type Description
attrs object &#x7B; attributeName: value &#x7D;
callback function (err)

socket.fire("webapp::instance::request", "editor:currentElement:setAttribute",
    { fill: "#ff6600", "stroke-width": "3", stroke: "#333" }
);

editor:currentElement:set-zoom, editor:currentElement:get-zoom -- Zoom

// Set zoom to 150%
socket.fire("webapp::instance::request", "editor:currentElement:set-zoom", 1.5);

// Get current zoom
socket.fire("webapp::instance::request", "editor:currentElement:get-zoom",
    function (err, zoom) { console.log("Zoom:", zoom); }
);

Complete Example

<!DOCTYPE html>
<html>
<head><title>SVG Editor Widget</title></head>
<body>
    <div style="display:flex;gap:8px;padding:10px;flex-wrap:wrap;">
        <button id="load-svg">Load Circle</button>
        <button id="get-svg">Get SVG</button>
        <button id="export-png">Export PNG</button>
    </div>

    <iframe id="editor" src="https://sgapps.io/online/webapp/svg-editor"
        width="100%" height="500" frameborder="0"></iframe>
    <pre id="svg-output" style="background:#f6f8fa;padding:8px;max-height:200px;overflow:auto;"></pre>

    <script src="https://sgapps.io/components/window-socket/index.js"></script>
    <script>
        var socket = new WindowSocket(document.getElementById('editor').contentWindow);
        socket.start();

        socket.on("webapp::connection::ping", function () {
            socket.fire("webapp::instance::embed-mode", true);
        });

        document.getElementById('load-svg').onclick = function () {
            socket.fire("webapp::instance::request", "loadSvgImage",
                '<svg xmlns="http://www.w3.org/2000/svg" width="300" height="300">' +
                '<circle cx="150" cy="150" r="120" fill="#4a6cf7" />' +
                '<circle cx="150" cy="150" r="80" fill="#fff" opacity="0.3" />' +
                '</svg>');
        };

        document.getElementById('get-svg').onclick = function () {
            socket.fire("webapp::instance::request", "getSVGSource",
                function (err, svg) {
                    document.getElementById('svg-output').textContent = svg;
                });
        };

        document.getElementById('export-png').onclick = function () {
            socket.fire("webapp::instance::request", "generateRasterImage",
                function (err, data) {
                    var a = document.createElement('a');
                    a.href = data;
                    a.download = 'export.png';
                    a.click();
                });
        };
    </script>
</body>
</html>