修改 Markdown 编译器 Vditor 支持 各类型 Echarts 配置项

  |   0 评论   |   0 浏览

Vditor 中的 echarts 图表,只能输入严格的 JSON 格式数据,参见 Echarts 页面渲染完整示例 ,源码如下 Vditor 示例,否则会报错,比如输入:

  1{
  2    backgroundColor: '#0e2147',
  3    grid: {
  4        left: '11%',
  5        top: '12%',
  6        right: '0%',
  7        bottom: '8%',
  8        containLabel: true
  9    },
 10    xAxis: [{
 11        show: false,
 12    }],
 13    yAxis: [{
 14        axisTick: 'none',
 15        axisLine: 'none',
 16        offset: '27',
 17        axisLabel: {
 18            textStyle: {
 19                color: '#ffffff',
 20                fontSize: '16',
 21            }
 22        },
 23        data: ['南昌', '广州', '杭州', '宁夏', '兰州', '南宁', '长沙', '武汉', '合肥', '贵州']
 24    }, {
 25        axisTick: 'none',
 26        axisLine: 'none',
 27        axisLabel: {
 28            textStyle: {
 29                color: '#ffffff',
 30                fontSize: '16',
 31            }
 32        },
 33        data: ['10', '9', '8', '7', '6', '5', '4', '3', '2', '1']
 34    }, {
 35        name: '分拨延误TOP 10',
 36        nameGap: '50',
 37        nameTextStyle: {
 38            color: '#ffffff',
 39            fontSize: '16',
 40        },
 41        axisLine: {
 42            lineStyle: {
 43                color: 'rgba(0,0,0,0)'
 44            }
 45        },
 46        data: [],
 47    }],
 48    series: [{
 49            name: '条',
 50            type: 'bar',
 51            yAxisIndex: 0,
 52            data: [4, 13, 25, 29, 38, 44, 50, 52, 60, 72],
 53            label: {
 54                normal: {
 55                    show: true,
 56                    position: 'right',
 57                    textStyle: {
 58                        color: '#ffffff',
 59                        fontSize: '16',
 60                    }
 61                }
 62            },
 63            barWidth: 12,
 64            itemStyle: {
 65                normal: {
 66                    color: function(params) {            
 67                        var myColor = ['#eb2100', '#eb3600', '#d0570e', '#d0a00e', '#34da62', '#00e9db', '#00c0e9', '#0096f3', '#33CCFF', '#33FFCC'];
 68                        var num = myColor.length;
 69                        return myColor[params.dataIndex % num]
 70                    },
 71                }
 72            },
 73            z: 2
 74        }, {
 75            name: '白框',
 76            type: 'bar',
 77            yAxisIndex: 1,
 78            barGap: '-100%',
 79            data: [99, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5],
 80            barWidth: 20,
 81            itemStyle: {
 82                normal: {
 83                    color: '#0e2147',
 84                    barBorderRadius: 5,
 85                }
 86            },
 87            z: 1
 88        }, {
 89            name: '外框',
 90            type: 'bar',
 91            yAxisIndex: 2,
 92            barGap: '-100%',
 93            data: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
 94            barWidth: 24,
 95            itemStyle: {
 96                normal: {
 97                    color: function(params) {           
 98                        var myColor = ['#eb2100', '#eb3600', '#d0570e', '#d0a00e', '#34da62', '#00e9db', '#00c0e9', '#0096f3', '#33CCFF', '#33FFCC'];
 99                        var num = myColor.length;
100                        return myColor[params.dataIndex % num]
101                    },
102                    barBorderRadius: 5,
103                }
104            },
105            z: 0
106        },
107        {
108            name: '外圆',
109            type: 'scatter',
110            hoverAnimation: false,
111            data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
112            yAxisIndex: 2,
113            symbolSize: 35,
114            itemStyle: {
115                normal: {
116                    color: function(params) {           
117                        var myColor = ['#eb2100', '#eb3600', '#d0570e', '#d0a00e', '#34da62', '#00e9db', '#00c0e9', '#0096f3', '#33CCFF', '#33FFCC'];
118                        var num = myColor.length;
119                        return myColor[params.dataIndex % num]
120                    },
121                    opacity: 1,
122                }
123            },
124            z: 2
125        }
126    ]
127}

