apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.2k stars 19.61k forks source link

[Feature] Request for JSON Schema #16427

Open maneetgoyal opened 2 years ago

maneetgoyal commented 2 years ago

What problem does this feature solve?

It will allow the users to validate whether the Echarts option they have authored is correct or not. Vega and Vega-Lite also provides it: https://github.com/vega/schema.

What does the proposed API look like?

.json files can be released. Or an ESM module can be released from where the JSON schema can be simply imported and later used by users as needed.

pissang commented 2 years ago

@maneetgoyal Hi, using TypeScript may provide a more accurate validation on the option.

maneetgoyal commented 2 years ago

Thanks for the reply @pissang. We are using TypeScript but we need run-time validation also as opposed to just compile-time validation. Say, while storing the option JSON coming from the client/front-end into a database at our backend, we need to make sure that the client sent properly formatted option.

pissang commented 2 years ago

We have a JSON schema for our doc page. https://github.com/apache/echarts-website/blob/asf-site/en/documents/option.json But I'm not sure if it's accurate enough for you. Perhaps you can have a try

maneetgoyal commented 2 years ago

Thanks again. If we run into any accuracy related issues, will bring it to the maintainers' notice. Feel free to close the issue AFAIC. 👍

maneetgoyal commented 2 years ago

@pissang Was taking a deeper look. The format of the JSON schema seems inconsistent with the specifications.

For example, the value of the first property $schema seems incorrect.

If providing the JSON schema is too much of a hassle, is there any other way (utility function), which can validate the option JSON during run time? Would be of great help.

georgechr commented 2 years ago

Hello, we are also looking for a valid schema. It's an important feature request

guhuajun commented 2 years ago

@pissang Was taking a deeper look. The format of the JSON schema seems inconsistent with the specifications.

For example, the value of the first property $schema seems incorrect.

If providing the JSON schema is too much of a hassle, is there any other way (utility function), which can validate the option JSON during run time? Would be of great help.

Greetings,

Just planning to build my own Python classes for generating echarts options, validations are also needed by me. And following content (WIP) is my first try to use Selenium to crawl all the properties. It's a little bit weird.

