How to canvas 2d methods the svg exporter emits: a reference
- Step 1Read the path-construction block — Each
<path>opens withctx.beginPath(), then a sequence ofmoveTo/lineTo/bezierCurveTo/quadraticCurveTo/closePath. Match each line back to its SVG command using the table below — the geometry is a direct, point-for-point translation. - Step 2Find the paint calls — After the path, look for
ctx.fillStyle = '<color>'; ctx.fill();and/orctx.strokeStyle = '<color>'; ctx.stroke();. These come from the path'sfill/strokeattributes;nonesuppresses the call. Canvas is stateful, so the style is set immediately before the paint. - Step 3Note the save/restore wrapper — The whole function body is wrapped in
ctx.save()…ctx.restore()so it doesn't permanently change your context's state (transform, styles) after it returns. Keep that wrapper if you copy parts out. - Step 4Spot the arc approximation comments — Any
// arc approximated as linecomment marks a place where an SVG elliptical arc was downgraded toctx.lineTo(). These are the lines to revisit if you need truectx.arc()/ctx.ellipse()geometry — the exporter does not emit those methods. - Step 5Add the methods it didn't emit, if needed — Need a real arc, text, a gradient, a clip region, or a thicker stroke? Add
ctx.arc/ctx.ellipse,ctx.fillText,ctx.createLinearGradient,ctx.clip, orctx.lineWidthyourself — the exporter leaves those to you. Set state before the relevantfill/stroke. - Step 6Trust the browser support — Every method the exporter emits is part of the original Canvas 2D spec and works in all current browsers and back many versions. You don't need feature detection for
moveTo/bezierCurveTo/filletc. — just ensure a 2D context exists.
SVG path command → emitted Canvas method + signature
The complete command-to-method map the exporter uses, with real signatures. Relative commands are resolved to absolutes; smooth-curve control points are reflected automatically before the call.
| SVG command | Emitted method | Signature |
|---|---|---|
M / m | moveTo | ctx.moveTo(x, y) |
L / l, H/h, V/v | lineTo | ctx.lineTo(x, y) (H/V hold the other coordinate) |
C / c, S/s | bezierCurveTo | ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y) |
Q / q, T/t | quadraticCurveTo | ctx.quadraticCurveTo(cpx, cpy, x, y) |
A / a | lineTo (approximation) | ctx.lineTo(x, y) + a flag comment — NOT ctx.arc |
Z / z | closePath | ctx.closePath() |
| (start of each path) | beginPath | ctx.beginPath() |
fill attribute | fillStyle + fill | ctx.fillStyle = '<color>'; ctx.fill(); |
stroke attribute | strokeStyle + stroke | ctx.strokeStyle = '<color>'; ctx.stroke(); |
| (function wrapper) | save / restore | ctx.save() … ctx.restore() |
Methods the exporter emits vs. methods it doesn't
Know the boundary so you don't go looking for output that isn't there. Everything in the 'Emitted' column has universal browser support.
| Emitted (universal support) | NOT emitted — add yourself if needed |
|---|---|
beginPath, moveTo, lineTo | arc, arcTo, ellipse (arcs are downgraded to lineTo) |
bezierCurveTo, quadraticCurveTo | rect, roundRect (primitives aren't translated) |
closePath, fill, stroke | fillText, strokeText (<text> is ignored) |
fillStyle, strokeStyle | createLinearGradient, createRadialGradient, addColorStop |
save, restore | clip (clip-paths aren't translated) |
| — | lineWidth, lineCap, lineJoin, setLineDash (stroke width/style not read) |
| — | globalAlpha, shadow* (opacity / shadow not read) |
| — | translate, rotate, scale (you apply transforms at the call site) |
Cookbook
Reference snippets: how a path becomes Canvas calls, and what the stateful model means when you read the output.
A path and its emitted Canvas equivalent, line for line
Each path command maps to exactly one method call. The fill is set immediately before the paint because Canvas is stateful.
SVG path: d="M10 10 H90 V90 L10 90 Z" fill="#334155" Emitted: ctx.beginPath(); ctx.moveTo(10, 10); // M ctx.lineTo(90, 10); // H90 → y held at 10 ctx.lineTo(90, 90); // V90 → x held at 90 ctx.lineTo(10, 90); // L ctx.closePath(); // Z ctx.fillStyle = '#334155'; ctx.fill();
The stateful model: style before paint
Unlike SVG where fill is an attribute on the element, Canvas paints with whatever fillStyle is current. The exporter therefore sets the style on the line just before fill().
// WRONG mental model (SVG-style): fill is 'attached' to the shape // RIGHT (Canvas): fill() uses the CURRENT fillStyle ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(40,0); ctx.lineTo(20,40); ctx.closePath(); ctx.fillStyle = '#ef4444'; // set state… ctx.fill(); // …then paint with it // If you reorder these, the triangle fills with the previous colour.
save/restore keeps the function self-contained
The wrapper means calling the function never leaves your context in a changed state — important when you call several draw functions in a row.
export function drawLogo(ctx) {
ctx.save(); // snapshot transform + styles
// … beginPath / commands / fillStyle / fill …
ctx.restore(); // roll back to the caller's state
}
// So after drawLogo(ctx), your ctx.fillStyle is unchanged.Adding an arc the exporter approximated
Where you see the arc comment, swap the straight line for a real arc. The exporter never emits ctx.arc, so this is a manual fix.
// Exported (approximation): // arc approximated as line — review and adjust if precise arc geometry is required ctx.lineTo(90, 50); // Hand-fixed for a semicircle from (10,50) to (90,50), r=40: ctx.arc(50, 50, 40, Math.PI, 0, false); // centre (50,50) // (compute centre/angles from the SVG arc's endpoints + radii)
Adding a gradient (not emitted)
The exporter only carries solid colours. To reproduce an SVG gradient, build a Canvas gradient and assign it to fillStyle before the fill.
const g = ctx.createLinearGradient(0, 0, 0, 100); g.addColorStop(0, '#6366f1'); g.addColorStop(1, '#a5b4fc'); ctx.beginPath(); /* … the exported path commands … */ ctx.fillStyle = g; // replace the exported solid fillStyle ctx.fill();
Edge cases and what actually happens
Looking for ctx.arc in the output
Not emittedThe exporter never writes ctx.arc, ctx.arcTo, or ctx.ellipse. SVG A arcs are downgraded to ctx.lineTo() with a flag comment. If your reference expectation was an arc method, that's why it's absent — add it by hand from the arc's geometry.
Expecting createLinearGradient / addColorStop
Not emittedGradient methods are not part of the exporter's output. A gradient fill in the SVG produces no createLinearGradient/addColorStop — at best an unusable fillStyle = 'url(#…)'. Build the gradient yourself and assign it to fillStyle before the path's fill().
Canvas rendering looks slightly different from the SVG
ExpectedSVG and Canvas differ subtly in anti-aliasing and sub-pixel rasterisation. Identical coordinates can produce marginally different edges, most visible on very thin strokes or at small sizes. This is a renderer difference, not a translation bug.
Stroke renders at 1px regardless of the SVG
Width not readOnly strokeStyle (colour) is emitted; lineWidth is not. Canvas defaults to 1px butt-cap miter-join strokes, so a heavy SVG outline becomes a hairline. Set ctx.lineWidth/lineCap/lineJoin before the stroke call to restore the intended weight.
Fill colour from CSS/style doesn't appear
Attribute-onlyThe exporter reads the literal fill/stroke attributes on each path. Colours from a stylesheet, an inline style=, or an inherited <g fill> are not picked up, so no fillStyle is emitted for them. Move the colour onto the path attribute or set fillStyle yourself.
Opacity / fill-opacity ignored
Not readNeither opacity, fill-opacity, nor stroke-opacity is translated — there's no ctx.globalAlpha in the output. A semi-transparent SVG shape renders fully opaque. Set ctx.globalAlpha (or use an rgba colour) before the paint to reproduce transparency.
Clip-path or mask in the SVG
Not emittedctx.clip() is not generated. Clip-paths and masks have no representation in the output. To clip, build the clip region's path yourself, call ctx.clip(), then draw — wrapped in save/restore so the clip doesn't persist.
Worrying about browser support of the emitted methods
UniversalEvery method the exporter emits (beginPath, moveTo, lineTo, bezierCurveTo, quadraticCurveTo, closePath, fill, stroke, fillStyle, strokeStyle, save, restore) is part of the original Canvas 2D specification and has been supported across all major browsers for well over a decade. No polyfill or feature detection is required.
Frequently asked questions
Which Canvas methods does the SVG exporter actually emit?
A small set: beginPath, moveTo, lineTo, bezierCurveTo, quadraticCurveTo, closePath for geometry; fillStyle/fill and strokeStyle/stroke for painting; and save/restore to wrap the function. That's the whole surface — it does not emit arc, fillText, gradient methods, clip, or lineWidth.
Is the Canvas 2D API supported in all browsers?
Yes. Every method the exporter uses is part of the original Canvas 2D spec and has universal support across Chrome, Firefox, Safari, and Edge going back many versions. You don't need feature detection — just confirm a getContext('2d') is available.
How does the SVG arc command (A) map to Canvas?
It doesn't map to ctx.arc(). The exporter approximates each elliptical arc as a straight ctx.lineTo() to its endpoint and adds a // arc approximated as line comment. The radii, rotation, and large-arc/sweep flags are discarded. For accurate arcs, replace those lines with ctx.arc/ctx.ellipse or convert arcs to Béziers before exporting.
Why is fillStyle set right before fill() instead of once?
Canvas is stateful — fill() paints with whatever fillStyle is current. The exporter sets the colour immediately before each fill()/stroke() so each path paints with its own attribute colour regardless of what was set earlier. Reordering those lines would change the result.
Why does my Canvas output look a little different from the SVG?
SVG and Canvas rasterise slightly differently — anti-aliasing and sub-pixel positioning aren't pixel-identical. The difference is usually imperceptible but can show on very thin strokes or tiny shapes. It's a rendering-engine difference, not a bug in the translation.
Does the exporter emit ctx.fillText for SVG text?
No. <text> elements are ignored entirely — there's no fillText/strokeText in the output. Add ctx.fillText calls yourself, or outline the text to paths first (for example with svg-font-to-path) and export those paths.
How are smooth curves (S and T) handled?
S becomes bezierCurveTo and T becomes quadraticCurveTo, with the omitted control point reflected from the previous curve's control point automatically. You get a correct smooth curve without computing the reflection yourself — it's done before the call is written.
Why is there no lineWidth in the output?
The exporter reads only the stroke colour attribute, not stroke-width (or cap/join/dash). Canvas defaults to a 1px stroke, so a thick SVG outline renders thin. Set ctx.lineWidth (and lineCap/lineJoin) before the generated stroke call to match the original weight.
Can I add a clip region to the exported shape?
Yes, manually. The exporter doesn't emit ctx.clip(). Build the clip path (beginPath + commands), call ctx.clip(), then draw, all inside save/restore so the clip is removed afterward. SVG clip-paths/masks aren't translated for you.
Do I need to set the canvas size or DPR for the output to look right?
For crisp rendering on high-DPI screens, yes — Canvas is a bitmap. Size the backing store to width*devicePixelRatio, ctx.scale(dpr, dpr) once, and redraw on resize. The exporter draws at the SVG's coordinates; you control the canvas resolution and any positioning transform.
What's the difference between this reference and just reading the output?
The output shows what one file produced; this reference tells you the full, fixed set of methods the exporter can and can't emit, their signatures, and the stateful semantics — so you can predict, debug, and extend any output. The key takeaway is the boundary: paths + solid fill/stroke + save/restore, nothing else.
Where do transforms (translate/rotate/scale) come from?
Not from the exporter — it never emits ctx.translate/rotate/scale, and any transform on the SVG isn't baked in. You apply transforms at the call site around draw<Name>(ctx). That keeps each function reusable at any position/scale you choose.
Privacy first
Every JAD SVG tool runs entirely in your browser using the DOM API and Canvas. Your SVG files never leave your device — verified by zero outbound network requests during processing.