Rocket ECharts Pro

Rocket is currently in alpha – available with Datastar Pro.

An ECharts integration, loaded via CDN using Rocket’s declarative import.

Demo

Explanation #

ECharts is a powerful, enterprise-grade charting library with hundreds of chart types, animations, and complex interaction patterns. Despite its complexity, Rocket allows you to create a fully-featured ECharts component in around 100 lines of code. This showcases Rocket’s ability to seamlessly integrate sophisticated JavaScript libraries while maintaining clean, declarative markup.

Component Structure #

The ECharts component accepts the following props:

Simplicity Through Rocket #

What would typically require complex initialization code, manual DOM manipulation, and event handling is reduced to:

The key features of this Rocket ECharts integration include:

Usage Example #

 1<rocket-echarts option='{
 2    "title": { "text": "Sales Data" },
 3    "tooltip": { "trigger": "axis" },
 4    "xAxis": { 
 5        "type": "category", 
 6        "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] 
 7    },
 8    "yAxis": { "type": "value" },
 9    "series": [{
10        "data": [120, 200, 150, 80, 70, 110, 130],
11        "type": "bar"
12    }]
13}'></rocket-echarts>

Rocket Component #

  1<template data-rocket:rocket-echarts
  2          data-props:option="js|={}"
  3          data-props:theme="string|=default"
  4          data-props:resize-delay="int|=100"
  5          data-import-esm:echarts="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.esm.js"
  6>
  7  <script>
  8    // Store non-serializable objects
  9    let chart = null
 10    let currentTheme = $$theme
 11
 12    // Helper to resolve CSS variables in options
 13    function resolveVars(val) {
 14      if (Array.isArray(val)) return val.map(resolveVars)
 15      if (val && typeof val === 'object') {
 16        const resolved = {}
 17        for (const key in val) {
 18          if (Object.hasOwn(val, key)) resolved[key] = resolveVars(val[key])
 19        }
 20        return resolved
 21      }
 22      if (typeof val === 'string' && val.includes('var(')) {
 23        return val.replace(/var\((--[\w-]+)\)/g, (_, name) =>
 24          getComputedStyle(el).getPropertyValue(name).trim() || `var(${name})`)
 25      }
 26      return val
 27    }
 28
 29    // Initialize chart - DOM and imports are ready when setup runs
 30    const chartEl = $$chartNode
 31    if (!chartEl) {
 32      console.error('[ECharts] Chart element not found')
 33      return
 34    }
 35
 36    // Ensure container has dimensions
 37    const hostHeight = el.clientHeight
 38    if (hostHeight > 0 && chartEl.clientHeight === 0) {
 39      chartEl.style.height = hostHeight + 'px'
 40    }
 41
 42    // Check if ECharts is available
 43    if (typeof echarts === 'undefined') {
 44      console.error('[ECharts] ECharts library not available')
 45      return
 46    }
 47
 48    // Create chart instance
 49    chart = echarts.init(chartEl, currentTheme === 'default' ? null : currentTheme)
 50
 51    // Helper to get plain value from signal (handles Proxy objects)
 52    function getPlainOption() {
 53      // Deep clone to resolve all proxy values and CSS variables
 54      return resolveVars(JSON.parse(JSON.stringify($$option || {})))
 55    }
 56
 57    // Set and update chart option
 58    function updateOption() {
 59      const option = getPlainOption()
 60      if (Object.keys(option).length) {
 61        chart.setOption(option)
 62      }
 63    }
 64
 65    // Set initial option
 66    updateOption()
 67
 68    // Update chart when option changes
 69    effect(updateOption)
 70
 71    // Handle theme changes
 72    effect(() => {
 73      if ($$theme !== currentTheme) {
 74        currentTheme = $$theme
 75        chart.dispose()
 76        chart = echarts.init(chartEl, currentTheme === 'default' ? null : currentTheme)
 77        updateOption()
 78      }
 79    })
 80
 81    // Set up resize observer with debounce
 82    let resizeTimeout
 83    const resizeObserver = new ResizeObserver(() => {
 84      clearTimeout(resizeTimeout)
 85      resizeTimeout = setTimeout(() => chart?.resize(), $$resizeDelay)
 86    })
 87    resizeObserver.observe(chartEl)
 88
 89    // Handle color scheme changes
 90    const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
 91    const handleSchemeChange = () => {
 92      if ($$theme === 'default') {
 93        chart.dispose()
 94        chart = echarts.init(chartEl, null)
 95        updateOption()
 96      }
 97    }
 98    mediaQuery.addEventListener('change', handleSchemeChange)
 99
100    // Cleanup on disconnect
101    onCleanup(() => {
102      resizeObserver.disconnect()
103      clearTimeout(resizeTimeout)
104      mediaQuery.removeEventListener('change', handleSchemeChange)
105      chart?.dispose()
106    })
107  </script>
108  <style>
109    .chart-container {
110      display: block;
111      width: 100%;
112      height: 100%;
113      min-height: inherit;
114      position: relative;
115      /* Important for ECharts' absolute positioned canvas */
116    }
117  </style>
118
119  <div class="chart-container" data-ref="chartNode"></div>
120</template>