CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vue-echarts

Vue.js component for Apache ECharts™ providing declarative data visualization with Vue 2.7+ and Vue 3.1+ support

Pending
Overview
Eval results
Files

injection-system.mddocs/

Injection System

Vue injection keys for providing themes and configuration options to child components. Enables consistent theming and configuration across component hierarchies.

Capabilities

Theme Injection

Provides chart theme to child components, allowing consistent theming across multiple charts.

/**
 * Injection key for chart theme
 * Use with Vue's provide/inject to share themes across components
 */
declare const THEME_KEY: InjectionKey<ThemeInjection>;

type ThemeInjection = Injection<Theme>;
type Theme = NonNullable<Parameters<typeof init>[1]>;
type Injection<T> = T | null | Ref<T | null> | { value: T | null };

Usage Examples:

<!-- Parent component providing theme -->
<template>
  <div class="dashboard">
    <v-chart :option="chart1Option" />
    <v-chart :option="chart2Option" />
  </div>
</template>

<script setup>
import { provide } from "vue";
import { THEME_KEY } from "vue-echarts";

// Provide theme to all child charts
provide(THEME_KEY, "dark");

// Or provide reactive theme
const currentTheme = ref("light");
provide(THEME_KEY, currentTheme);

// Or provide theme object
const customTheme = {
  backgroundColor: "#1e1e1e",
  textStyle: { color: "#fff" }
};
provide(THEME_KEY, customTheme);
</script>
<!-- Child component consuming theme -->
<template>
  <v-chart :option="option" />
  <!-- Theme will be automatically applied -->
</template>

<script setup>
import { inject } from "vue";
import { THEME_KEY } from "vue-echarts";

// Access injected theme if needed
const theme = inject(THEME_KEY, null);
console.log("Current theme:", theme);
</script>

Init Options Injection

Provides ECharts initialization options to child components.

/**
 * Injection key for ECharts initialization options
 * Use with Vue's provide/inject to share init options
 */
declare const INIT_OPTIONS_KEY: InjectionKey<InitOptionsInjection>;

type InitOptionsInjection = Injection<InitOptions>;
type InitOptions = NonNullable<Parameters<typeof init>[2]>;

Usage Examples:

<!-- Parent providing init options -->
<script setup>
import { provide } from "vue";
import { INIT_OPTIONS_KEY } from "vue-echarts";

const initOptions = {
  renderer: "canvas",
  devicePixelRatio: 2,
  width: "auto",
  height: "auto",
  locale: "EN"
};

provide(INIT_OPTIONS_KEY, initOptions);
</script>

Update Options Injection

Provides chart update options to child components.

/**
 * Injection key for chart update options
 * Controls how charts update when options change
 */
declare const UPDATE_OPTIONS_KEY: InjectionKey<UpdateOptionsInjection>;

type UpdateOptionsInjection = Injection<UpdateOptions>;
type UpdateOptions = SetOptionOpts;

Usage Examples:

<!-- Parent providing update options -->
<script setup>
import { provide } from "vue";
import { UPDATE_OPTIONS_KEY } from "vue-echarts";

const updateOptions = {
  notMerge: false,
  replaceMerge: undefined,
  lazyUpdate: false
};

provide(UPDATE_OPTIONS_KEY, updateOptions);
</script>

Loading Options Injection

Provides loading animation options to child components.

/**
 * Injection key for loading animation options
 * Configures loading state appearance across charts
 */
declare const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection>;

type LoadingOptionsInjection = Injection<LoadingOptions>;

interface LoadingOptions {
  text?: string;
  textColor?: string;
  fontSize?: number | string;
  fontWeight?: number | string;
  fontStyle?: string;
  fontFamily?: string;
  maskColor?: string;
  showSpinner?: boolean;
  color?: string;
  spinnerRadius?: number;
  lineWidth?: number;
  zlevel?: number;
}

Usage Examples:

<!-- Parent providing loading options -->
<script setup>
import { provide } from "vue";
import { LOADING_OPTIONS_KEY } from "vue-echarts";

const loadingOptions = {
  text: "Loading data...",
  textColor: "#ffffff",
  fontSize: 14,
  maskColor: "rgba(0, 0, 0, 0.7)",
  showSpinner: true,
  color: "#409eff",
  spinnerRadius: 10,
  lineWidth: 2
};

provide(LOADING_OPTIONS_KEY, loadingOptions);
</script>

Complete Injection Setup

Setting up all injection providers in a root component:

