improve echart exporting
This commit is contained in:
@@ -92,7 +92,7 @@ pub fn playmacro(action Action) !string {
|
|||||||
content = sh.wiki(args) or { panic(err) }
|
content = sh.wiki(args) or { panic(err) }
|
||||||
}
|
}
|
||||||
'graph_title_row' {
|
'graph_title_row' {
|
||||||
content = sh.wiki_title_chart(args)
|
content = sh.wiki_title_chart(args)!
|
||||||
}
|
}
|
||||||
'graph_line_row' {
|
'graph_line_row' {
|
||||||
content = sh.wiki_line_chart(args)!
|
content = sh.wiki_line_chart(args)!
|
||||||
|
|||||||
@@ -260,7 +260,9 @@ pub fn (mut s Sheet) json() string {
|
|||||||
|
|
||||||
// find row, report error if not found
|
// find row, report error if not found
|
||||||
pub fn (s Sheet) row_get(name string) !&Row {
|
pub fn (s Sheet) row_get(name string) !&Row {
|
||||||
row := s.rows[name] or { return error('could not find row with name: ${name}, available rows: ${s.rows.keys()}') }
|
row := s.rows[name] or {
|
||||||
|
return error('could not find row with name: ${name}, available rows: ${s.rows.keys()}')
|
||||||
|
}
|
||||||
return row
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import freeflowuniverse.herolib.core.texttools
|
|||||||
import freeflowuniverse.herolib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
// format a sheet properly in wiki format
|
// format a sheet properly in wiki format
|
||||||
|
|
||||||
pub fn (mut s Sheet) wiki(args_ RowGetArgs) !string {
|
pub fn (s Sheet) wiki(args_ RowGetArgs) !string {
|
||||||
mut args := args_
|
mut args := args_
|
||||||
|
|
||||||
_ := match args.period_type {
|
_ := match args.period_type {
|
||||||
|
|||||||
@@ -3,22 +3,12 @@ module spreadsheet
|
|||||||
import freeflowuniverse.herolib.data.markdownparser.elements
|
import freeflowuniverse.herolib.data.markdownparser.elements
|
||||||
import freeflowuniverse.herolib.ui.console
|
import freeflowuniverse.herolib.ui.console
|
||||||
|
|
||||||
pub fn (mut s Sheet) wiki_title_chart(args RowGetArgs) string {
|
pub fn (s Sheet) wiki_title_chart(args RowGetArgs) !string {
|
||||||
if args.title.len > 0 {
|
return s.title_chart(args).markdown()
|
||||||
titletxt := "
|
|
||||||
title: {
|
|
||||||
text: '${args.title}',
|
|
||||||
subtext: '${args.title_sub}',
|
|
||||||
left: 'center'
|
|
||||||
},
|
|
||||||
"
|
|
||||||
return titletxt
|
|
||||||
}
|
|
||||||
return ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
|
pub fn (s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
|
||||||
mut s := s_.filter(args)!
|
s := s_.filter(args)!
|
||||||
|
|
||||||
rows_values := s.rows.values().map([it.name, it.description, it.tags])
|
rows_values := s.rows.values().map([it.name, it.description, it.tags])
|
||||||
mut rows := []elements.Row{}
|
mut rows := []elements.Row{}
|
||||||
@@ -43,146 +33,18 @@ pub fn (mut s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
|
|||||||
|
|
||||||
// produce a nice looking bar chart see
|
// produce a nice looking bar chart see
|
||||||
// https://echarts.apache.org/examples/en/editor.html?c=line-stack
|
// https://echarts.apache.org/examples/en/editor.html?c=line-stack
|
||||||
pub fn (mut s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
|
pub fn (s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
|
||||||
mut args := args_
|
return s.line_chart(args_)!.markdown()
|
||||||
|
|
||||||
rownames := s.rownames_get(args)!
|
|
||||||
header := s.header_get_as_string(args.period_type)!
|
|
||||||
mut series_lines := []string{}
|
|
||||||
|
|
||||||
for rowname in rownames {
|
|
||||||
data := s.data_get_as_string(RowGetArgs{
|
|
||||||
...args
|
|
||||||
rowname: rowname
|
|
||||||
})!
|
|
||||||
series_lines << '{
|
|
||||||
name: \'${rowname}\',
|
|
||||||
type: \'line\',
|
|
||||||
stack: \'Total\',
|
|
||||||
data: [${data}]
|
|
||||||
}'
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: need to implement the multiple results which can come back from the args, can be more than 1
|
|
||||||
|
|
||||||
// header := s.header_get_as_string(args.period_type)!
|
|
||||||
// data := s.data_get_as_string(args)!
|
|
||||||
// console.print_debug('HERE! ${header}')
|
|
||||||
// console.print_debug('HERE!! ${data}')
|
|
||||||
|
|
||||||
template := "
|
|
||||||
${s.wiki_title_chart(args)}
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
data: ${rownames}
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '3%',
|
|
||||||
right: '4%',
|
|
||||||
bottom: '3%',
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
toolbox: {
|
|
||||||
feature: {
|
|
||||||
saveAsImage: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
boundaryGap: false,
|
|
||||||
data: [${header}]
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value'
|
|
||||||
},
|
|
||||||
series: [${series_lines.join(',')}]
|
|
||||||
"
|
|
||||||
out := remove_empty_line('```echarts\n{${template}\n};\n```\n')
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// produce a nice looking bar chart see
|
// produce a nice looking bar chart see
|
||||||
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
||||||
pub fn (mut s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
|
pub fn (s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
|
||||||
mut args := args_
|
return s.bar_chart(args_)!.markdown()
|
||||||
args.rowname = s.rowname_get(args)!
|
|
||||||
header := s.header_get_as_string(args.period_type)!
|
|
||||||
data := s.data_get_as_string(args)!
|
|
||||||
bar1 := "
|
|
||||||
${s.wiki_title_chart(args)}
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: [${header}]
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: 'value'
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
data: [${data}],
|
|
||||||
type: 'bar',
|
|
||||||
showBackground: true,
|
|
||||||
backgroundStyle: {
|
|
||||||
color: 'rgba(180, 180, 180, 0.2)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
"
|
|
||||||
out := remove_empty_line('```echarts\n{${bar1}\n};\n```\n')
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// produce a nice looking bar chart see
|
// produce a nice looking bar chart see
|
||||||
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
||||||
pub fn (mut s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
|
pub fn (s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
|
||||||
mut args := args_
|
return s.pie_chart(args_)!.markdown()
|
||||||
args.rowname = s.rowname_get(args)!
|
|
||||||
header := s.header_get_as_list(args.period_type)!
|
|
||||||
data := s.data_get_as_list(args)!
|
|
||||||
|
|
||||||
mut radius := ''
|
|
||||||
if args.size.len > 0 {
|
|
||||||
radius = "radius: '${args.size}',"
|
|
||||||
}
|
|
||||||
|
|
||||||
if header.len != data.len {
|
|
||||||
return error('data and header lengths must match.\n${header}\n${data}')
|
|
||||||
}
|
|
||||||
|
|
||||||
mut data_lines := []string{}
|
|
||||||
for i, _ in data {
|
|
||||||
data_lines << '{ value: ${data[i]}, name: ${header[i]}}'
|
|
||||||
}
|
|
||||||
data_str := '[${data_lines.join(',')}]'
|
|
||||||
|
|
||||||
bar1 := "
|
|
||||||
${s.wiki_title_chart(args)}
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'item'
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
orient: 'vertical',
|
|
||||||
left: 'left'
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
name: 'Access From',
|
|
||||||
type: 'pie',
|
|
||||||
${radius}
|
|
||||||
data: ${data_str},
|
|
||||||
emphasis: {
|
|
||||||
itemStyle: {
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowOffsetX: 0,
|
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
"
|
|
||||||
out := remove_empty_line('```echarts\n{${bar1}\n};\n```\n')
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
|
|||||||
87
lib/web/echarts/echarts.v
Normal file
87
lib/web/echarts/echarts.v
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
module echarts
|
||||||
|
|
||||||
|
import json
|
||||||
|
import x.json2
|
||||||
|
|
||||||
|
pub struct Title {
|
||||||
|
pub:
|
||||||
|
text string @[json: 'text'; omitempty]
|
||||||
|
subtext string @[json: 'subtext'; omitempty]
|
||||||
|
left string @[json: 'left'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Tooltip {
|
||||||
|
pub:
|
||||||
|
trigger string @[json: 'trigger'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Legend {
|
||||||
|
pub:
|
||||||
|
data []string @[json: 'data'; omitempty]
|
||||||
|
orient string @[omitempty]
|
||||||
|
left string @[omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Grid {
|
||||||
|
pub:
|
||||||
|
left string @[json: 'left'; omitempty]
|
||||||
|
right string @[json: 'right'; omitempty]
|
||||||
|
bottom string @[json: 'bottom'; omitempty]
|
||||||
|
contain_label bool @[json: 'containLabel'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ToolboxFeature {
|
||||||
|
pub:
|
||||||
|
save_as_image map[string]string @[json: 'saveAsImage'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Toolbox {
|
||||||
|
pub:
|
||||||
|
feature ToolboxFeature @[json: 'feature'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct XAxis {
|
||||||
|
pub:
|
||||||
|
type_ string @[json: 'type'; omitempty]
|
||||||
|
boundary_gap bool @[json: 'boundaryGap'; omitempty]
|
||||||
|
data []string @[json: 'data'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct YAxis {
|
||||||
|
pub:
|
||||||
|
type_ string @[json: 'type'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Series {
|
||||||
|
pub:
|
||||||
|
name string @[json: 'name'; omitempty]
|
||||||
|
type_ string @[json: 'type'; omitempty]
|
||||||
|
stack string @[json: 'stack'; omitempty]
|
||||||
|
data []string @[json: 'data'; omitempty]
|
||||||
|
radius int @[omitempty]
|
||||||
|
emphasis Emphasis @[omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Emphasis {
|
||||||
|
pub:
|
||||||
|
item_style ItemStyle @[json: 'itemStyle'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ItemStyle {
|
||||||
|
pub:
|
||||||
|
shadow_blur int @[json: 'shadowBlur'; omitempty]
|
||||||
|
shadow_offset_x int @[json: 'shadowOffsetX'; omitempty]
|
||||||
|
shadow_color string @[json: 'shadowColor'; omitempty]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EChartsOption {
|
||||||
|
pub:
|
||||||
|
title Title @[json: 'title'; omitempty]
|
||||||
|
tooltip Tooltip @[json: 'tooltip'; omitempty]
|
||||||
|
legend Legend @[json: 'legend'; omitempty]
|
||||||
|
grid Grid @[json: 'grid'; omitempty]
|
||||||
|
toolbox Toolbox @[json: 'toolbox'; omitempty]
|
||||||
|
x_axis XAxis @[json: 'xAxis'; omitempty]
|
||||||
|
y_axis YAxis @[json: 'yAxis'; omitempty]
|
||||||
|
series []Series @[json: 'series'; omitempty]
|
||||||
|
}
|
||||||
55
lib/web/echarts/echarts_test.v
Normal file
55
lib/web/echarts/echarts_test.v
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
module echarts
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
const option_json = '{"title":{"text":"Main Title","subtext":"Subtitle","left":"center"},"tooltip":{"trigger":"axis"},"legend":{"data":["Example1","Example2"]},"grid":{"left":"3%","right":"4%","bottom":"3%","containLabel":true},"xAxis":{"type":"category","data":["Jan","Feb","Mar"]},"yAxis":{"type":"value"},"series":[{"name":"Example1","type":"line","stack":"Total","data":["10","20","30"]},{"name":"Example2","type":"line","stack":"Total","data":["15","25","35"]}]}'
|
||||||
|
|
||||||
|
fn test_echarts() {
|
||||||
|
option := EChartsOption{
|
||||||
|
title: Title{
|
||||||
|
text: 'Main Title'
|
||||||
|
subtext: 'Subtitle'
|
||||||
|
left: 'center'
|
||||||
|
}
|
||||||
|
tooltip: Tooltip{
|
||||||
|
trigger: 'axis'
|
||||||
|
}
|
||||||
|
legend: Legend{
|
||||||
|
data: ['Example1', 'Example2']
|
||||||
|
}
|
||||||
|
grid: Grid{
|
||||||
|
left: '3%'
|
||||||
|
right: '4%'
|
||||||
|
bottom: '3%'
|
||||||
|
contain_label: true
|
||||||
|
}
|
||||||
|
toolbox: Toolbox{
|
||||||
|
feature: ToolboxFeature{
|
||||||
|
save_as_image: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x_axis: XAxis{
|
||||||
|
type_: 'category'
|
||||||
|
boundary_gap: false
|
||||||
|
data: ['Jan', 'Feb', 'Mar']
|
||||||
|
}
|
||||||
|
y_axis: YAxis{
|
||||||
|
type_: 'value'
|
||||||
|
}
|
||||||
|
series: [
|
||||||
|
Series{
|
||||||
|
name: 'Example1'
|
||||||
|
type_: 'line'
|
||||||
|
stack: 'Total'
|
||||||
|
data: ['10', '20', '30']
|
||||||
|
},
|
||||||
|
Series{
|
||||||
|
name: 'Example2'
|
||||||
|
type_: 'line'
|
||||||
|
stack: 'Total'
|
||||||
|
data: ['15', '25', '35']
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
assert json.encode(option) == option_json
|
||||||
|
}
|
||||||
120
lib/web/echarts/encode.v
Normal file
120
lib/web/echarts/encode.v
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
module echarts
|
||||||
|
|
||||||
|
import x.json2 as json
|
||||||
|
|
||||||
|
pub fn (o EChartsOption) json() string {
|
||||||
|
return json.encode(o)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (o EChartsOption) mdx() string {
|
||||||
|
option := format_js_object(o, true)
|
||||||
|
return '<EChart option={${option}} />'
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn (o EChartsOption) markdown() string {
|
||||||
|
option := format_js_object(o, true)
|
||||||
|
return '```echarts\n{${option}\n};\n```\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic function to format JavaScript-like objects
|
||||||
|
fn format_js_object[T](obj T, omitempty bool) string {
|
||||||
|
mut result := ''
|
||||||
|
result += '{'
|
||||||
|
|
||||||
|
$for field in T.fields {
|
||||||
|
field_name := if field.attrs.any(it.starts_with('json:')) {
|
||||||
|
field.attrs.filter(it.starts_with('json'))[0].all_after('json:').trim_space()
|
||||||
|
} else {
|
||||||
|
field.name
|
||||||
|
}
|
||||||
|
value := obj.$(field.name)
|
||||||
|
formatted_value := format_js_value(value, field.attrs.contains('omitempty'))
|
||||||
|
if formatted_value.trim_space() != '' || !omitempty {
|
||||||
|
result += '${field_name}: ${formatted_value.trim_space()}, '
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += '}'
|
||||||
|
if result == '{}' && omitempty {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
return result.str().replace(', }', '}') // Remove trailing comma
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fully generic function to format any JS value
|
||||||
|
// TODO: improve code below, far from cleanest implementation
|
||||||
|
// currently is sufficient since only used in echart mdx export
|
||||||
|
fn format_js_value[T](value T, omitempty bool) string {
|
||||||
|
return $if T is string {
|
||||||
|
// is actually map
|
||||||
|
if value.str().starts_with('{') && value.str().ends_with('}') {
|
||||||
|
value
|
||||||
|
// map_any := json2.raw_decode(value.str()) or {'{}'}.as_map()
|
||||||
|
// println('debugzo21 ${map_any}')
|
||||||
|
// mut val := '{'
|
||||||
|
// for k, v in map_any {
|
||||||
|
// val += '${k}: ${format_js_value(v.str(), false)}'
|
||||||
|
// }
|
||||||
|
// val += '}'
|
||||||
|
// if val == '{}' && omitempty {
|
||||||
|
// return ''
|
||||||
|
// }
|
||||||
|
// val
|
||||||
|
} else {
|
||||||
|
val := '"${value}"'
|
||||||
|
if val == '""' && omitempty {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
val
|
||||||
|
}
|
||||||
|
} $else $if T is int {
|
||||||
|
if '${value}' == '0' && omitempty {
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
'${value}'
|
||||||
|
}
|
||||||
|
} $else $if T is f64 {
|
||||||
|
if '${value}' == '0.0' && omitempty {
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
'${value}'
|
||||||
|
}
|
||||||
|
} $else $if T is bool {
|
||||||
|
if '${value}' == 'false' && omitempty {
|
||||||
|
''
|
||||||
|
} else {
|
||||||
|
'${value}'
|
||||||
|
}
|
||||||
|
} $else $if T is $struct {
|
||||||
|
val := format_js_object(value, omitempty)
|
||||||
|
if val == '' && omitempty {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
val
|
||||||
|
} $else $if T is $array {
|
||||||
|
mut arr := '['
|
||||||
|
for i in 0 .. value.len {
|
||||||
|
if i != 0 {
|
||||||
|
arr += ', '
|
||||||
|
}
|
||||||
|
val := format_js_value(value[i], omitempty)
|
||||||
|
if val.starts_with('"{') && val.ends_with('}"') {
|
||||||
|
arr += val.trim('"')
|
||||||
|
} else if val.starts_with('"\'') && val.ends_with('\'"') {
|
||||||
|
arr += val.trim('"')
|
||||||
|
} else if val.trim('"').trim_space().f64() != 0 {
|
||||||
|
arr += val.trim('"').trim_space()
|
||||||
|
} else if val.trim('"').trim_space() == '0' || val.trim('"').trim_space() == '0.0' {
|
||||||
|
arr += '0'
|
||||||
|
} else {
|
||||||
|
arr += val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr += ']'
|
||||||
|
if omitempty && arr == '[]' {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
arr
|
||||||
|
} $else {
|
||||||
|
'null'
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user