PerfectVector
Di Irene Kim9 min di lettura

Canvas Path2D SVG: riusa i tracciati alla giusta scala

Riusa dati di tracciato SVG su canvas con trasformazione viewBox, colori, fori e densità corretti. Segui un esempio originale e conserva l'SVG modificabile.

In questa pagina

Passa l'attributo d di un tracciato a new Path2D(d), poi disegnalo con un contesto canvas. Per riprodurre l'SVG, trasferisci anche la corrispondenza delle coordinate, i colori e la regola di riempimento. Il costruttore accetta dati di tracciato; non importa un documento SVG e non applica il suo viewBox, CSS o trasformazioni di gruppo (costruttore Path2D su MDN).

Questo conta quando un'icona personalizzata appare corretta come SVG ma diventa piccola, spostata, nera o piena nella sua apertura su canvas. L'esempio seguente corregge queste differenze con due tracciati e una trasformazione esplicita di adattamento. Inizia dalla geometria vettoriale esistente quando la possiedi. La vettorializzazione è utile soltanto quando la grafica da riusare esiste ancora come pixel.

Cosa contiene un oggetto Path2D

Pensa ai dati del tracciato come alla descrizione del contorno. Le altre istruzioni SVG sono esterne a quella stringa, e il codice di disegno canvas deve fornire quelle necessarie.

Input SVGResponsabilità del canvas
Valore d di un tracciatoCostruire la geometria Path2D
viewBox e dimensioni visualizzateCalcolare la trasformazione di disegno
fill e fill-ruleImpostare fillStyle e passare la regola a fill()
transform del genitore o del tracciatoApplicare separatamente la trasformazione equivalente
CSS, gradienti, maschere, testo e immaginiImplementare il rendering richiesto oppure scegliere un altro metodo

L'esempio usa riempimenti espliciti, due tracciati figli diretti e nessun'altra funzionalità SVG. È deliberatamente abbastanza piccolo da poterlo ispezionare. Copiare il ciclo di estrazione in un importatore SVG arbitrario perderebbe stili ereditati ed elementi non supportati.

Confronta il sorgente con un canvas non configurato

Questo emblema originale ha un corpo arrotondato verde petrolio, una punta arancione e un'apertura quadrata. Il suo viewBox inizia in (20, 10), non in (0, 0). Il sottotracciato interno percorre la stessa direzione del contorno esterno, quindi la regola dichiarata evenodd conta.

Inserisci questo SVG e un canvas in una pagina HTML:

<svg id="source" xmlns="http://www.w3.org/2000/svg"
     viewBox="20 10 120 80" width="240" height="160">
  <path fill="#126d70" fill-rule="evenodd"
        d="M40 20 H90 Q110 20 110 40 V60 Q110 80 90 80 H40 Q30 80 30 70 V30 Q30 20 40 20 Z M50 35 H80 V60 H50 Z"/>
  <path fill="#f19b38" d="M115 25 L135 50 L115 75 Z"/>
</svg>
<canvas id="result"></canvas>

Se percorri i due valori d e chiami ctx.fill(new Path2D(d)) senza impostare altro, la geometria usa le coordinate canvas e il colore e la regola di riempimento predefiniti. Non acquisisce automaticamente l'aspetto dell'SVG. Il metodo canvas fill() accetta sia un tracciato sia una regola esplicita evenodd o nonzero; nonzero è il valore predefinito (fill() su MDN).

Confronto nel browser fra un emblema SVG, un rendering Path2D grezzo piccolo e nero con l'apertura riempita e un rendering canvas bicolore adattato correttamente
Gli stessi tracciati scritti a mano in un browser: riferimento SVG, Path2D grezzo e adattamento esplicito con colori ed evenodd ripristinati. La tabella riporta le dimensioni della bitmap per quattro combinazioni di dimensioni e DPR.

Metodo: abbiamo renderizzato questo SVG scritto a mano nel browser, disegnato i due tracciati con entrambi i metodi canvas e rieseguito il codice pubblicato in una pagina HTML separata. Lo screenshot è output reale del browser. Dimostra la gestione di coordinate e colori, non una conversione PerfectVector.