<!-- Root dashboard component -->
<template>
  <div class="dashboard">
    <theme-switcher @change="handleThemeChange" />
    <chart-grid>
      <v-chart v-for="chart in charts" :key="chart.id" :option="chart.option" />
    </chart-grid>
  </div>
</template>

<script setup>
import { provide, ref } from "vue";
import { 
  THEME_KEY, 
  INIT_OPTIONS_KEY, 
  UPDATE_OPTIONS_KEY, 
  LOADING_OPTIONS_KEY 
} from "vue-echarts";

// Reactive theme
const currentTheme = ref("light");

// Static configuration
const initOptions = {
  renderer: "canvas",
  devicePixelRatio: window.devicePixelRatio || 1
};

const updateOptions = {
  notMerge: false,
  lazyUpdate: true
};

const loadingOptions = {
  text: "Loading...",
  showSpinner: true,
  color: "#409eff"
};

// Provide all options
provide(THEME_KEY, currentTheme);
provide(INIT_OPTIONS_KEY, initOptions);
provide(UPDATE_OPTIONS_KEY, updateOptions);
provide(LOADING_OPTIONS_KEY, loadingOptions);

function handleThemeChange(theme) {
  currentTheme.value = theme;
  // All child charts will automatically update
}
</script>

Nested Injection

Child components can override parent injections:

<!-- Parent component -->
<script setup>
import { provide } from "vue";
import { THEME_KEY } from "vue-echarts";

provide(THEME_KEY, "dark"); // Default theme
</script>

<template>
  <div>
    <v-chart :option="chart1" /> <!-- Uses dark theme -->
    <special-chart-section />
  </div>
</template>
<!-- Child component overriding theme -->
<script setup>
import { provide } from "vue";
import { THEME_KEY } from "vue-echarts";

provide(THEME_KEY, "light"); // Override with light theme
</script>

<template>
  <div class="special-section">
    <v-chart :option="chart2" /> <!-- Uses light theme -->
    <v-chart :option="chart3" /> <!-- Uses light theme -->
  </div>
</template>

Injection Utilities

Accessing injected values in custom components:

<script setup>
import { inject, computed } from "vue";
import { THEME_KEY, INIT_OPTIONS_KEY } from "vue-echarts";

// Inject with defaults
const theme = inject(THEME_KEY, "light");
const initOptions = inject(INIT_OPTIONS_KEY, {});

// Use in computed properties
const isDarkTheme = computed(() => {
  const themeValue = unref(theme);
  return themeValue === "dark" || 
         (typeof themeValue === "object" && themeValue?.backgroundColor === "#1e1e1e");
});

// Apply conditional styling
const containerClass = computed(() => ({
  "dark-container": isDarkTheme.value,
  "light-container": !isDarkTheme.value
}));
</script>

Vue 2 Compatibility

For Vue 2, when providing reactive values, wrap them in objects:

<!-- Vue 2 dynamic injection -->
<script>
export default {
  data() {
    return {
      themeWrapper: { value: "light" },
      initOptionsWrapper: { 
        value: { 
          renderer: "canvas",
          devicePixelRatio: 2 
        } 
      }
    };
  },
  provide() {
    return {
      [THEME_KEY]: this.themeWrapper,
      [INIT_OPTIONS_KEY]: this.initOptionsWrapper
    };
  },
  methods: {
    switchTheme() {
      this.themeWrapper.value = this.themeWrapper.value === "light" ? "dark" : "light";
    }
  }
};
</script>

Performance Considerations

When providing complex objects, consider memoization to avoid unnecessary re-renders:

<script setup>
import { provide, computed, ref } from "vue";
import { INIT_OPTIONS_KEY, UPDATE_OPTIONS_KEY } from "vue-echarts";

const devicePixelRatio = ref(window.devicePixelRatio || 1);
const locale = ref("EN");

// Memoized init options
const initOptions = computed(() => ({
  renderer: "canvas",
  devicePixelRatio: devicePixelRatio.value,
  locale: locale.value
}));

// Static update options (no need to compute)
const updateOptions = {
  notMerge: false,
  lazyUpdate: true,
  silent: false
};

provide(INIT_OPTIONS_KEY, initOptions);
provide(UPDATE_OPTIONS_KEY, updateOptions);

// Update pixel ratio on window changes
window.addEventListener("resize", () => {
  devicePixelRatio.value = window.devicePixelRatio || 1;
});
</script>

Install with Tessl CLI

npx tessl i tessl/npm-vue-echarts

docs

index.md

injection-system.md

main-component.md

tile.json