{
  "title": {
    "id": "",
    "show": "true",
    "text": "",
    "link": "",
    "target": "blank",
    "textStyle:": {},
    "subtext": "",
    "sublink": "",
    "subtarget": "blank",
    "subtextStyle:": {},
    "textAlign": "auto",
    "textVerticalAlign": "auto",
    "triggerEvent": "false",
    "padding": "5",
    "itemGap": "10",
    "zlevel": "0",
    "z": "2",
    "left": "auto",
    "top": "auto",
    "right": "auto",
    "bottom": "auto",
    "backgroundColor": "transparent",
    "borderColor": "#ccc",
    "borderWidth": "0",
    "borderRadius": "0",
    "shadowBlur": "",
    "shadowColor": "",
    "shadowOffsetX": "0",
    "shadowOffsetY": "0"
  },
  "legend": {
    "type": "",
    "id": "",
    "show": "true",
    "zlevel": "0",
    "z": "2",
    "left": "auto",
    "top": "auto",
    "right": "auto",
    "bottom": "auto",
    "width": "auto",
    "height": "auto",
    "orient": "horizontal",
    "align": "auto",
    "padding": "5",
    "itemGap": "10",
    "itemWidth": "25",
    "itemHeight": "14",
    "itemStyle:": {},
    "lineStyle:": {},
    "symbolRotate": "inherit",
    "formatter": "",
    "selectedMode": "true",
    "inactiveColor": "#ccc",
    "inactiveBorderColor": "#ccc",
    "inactiveBorderWidth": "auto",
    "selected": "",
    "textStyle:": {},
    "tooltip": "",
    "icon": "",
    "data:": [],
    "backgroundColor": "transparent",
    "borderColor": "#ccc",
    "borderWidth": "1",
    "borderRadius": "0",
    "shadowBlur": "",
    "shadowColor": "",
    "shadowOffsetX": "0",
    "shadowOffsetY": "0",
    "scrollDataIndex": "0",
    "pageButtonItemGap": "5",
    "pageButtonGap": "",
    "pageButtonPosition": "end",
    "pageFormatter": "{current}/{total}",
    "pageIcons:": {},
    "pageIconColor": "#2f4554",
    "pageIconInactiveColor": "#aaa",
    "pageIconSize": "15",
    "pageTextStyle:": {},
    "animation": "",
    "animationDurationUpdate": "800",
    "emphasis:": {},
    "selector": "false",
    "selectorLabel:": {},
    "selectorPosition": "auto",
    "selectorItemGap": "7",
    "selectorButtonGap": "10"
  },
  "grid": {
    "id": "",
    "show": "false",
    "zlevel": "0",
    "z": "2",
    "left": "10%",
    "top": "60",
    "right": "10%",
    "bottom": "60",
    "width": "auto",
    "height": "auto",
    "containLabel": "false",
    "backgroundColor": "transparent",
    "borderColor": "#ccc",
    "borderWidth": "1",
    "shadowBlur": "",
    "shadowColor": "",
    "shadowOffsetX": "0",
    "shadowOffsetY": "0",
    "tooltip:": {}
  },
  "xAxis": {
    "id": "",
    "show": "true",
    "gridIndex": "0",
    "alignTicks": "false",
    "position": "",
    "offset": "0",
    "type": "category",
    "name": "",
    "nameLocation": "end",
    "nameTextStyle:": {},
    "nameGap": "15",
    "nameRotate": "",
    "inverse": "false",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "minorSplitLine:": {},
    "splitArea:": {},
    "data:": [],
    "axisPointer:": {},
    "zlevel": "0",
    "z": "0"
  },
  "yAxis": {
    "id": "",
    "show": "true",
    "gridIndex": "0",
    "alignTicks": "false",
    "position": "",
    "offset": "0",
    "type": "value",
    "name": "",
    "nameLocation": "end",
    "nameTextStyle:": {},
    "nameGap": "15",
    "nameRotate": "",
    "inverse": "false",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "minorSplitLine:": {},
    "splitArea:": {},
    "data:": [],
    "axisPointer:": {},
    "zlevel": "0",
    "z": "0"
  },
  "polar": {
    "id": "",
    "zlevel": "0",
    "z": "2",
    "center": "[50%, 50%]",
    "radius": "",
    "tooltip:": {}
  },
  "radiusAxis": {
    "id": "",
    "polarIndex": "0",
    "type": "value",
    "name": "",
    "nameLocation": "end",
    "nameTextStyle:": {},
    "nameGap": "15",
    "nameRotate": "",
    "inverse": "false",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "minorSplitLine:": {},
    "splitArea:": {},
    "data:": [],
    "axisPointer:": {},
    "zlevel": "0",
    "z": "0"
  },
  "angleAxis": {
    "id": "",
    "polarIndex": "0",
    "startAngle": "90",
    "clockwise": "true",
    "type": "category",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "minorSplitLine:": {},
    "splitArea:": {},
    "data:": [],
    "axisPointer:": {},
    "zlevel": "0",
    "z": "0"
  },
  "radar": {
    "id": "",
    "zlevel": "0",
    "z": "2",
    "center": "[50%, 50%]",
    "radius": "75%",
    "startAngle": "90",
    "axisName:": {},
    "nameGap": "15",
    "splitNumber": "5",
    "shape": "polygon",
    "scale": "false",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "splitArea:": {},
    "indicator:": []
  },
  "dataZoom:": [],
  "visualMap:": [],
  "tooltip": {
    "show": "true",
    "trigger": "item",
    "axisPointer:": {},
    "showContent": "true",
    "alwaysShowContent": "false",
    "triggerOn": "mousemove|click",
    "showDelay": "0",
    "hideDelay": "100",
    "enterable": "false",
    "renderMode": "html",
    "confine": "false",
    "appendToBody": "false",
    "className": "",
    "transitionDuration": "0.4",
    "position": "",
    "formatter": "",
    "valueFormatter": "",
    "backgroundColor": "rgba(50,50,50,0.7)",
    "borderColor": "#333",
    "borderWidth": "0",
    "padding": "5",
    "textStyle:": {},
    "extraCssText": "",
    "order": "seriesAsc"
  },
  "axisPointer": {
    "id": "",
    "show": "false",
    "type": "line",
    "snap": "",
    "z": "",
    "label:": {},
    "lineStyle:": {},
    "shadowStyle:": {},
    "triggerTooltip": "true",
    "value": "",
    "status": "",
    "handle:": {},
    "link": "",
    "triggerOn": "mousemove|click"
  },
  "toolbox": {
    "id": "",
    "show": "true",
    "orient": "horizontal",
    "itemSize": "15",
    "itemGap": "8",
    "showTitle": "true",
    "feature:": {},
    "iconStyle:": {},
    "emphasis:": {},
    "zlevel": "0",
    "z": "2",
    "left": "auto",
    "top": "auto",
    "right": "auto",
    "bottom": "auto",
    "width": "auto",
    "height": "auto",
    "tooltip": ""
  },
  "brush": {
    "id": "",
    "toolbox": "[rect, polygon, keep, clear]",
    "brushLink": "",
    "seriesIndex": "all",
    "geoIndex": "",
    "xAxisIndex": "",
    "yAxisIndex": "",
    "brushType": "rect",
    "brushMode": "single",
    "transformable": "true",
    "brushStyle": "",
    "throttleType": "fixRate",
    "throttleDelay": "0",
    "removeOnClick": "true",
    "inBrush": "",
    "outOfBrush": "",
    "z": "10000"
  },
  "geo": {
    "id": "",
    "show": "true",
    "map": "",
    "roam": "false",
    "projection:": {},
    "center": "",
    "aspectScale": "0.75",
    "boundingCoords": "",
    "zoom": "1",
    "scaleLimit:": {},
    "nameMap": "",
    "nameProperty": "name",
    "selectedMode": "false",
    "label:": {},
    "itemStyle:": {},
    "emphasis:": {},
    "select:": {},
    "blur:": {},
    "zlevel": "0",
    "z": "2",
    "left": "auto",
    "top": "auto",
    "right": "auto",
    "bottom": "auto",
    "layoutCenter": "",
    "layoutSize": "",
    "regions:": [],
    "silent": "false",
    "tooltip:": {}
  },
  "parallel": {
    "id": "",
    "zlevel": "0",
    "z": "2",
    "left": "80",
    "top": "60",
    "right": "80",
    "bottom": "60",
    "width": "auto",
    "height": "auto",
    "layout": "horizontal",
    "axisExpandable": "false",
    "axisExpandCenter": "",
    "axisExpandCount": "0",
    "axisExpandWidth": "50",
    "axisExpandTriggerOn": "click",
    "parallelAxisDefault:": {}
  },
  "parallelAxis": {
    "id": "",
    "dim": "",
    "parallelIndex": "0",
    "realtime": "true",
    "areaSelectStyle:": {},
    "type": "value",
    "name": "",
    "nameLocation": "end",
    "nameTextStyle:": {},
    "nameGap": "15",
    "nameRotate": "",
    "inverse": "false",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "data:": []
  },
  "singleAxis": {
    "id": "",
    "zlevel": "0",
    "z": "2",
    "left": "5%",
    "top": "5%",
    "right": "5%",
    "bottom": "5%",
    "width": "auto",
    "height": "auto",
    "orient": "horizontal",
    "type": "value",
    "name": "",
    "nameLocation": "end",
    "nameTextStyle:": {},
    "nameGap": "15",
    "nameRotate": "",
    "inverse": "false",
    "boundaryGap": "",
    "min": "",
    "max": "",
    "scale": "false",
    "splitNumber": "5",
    "minInterval": "0",
    "maxInterval": "",
    "interval": "",
    "logBase": "10",
    "silent": "false",
    "triggerEvent": "false",
    "axisLine:": {},
    "axisTick:": {},
    "minorTick:": {},
    "axisLabel:": {},
    "splitLine:": {},
    "minorSplitLine:": {},
    "splitArea:": {},
    "data:": [],
    "axisPointer:": {},
    "tooltip:": {}
  },
  "timeline": {
    "show": "true",
    "type": "slider",
    "axisType": "time",
    "currentIndex": "0",
    "autoPlay": "false",
    "rewind": "false",
    "loop": "true",
    "playInterval": "2000",
    "realtime": "true",
    "replaceMerge": "undefined",
    "controlPosition": "left",
    "zlevel": "0",
    "z": "2",
    "left": "auto",
    "top": "auto",
    "right": "auto",
    "bottom": "auto",
    "padding": "5",
    "orient": "horizontal",
    "inverse": "false",
    "symbol": "emptyCircle",
    "symbolSize": "10",
    "symbolRotate": "",
    "symbolKeepAspect": "false",
    "symbolOffset": "[0, 0]",
    "lineStyle:": {},
    "label:": {},
    "itemStyle:": {},
    "checkpointStyle:": {},
    "controlStyle:": {},
    "progress:": {},
    "emphasis:": {},
    "data": ""
  },
  "graphic": { "id": "", "elements:": [] },
  "calendar": {
    "id": "",
    "zlevel": "0",
    "z": "2",
    "left": "80",
    "top": "60",
    "right": "auto",
    "bottom": "auto",
    "width": "auto",
    "height": "auto",
    "range": "",
    "cellSize": "20",
    "orient": "horizontal",
    "splitLine:": {},
    "itemStyle:": {},
    "dayLabel:": {},
    "monthLabel:": {},
    "yearLabel:": {},
    "silent": "false"
  },
  "dataset": {
    "id": "",
    "source": "",
    "dimensions": "",
    "sourceHeader": "",
    "transform:": [],
    "fromDatasetIndex": "",
    "fromDatasetId": "",
    "fromTransformResult": ""
  },
  "aria": { "enabled": "false", "label:": {}, "decal:": {} },
  "series:": [],
  "darkMode": "false",
  "color": [],
  "backgroundColor": "transparent",
  "textStyle": {
    "color": "#fff",
    "fontStyle": "normal",
    "fontWeight": "normal",
    "fontFamily": "sans-serif",
    "fontSize": "12",
    "lineHeight": "",
    "width": "",
    "height": "",
    "textBorderColor": "",
    "textBorderWidth": "",
    "textBorderType": "solid",
    "textBorderDashOffset": "0",
    "textShadowColor": "transparent",
    "textShadowBlur": "0",
    "textShadowOffsetX": "0",
    "textShadowOffsetY": "0",
    "overflow": "none",
    "ellipsis": "..."
  },
  "animation": "true",
  "animationThreshold": "2000",
  "animationDuration": "1000",
  "animationEasing": "cubicOut",
  "animationDelay": "0",
  "animationDurationUpdate": "300",
  "animationEasingUpdate": "cubicInOut",
  "animationDelayUpdate": "0",
  "stateAnimation": { "duration": "300", "easing": "cubicOut" },
  "blendMode": "source-over",
  "hoverLayerThreshold": "3000",
  "useUTC": "false",
  "options": [],
  "media:": []
}
cjw85 commented 1 year ago

@guhuajun We've actually built a pydantic model for eCharts after extracting the schema in the eCharts documentation build: https://github.com/epi2me-labs/ezcharts

Its not perfect: its highly redundant and there are various things where the schema is not correct and we've have to manually edit things to allow contructs we know render correctly to pass the pydantic models.

AaronNHart commented 8 months ago

+1, a schema would be quite nice to have considering the json format was identified as a key feature in the echarts paper.

lublak commented 2 weeks ago

Just some more infos, i tried to build a valid schema from https://github.com/apache/echarts-website/blob/asf-site/en/documents/option.json But there are some issues (i checked only one value after i give up):

path /xAxis/data grafik

which should have an anyOf only hast a "object" configured. This means that validation is not possible even with a valid schema.