Associa il viewBox al canvas

Il comportamento predefinito di SVG che conserva le proporzioni adatta il viewBox all'interno della sua area di visualizzazione e lo centra. La specifica del sistema di coordinate SVG definisce questa corrispondenza. Per questo esempio senza annidamenti, riproduci xMidYMid meet con una sola scala uniforme e una traslazione:

scale = min(cssWidth / viewBoxWidth, cssHeight / viewBoxHeight)
tx = (cssWidth - viewBoxWidth * scale) / 2 - viewBoxX * scale
ty = (cssHeight - viewBoxHeight * scale) / 2 - viewBoxY * scale

Gli ultimi termini eliminano l'origine diversa da zero. A 240 × 160, la scala è 2, tx è -40 e ty è -20. A 300 × 120, la scala diventa 1.5; il viewBox adattato largo 180 pixel ha 60 pixel di spazio orizzontale per lato. La traslazione è quindi (30, -15) dopo aver considerato l'origine sorgente.

Usa lo script seguente dopo l'HTML sopra. Gestisce gli attributi diretti dei tracciati di questo esempio, ridisegna l'intero canvas e distingue dimensioni CSS e dimensioni della bitmap sottostante:

const source = document.querySelector("#source");
const vb = source.viewBox.baseVal;
const layers = [...source.querySelectorAll("path")].map(el => ({
  path: new Path2D(el.getAttribute("d")),
  fill: el.getAttribute("fill"),
  rule: el.getAttribute("fill-rule") || "nonzero"
}));
 
function draw(canvas, cssWidth, cssHeight, dpr = window.devicePixelRatio || 1) {
  canvas.style.width = `${cssWidth}px`;
  canvas.style.height = `${cssHeight}px`;
  canvas.width = Math.round(cssWidth * dpr);
  canvas.height = Math.round(cssHeight * dpr);
  const ctx = canvas.getContext("2d");
  const scale = Math.min(cssWidth / vb.width, cssHeight / vb.height);
  const tx = (cssWidth - vb.width * scale) / 2 - vb.x * scale;
  const ty = (cssHeight - vb.height * scale) / 2 - vb.y * scale;
  const px = canvas.width / cssWidth;
  const py = canvas.height / cssHeight;
  ctx.setTransform(px * scale, 0, 0, py * scale, px * tx, py * ty);
  for (const layer of layers) {
    ctx.fillStyle = layer.fill;
    ctx.fill(layer.path, layer.rule);
  }
}
 
draw(document.querySelector("#result"), 240, 160);
 

Impostare canvas.width e canvas.height cancella e reimposta il contesto. La funzione imposta poi la trasformazione completa e disegna di nuovo ogni livello, così le chiamate ripetute non accumulano la scala. Presuppone un viewBox valido con larghezza e altezza positive e dimensioni richieste positive.

px e py usano le dimensioni effettive arrotondate della bitmap. Questo mantiene le coordinate CSS associate ai pixel allocati anche quando la densità richiesta produce dimensioni frazionarie. L'esempio MDN su devicePixelRatio spiega perché le dimensioni di visualizzazione del canvas e quelle in pixel richiedono trattamenti separati.

Controlla separatamente dimensioni e densità dei pixel

Abbiamo passato esplicitamente valori DPR 1 e 2 alla stessa funzione a due dimensioni CSS. Sono input di densità controllati, non un'affermazione di aver verificato due dispositivi fisici. Il rapporto pixel del dispositivo riportato dal browser per la chiamata predefinita era 2.

Dimensioni CSSArgomento DPRBitmap canvas osservata
240 × 1601240 × 160
240 × 1602480 × 320
300 × 1201300 × 120
300 × 1202600 × 240

Il centro dell'apertura è rimasto trasparente in tutti e quattro i casi. Una densità maggiore cambia la risoluzione della bitmap; non corregge una trasformazione sbagliata né recupera una regola di riempimento mancante. Ridisegna quando cambiano le dimensioni CSS previste o il rapporto pixel del dispositivo. Un ingrandimento soltanto CSS allunga la bitmap già presente sul canvas.