会报错:

1echarts render error: 
2SyntaxError: Unexpected token s **in** JSON at position 2

只能输入以下严格的 JSON 格式才行,即所有字段以及字符串值都需要使用双引号括起来。

  1{
  2	"backgroundColor": "#0e2147",
  3	"grid": {
  4		"left": "11%",
  5		"top": "12%",
  6		"right": "0%",
  7		"bottom": "8%",
  8		"containLabel": true
  9	},
 10	"xAxis": [{
 11		"show": false
 12	}],
 13	"yAxis": [{
 14		"axisTick": "none",
 15		"axisLine": "none",
 16		"offset": "27",
 17		"axisLabel": {
 18			"textStyle": {
 19				"color": "#ffffff",
 20				"fontSize": "16"
 21			}
 22		},
 23		"data": ["南昌", "广州", "杭州", "宁夏", "兰州", "南宁", "长沙", "武汉", "合肥", "贵州"]
 24	}, {
 25		"axisTick": "none",
 26		"axisLine": "none",
 27		"axisLabel": {
 28			"textStyle": {
 29				"color": "#ffffff",
 30				"fontSize": "16"
 31			}
 32		},
 33		"data": ["10", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
 34	}, {
 35		"name": "分拨延误TOP 10",
 36		"nameGap": "50",
 37		"nameTextStyle": {
 38			"color": "#ffffff",
 39			"fontSize": "16"
 40		},
 41		"axisLine": {
 42			"lineStyle": {
 43				"color": "rgba(0,0,0,0)"
 44			}
 45		},
 46		"data": []
 47	}],
 48	"series": [{
 49		"name": "条",
 50		"type": "bar",
 51		"yAxisIndex": 0,
 52		"data": [4, 13, 25, 29, 38, 44, 50, 52, 60, 72],
 53		"label": {
 54			"normal": {
 55				"show": true,
 56				"position": "right",
 57				"textStyle": {
 58					"color": "#ffffff",
 59					"fontSize": "16"
 60				}
 61			}
 62		},
 63		"barWidth": 12,
 64		"itemStyle": {
 65			"normal": {}
 66		},
 67		"z": 2
 68	}, {
 69		"name": "白框",
 70		"type": "bar",
 71		"yAxisIndex": 1,
 72		"barGap": "-100%",
 73		"data": [99, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5],
 74		"barWidth": 20,
 75		"itemStyle": {
 76			"normal": {
 77				"color": "#0e2147",
 78				"barBorderRadius": 5
 79			}
 80		},
 81		"z": 1
 82	}, {
 83		"name": "外框",
 84		"type": "bar",
 85		"yAxisIndex": 2,
 86		"barGap": "-100%",
 87		"data": [100, 100, 100, 100, 100, 100, 100, 100, 100, 100],
 88		"barWidth": 24,
 89		"itemStyle": {
 90			"normal": {
 91				"barBorderRadius": 5
 92			}
 93		},
 94		"z": 0
 95	}, {
 96		"name": "外圆",
 97		"type": "scatter",
 98		"hoverAnimation": false,
 99		"data": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
100		"yAxisIndex": 2,
101		"symbolSize": 35,
102		"itemStyle": {
103			"normal": {
104				"opacity": 1
105			}
106		},
107		"z": 2
108	}]
109}

最终生成图表如下:

var myColor = ['#eb2100', '#eb3600', '#d0570e', '#d0a00e', '#34da62', '#00e9db', '#00c0e9', '#0096f3', '#33CCFF', '#33FFCC']; option = { backgroundColor: '#0e2147', grid: { left: '11%', top: '12%', right: '0%', bottom: '8%', containLabel: true }, xAxis: [{ show: false, }], yAxis: [{ axisTick: 'none', axisLine: 'none', offset: '27', axisLabel: { textStyle: { color: '#ffffff', fontSize: '16', } }, data: ["南昌", "广州", "杭州", "宁夏", "兰州", "南宁", "长沙", "武汉", "合肥", "贵州"] }, { axisTick: 'none', axisLine: 'none', axisLabel: { textStyle: { color: '#ffffff', fontSize: '16', } }, data: ['10', '9', '8', '7', '6', '5', '4', '3', '2', '1'] }, { name: '分拨延误TOP 10', nameGap: '50', nameTextStyle: { color: '#ffffff', fontSize: '16', }, axisLine: { lineStyle: { color: 'rgba(0,0,0,0)' } }, data: [], }], series: [{ name: '条', type: 'bar', yAxisIndex: 0, data: [4, 13, 25, 29, 38, 44, 50, 52, 60, 72], label: { normal: { show: true, position: 'right', textStyle: { color: '#ffffff', fontSize: '16', } } }, barWidth: 12, itemStyle: { normal: { color: function(params) { var num = myColor.length; return myColor[params.dataIndex % num] }, } }, z: 2 }, { name: '白框', type: 'bar', yAxisIndex: 1, barGap: '-100%', data: [99, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5, 99.5], barWidth: 20, itemStyle: { normal: { color: '#0e2147', barBorderRadius: 5, } }, z: 1 }, { name: '外框', type: 'bar', yAxisIndex: 2, barGap: '-100%', data: [100, 100, 100, 100, 100, 100, 100, 100, 100, 100], barWidth: 24, itemStyle: { normal: { color: function(params) { var num = myColor.length; return myColor[params.dataIndex % num] }, barBorderRadius: 5, } }, z: 0 }, { name: '外圆', type: 'scatter', hoverAnimation: false, data: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], yAxisIndex: 2, symbolSize: 35, itemStyle: { normal: { color: function(params) { var num = myColor.length; return myColor[params.dataIndex % num] }, opacity: 1, } }, z: 2 } ] };

