123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- import MarkdownIt from "markdown-it";
- import type { RenderRule } from "markdown-it/lib/renderer.mjs";
- import type Token from "markdown-it/lib/token.mjs";
- import type { Options } from "markdown-it/lib/index.mjs";
- import type Renderer from "markdown-it/lib/renderer.mjs";
- import * as echarts from 'echarts'
- class EChartsElement extends HTMLDivElement {
- instance!: echarts.ECharts
- private resizeHandler!: () => void
- connectedCallback() {
- const config = decodeURIComponent(this.getAttribute('config') ?? '') ?? '';
- let data: echarts.EChartsOption
- try {
- data = JSON.parse(config)
- } catch (e) {
- console.error(e)
- return
- }
- this.instance = echarts.init(this)
- this.instance.setOption(data)
- // 创建绑定了正确上下文的 resize 处理器
- this.resizeHandler = () => {
- this.instance?.resize()
- }
- window.addEventListener('resize', this.resizeHandler)
- }
- disconnectedCallback() {
- // 清理 resize 事件监听器
- if (this.resizeHandler) {
- window.removeEventListener('resize', this.resizeHandler)
- }
- // 销毁 ECharts 实例
- if (this.instance) {
- this.instance.dispose()
- }
- }
- }
- export type EchartsPluginOptions = {
- }
- // 生成唯一ID
- function generateId(): string {
- return 'echarts-' + Math.random().toString(36).substring(2, 9)
- }
- // 验证JSON格式
- function isValidJSON(str: string): boolean {
- try {
- JSON.parse(str)
- return true
- } catch {
- return false
- }
- }
- // 渲染echarts代码块
- const renderEcharts: RenderRule = (tokens: Token[], idx: number, _options: Options, env: any, _self: Renderer) => {
- const token = tokens[idx]
- const content = token.content.trim()
- if (!content) {
- return '<div style="padding: 16px;background-color: #fff5f5;border: 1px solid #fed7d7;border-radius: 6px;color: #c53030;margin: 16px 0;">ECharts配置不能为空</div>'
- }
- const id = generateId()
- const className = env.echartsClassName || 'echarts-container'
- // 生成完整HTML
- return `<div is="echarts-container" style="width: 100%;height: 350px;margin: 16px 0; border-radius: 6px" class="${className}" id="${id}" config="${encodeURIComponent(content)}"></div>`
- }
- // markdown-it插件
- //@ts-ignore
- // eslint-disable-next-line no-unused-vars
- function echartsPlugin(md: MarkdownIt, options: EchartsPluginOptions = {}) {
- // 保存原始的fence渲染器
- const defaultRender = md.renderer.rules.fence ?? function(tokens, idx, options, _env, renderer) {
- return renderer.renderToken(tokens, idx, options)
- }
- if (customElements.get('echarts-container') === undefined) {
- customElements.define('echarts-container', EChartsElement, { extends: 'div' })
- }
- // 重写fence渲染器
- md.renderer.rules.fence = function(tokens, idx, options, env, renderer) {
- const token = tokens[idx]
- const info = token.info ? token.info.trim() : ''
- // 检查是否是echarts代码块
- if (info === 'echarts' && isValidJSON(token.content.trim())) {
- console.log(`prepare renderer`,tokens,idx,options,env,renderer,tokens[idx])
- return renderEcharts(tokens, idx, options, env, renderer)
- }
- // 其他代码块使用默认渲染器
- return defaultRender(tokens, idx, options, env, renderer)
- }
- }
- export default echartsPlugin
|