Se il sorgente è già sbagliato prima di raggiungere il canvas, usa i controlli delle dimensioni e del viewBox SVG. Se è sbagliato soltanto il canvas, confronta prima la sua trasformazione e gestione dei colori con il riferimento SVG funzionante.

Conserva il sorgente e scegli il metodo di importazione adatto

Mantieni l'originale SVG e i suoi attributi insieme ai dati di tracciato derivati. Una funzione di disegno Path2D è utile quando controlli un piccolo insieme di contorni e i loro stili. Per un SVG complesso di cui serve soltanto l'aspetto renderizzato dal browser, caricarlo come immagine e disegnare quell'immagine può evitare di ricostruire ogni funzionalità. Anche quel metodo disegna nella bitmap del canvas.

Salvare l'output canvas come PNG crea un'immagine raster, anche se il disegno è iniziato con tracciati vettoriali. L'API di esportazione canvas produce un blob immagine; il supporto PNG è obbligatorio (toBlob() su MDN). Conserva l'SVG per successive modifiche dei tracciati. Analogamente, un file SVG può contenere un'immagine raster anziché dati di tracciato utili; la diagnosi delle immagini incorporate aiuta a distinguere quei casi.

PerfectVector è adatto quando rimane soltanto un PNG o JPG dell'icona personalizzata e servono contorni riutilizzabili. Converti quell'immagine in SVG, poi ispeziona sagoma, colori separati e piccole aperture prima di estrarre i tracciati per canvas. Un originale SVG pulito dovrebbe passare direttamente alla preparazione. Il ricalco non implementa la mappatura del viewBox, non copia il CSS e non rende un PNG canvas modificabile come vettori.

Per un'intera famiglia di icone, definisci la griglia condivisa e le regole dei colori del kit UI prima di collegare ogni funzione di disegno. Altri esempi di preparazione SVG sono nel blog.

Prima di usare il disegno nell'interfaccia

  • Controlla il riferimento SVG alle stesse dimensioni di visualizzazione del canvas.
  • Conferma l'origine del viewBox oltre a larghezza e altezza.
  • Trasferisci colori e regola di riempimento prevista; ispeziona ogni apertura.
  • Tieni conto delle trasformazioni dei gruppi invece di copiare soltanto d.
  • Leggi i valori effettivi canvas.width e canvas.height, poi prova le dimensioni massime previste di visualizzazione.
  • Conserva l'originale SVG e fornisci un nome accessibile o testo circostante appropriato all'interfaccia.

FAQ

Path2D può importare un intero file SVG? No. Il suo input stringa è costituito da dati di tracciato SVG, come il valore dell'attributo d di un tracciato. Struttura del documento, mappatura del viewBox, stili e trasformazioni di gruppo richiedono una gestione separata.

Perché il foro del mio SVG si è riempito su canvas? Controlla la regola di riempimento e le direzioni dei sottotracciati. Questo esempio richiede evenodd, mentre il riempimento canvas usa nonzero come valore predefinito. Passa la regola prevista quando riempi l'oggetto Path2D.

Disegnare tracciati SVG su canvas conserva un'esportazione vettoriale? I tracciati rimangono istruzioni di disegno riutilizzabili nel programma, ma esportare il canvas come PNG produce pixel. Conserva l'SVG originale per la modifica e la consegna vettoriale.

Fonti

  1. MDN — Costruttore Path2D — Definisce la stringa di dati di tracciato accettata dal costruttore.
  2. W3C — Sistemi di coordinate SVG — Definisce origine del viewBox, mappatura dell'area di visualizzazione e allineamento che conserva le proporzioni.
  3. MDN — fill() del canvas — Documenta il riempimento dei tracciati e le regole evenodd e nonzero.
  4. MDN — devicePixelRatio — Spiega dimensioni CSS di visualizzazione e risoluzione della bitmap canvas.
  5. MDN — toBlob() del canvas — Documenta l'esportazione di immagini raster da un canvas.

Hai soltanto un'icona raster? Prepara il suo SVG con PerfectVector, controlla contorno e aperture, poi confronta il disegno canvas con quell'SVG alle dimensioni effettive dell'interfaccia.

Altro dal blog

Riparti da un SVG più pulito
e facile da modificare