但是目前官方还没修改,参见 希望 echarts 支持 js 格式的 json 其中提到,通过 修改 vditor 的源码可实现,把 src\ts\markdown\chartRender.ts 中的

1const option = JSON.parse(text)

改成

1var js = eval("(" + text + ")");
2var strJS = JSON.stringify(js);
3const option = JSON.parse(strJS)

即可实现,但是有一点问题就是 输入数据中不支持注释。然后使用以下命令编译:

1npm run build

编译成功后会生成 dist 目录,使用下面两个文件

1index.css
2index.min.js

替换 vditor.css 和 vditor.js 即可。

关于支持 JS 形式的配置项,通过研究 Echarts 官网的 example-bundle.js 中涉及 JS 形式配置项的代码:

1new Function("myChart", "app", "setTimeout", "setInterval", "ROOT_PATH", "var option; \n" + text + "\nreturn option;")

发现,可以采用 JS Function 来解决包含 JS 代码 的配置项结果获取,即修改 src\ts\markdown\chartRender.ts 中的

1const option = JSON.parse(text)
2echarts.init(e, theme === "dark" ? "dark" : undefined).setOption(option);

为以下代码,如果还有其他变量,可以在最后一个参数前继续加入。

 1const txtStr = text.replace(/^\s+|\s+$/g,''); 
 2
 3// 输入文本的函数定义, https://fuyiyi.imdo.co 如果有其他参数请加入
 4var optionFun = new Function('myChart',  'setTimeout', 'setInterval', 'var option; \n' + (txtStr.startsWith('{') ? 'option = ' : '') + txtStr + '\nreturn option;');
 5
 6// 原chartRender中的实例化后直接设置Option,现在拆开
 7var myChart = echarts.init(e, theme === "dark" ? "dark" : undefined);
 8
 9// 通过原 JS 形式配置项 获取最终的option,https://fuyiyi.imdo.co
10const option = optionFun(myChart, setTimeout, setInterval);
11myChart.setOption(option);

具体结果可参见 vditor/chartRender.ts at master · zxniuniu/vditor (github.com),然后编译后替换文件即可,大功告成!

如果有需要的,可直接引用 Vditor 为 https://fastly.jsdelivr.net/gh/zxniuniu/vditor@latest/dist/index.min.js

参考:

修改 vditor 以支持 javascript 形式的 json

vditor/chartRender.ts at master

charts/update-example.js snwowolf20170103/charts

JavaScript 函数