A Renderer that draws on a canvas

A library that draws pixels, such as Chart.js, has no SVG to give. Its Renderer has toImage instead of toSVG and returns a PNG at input.size; export, Word and the attribution work as for any other chart.
Pro ExtensionAlphaPilot program
New tab

The Renderer

import type { RasterChartRenderer } from '@tiptap-pro/extension-diagrams'
import { Chart, registerables } from 'chart.js'

Chart.register(...registerables)

export const chartJsRenderer: RasterChartRenderer = {
  id: 'chartjs',
  label: 'Chart.js',
  types: ['bar', 'line', 'pie', 'doughnut'],
  mount(target, input) {
    const canvas = document.createElement('canvas')
    target.replaceChildren(canvas)
    const chart = new Chart(canvas, toChartJsConfig(input))
    return {
      update: (next) => {
        const config = toChartJsConfig(next)
        chart.data = config.data
        chart.options = config.options
        chart.update('none')
      },
      destroy: () => chart.destroy(),
    }
  },
  toImage(input) {
    const canvas = document.createElement('canvas')
    canvas.width = input.size.width
    canvas.height = input.size.height
    const chart = new Chart(canvas, { ...toChartJsConfig(input), options: { animation: false } })
    return new Promise((resolve, reject) =>
      canvas.toBlob((blob) => {
        chart.destroy()
        blob ? resolve(blob) : reject(new Error('No picture.'))
      }, 'image/png'),
    )
  },
}

toChartJsConfig turns the Chart Data and Spec into a Chart.js configuration, in the colors of input.theme. The demo has a complete one.

  • PNG, WebP, JPEG and Word use the picture.
  • An SVG file holds the picture, not shapes, and export returns raster: true.
  • The frame and the attribution are added as for any Renderer.
  • Draw without animation in toImage, and pass responsive: false with a fixed devicePixelRatio, so the picture has exactly the size it was asked for.
  • A server has no canvas, so toImage runs only in a browser, or with a canvas library of your own.