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) }
|
||||
}
|
||||
'graph_title_row' {
|
||||
content = sh.wiki_title_chart(args)
|
||||
content = sh.wiki_title_chart(args)!
|
||||
}
|
||||
'graph_line_row' {
|
||||
content = sh.wiki_line_chart(args)!
|
||||
|
||||
@@ -260,7 +260,9 @@ pub fn (mut s Sheet) json() string {
|
||||
|
||||
// find row, report error if not found
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import freeflowuniverse.herolib.core.texttools
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
// 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_
|
||||
|
||||
_ := match args.period_type {
|
||||
|
||||
@@ -3,22 +3,12 @@ module spreadsheet
|
||||
import freeflowuniverse.herolib.data.markdownparser.elements
|
||||
import freeflowuniverse.herolib.ui.console
|
||||
|
||||
pub fn (mut s Sheet) wiki_title_chart(args RowGetArgs) string {
|
||||
if args.title.len > 0 {
|
||||
titletxt := "
|
||||
title: {
|
||||
text: '${args.title}',
|
||||
subtext: '${args.title_sub}',
|
||||
left: 'center'
|
||||
},
|
||||
"
|
||||
return titletxt
|
||||
}
|
||||
return ''
|
||||
pub fn (s Sheet) wiki_title_chart(args RowGetArgs) !string {
|
||||
return s.title_chart(args).markdown()
|
||||
}
|
||||
|
||||
pub fn (mut s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
|
||||
mut s := s_.filter(args)!
|
||||
pub fn (s_ Sheet) wiki_row_overview(args RowGetArgs) !string {
|
||||
s := s_.filter(args)!
|
||||
|
||||
rows_values := s.rows.values().map([it.name, it.description, it.tags])
|
||||
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
|
||||
// https://echarts.apache.org/examples/en/editor.html?c=line-stack
|
||||
pub fn (mut s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
|
||||
mut args := args_
|
||||
|
||||
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
|
||||
pub fn (s Sheet) wiki_line_chart(args_ RowGetArgs) !string {
|
||||
return s.line_chart(args_)!.markdown()
|
||||
}
|
||||
|
||||
// produce a nice looking bar chart see
|
||||
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
||||
pub fn (mut s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
|
||||
mut args := args_
|
||||
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
|
||||
pub fn (s Sheet) wiki_bar_chart(args_ RowGetArgs) !string {
|
||||
return s.bar_chart(args_)!.markdown()
|
||||
}
|
||||
|
||||
// produce a nice looking bar chart see
|
||||
// https://echarts.apache.org/examples/en/index.html#chart-type-bar
|
||||
pub fn (mut s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
|
||||
mut args := args_
|
||||
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
|
||||
pub fn (s Sheet) wiki_pie_chart(args_ RowGetArgs) !string {
|
||||
return s.pie_chart(args_)!.markdown()
|
||||
}
|
||||
|
||||
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