mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
[html-chart] add html-chart.scm to access ChartJS
This is very similar to (but not 100% drop-in replacement) jqplot.
This commit is contained in:
parent
847c531fdd
commit
24550714f3
@ -61,6 +61,7 @@ set (report_system_SCHEME_2b
|
||||
set (report_system_SCHEME_3
|
||||
commodity-utilities.scm
|
||||
html-acct-table.scm
|
||||
html-chart.scm
|
||||
html-barchart.scm
|
||||
html-document.scm
|
||||
html-fonts.scm
|
||||
|
489
gnucash/report/report-system/html-chart.scm
Normal file
489
gnucash/report/report-system/html-chart.scm
Normal file
@ -0,0 +1,489 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; html-chart.scm : generate HTML programmatically, with support
|
||||
;; for simple style elements.
|
||||
;;
|
||||
;; Added dependency on guile-json to help construct options. Migrated
|
||||
;; from obsolete jquery and jqplot to modern chartjs instead in 2018
|
||||
;; by Christopher Lam
|
||||
;;
|
||||
;; This program is free software; you can redistribute it and/or
|
||||
;; modify it under the terms of the GNU General Public License as
|
||||
;; published by the Free Software Foundation; either version 2 of
|
||||
;; the License, or (at your option) any later version.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program; if not, contact:
|
||||
;;
|
||||
;; Free Software Foundation Voice: +1-617-542-5942
|
||||
;; 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
|
||||
;; Boston, MA 02110-1301, USA gnu@gnu.org
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(use-modules (json builder)) ;for building JSON options
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; utility functions for nested list handling
|
||||
;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; nested-alist-set! parameters are
|
||||
;; lst - a nested alist e.g. (list (cons 'key1 'val1)
|
||||
;; (cons 'key2 (list (cons 'key2-sub1 'val2a))))
|
||||
;; path - a list of symbols or single-element list
|
||||
;; e.g. '(key2 key2-sub1)
|
||||
;; '(key2 key2-sub2 (0))
|
||||
;; '(key3 key3-sub1 key3-sub1-sub1)
|
||||
;; newval - the cdr of the innermost cons cell specified by the path
|
||||
;;
|
||||
;; see test-html-chart.scm for usage examples
|
||||
(define (nested-alist-set! lst path newval)
|
||||
(define (path->nested-alist path newval)
|
||||
(let innerloop ((path (reverse path))
|
||||
(result newval))
|
||||
(cond
|
||||
((null? path)
|
||||
result)
|
||||
((and (pair? (car path)) (number? (caar path)))
|
||||
(innerloop (cdr path)
|
||||
(let ((v (make-vector (1+ (caar path)))))
|
||||
(vector-set! v (caar path) result)
|
||||
v)))
|
||||
(else
|
||||
(innerloop (cdr path)
|
||||
(list (cons (car path) result)))))))
|
||||
|
||||
(let loop ((nested-lst lst) (path path))
|
||||
(cond
|
||||
((or (null? nested-lst) (null? path))
|
||||
(throw "invalid state"))
|
||||
((and (pair? (car path)) (number? (caar path)))
|
||||
(cond
|
||||
((>= (caar path) (vector-length nested-lst))
|
||||
(throw (format #f "high vector index ~s must be set earlier"
|
||||
(caar path))))
|
||||
((list? (vector-ref nested-lst (caar path)))
|
||||
(loop (vector-ref nested-lst (caar path))
|
||||
(cdr path)))
|
||||
(else
|
||||
(vector-set! nested-lst
|
||||
(caar path)
|
||||
(path->nested-alist (cdr path) newval)))))
|
||||
(else
|
||||
(let ((kvp (assq (car path) nested-lst)))
|
||||
(cond
|
||||
((not kvp) ; new branch. append to end of parent branch
|
||||
(list-cdr-set! nested-lst
|
||||
(1- (length nested-lst))
|
||||
(path->nested-alist path newval)))
|
||||
((null? (cdr path)) ; existing branch, last path. replace pair's cdr
|
||||
(set-cdr! kvp newval))
|
||||
(else ; existing branch. traverse into next layer.
|
||||
(loop (cdr kvp) (cdr path)))))))))
|
||||
|
||||
(define (nested-alist-get lst path)
|
||||
(let loop ((nested-lst lst) (path path))
|
||||
(cond
|
||||
((null? path)
|
||||
nested-lst)
|
||||
((null? nested-lst)
|
||||
(throw "invalid state. most likely the initial list is empty."))
|
||||
((and (pair? (car path)) (number? (caar path)))
|
||||
(cond
|
||||
((>= (caar path) (vector-length nested-lst))
|
||||
(throw (format #f "invalid path vector index ~s too high"
|
||||
(caar path))))
|
||||
(else
|
||||
(loop (vector-ref nested-lst (caar path))
|
||||
(cdr path)))))
|
||||
(else
|
||||
(let ((kvp (assq (car path) nested-lst)))
|
||||
(cond
|
||||
((not kvp)
|
||||
(throw (format #f "invalid path: ~s" path)))
|
||||
(else
|
||||
(loop (cdr kvp) (cdr path)))))))))
|
||||
|
||||
;; helper for setting data - guile-json expects vectors to be
|
||||
;; transformed into JSON arrays; convert list to vector. if not list,
|
||||
;; leave alone.
|
||||
(define (list-to-vec v)
|
||||
(if (list? v)
|
||||
(list->vector v)
|
||||
v))
|
||||
|
||||
;; The html-chart specifies options and data to create a chart. The
|
||||
;; old chart toolkits guppi and jqplot seemed to require restrictive
|
||||
;; specific formats for the options and data, and modern toolkit
|
||||
;; chartjs is more permissive. Nonetheless some of the restrictions
|
||||
;; remain.
|
||||
|
||||
;; At minimum the html-chart will require setting the following
|
||||
;; fields:
|
||||
;; type - one of 'bar 'line 'pie
|
||||
;; width - pair
|
||||
;; height - pair
|
||||
|
||||
(define <html-chart>
|
||||
(make-record-type "<html-chart>"
|
||||
'(width
|
||||
height
|
||||
chart-options
|
||||
currency-iso
|
||||
currency-symbol
|
||||
custom-x-axis-ticks?
|
||||
custom-y-axis-ticks?)))
|
||||
|
||||
(define gnc:html-chart?
|
||||
(record-predicate <html-chart>))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; <html-chart> class
|
||||
;; generate the <object> form for an html chart.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(define gnc:make-html-chart-internal
|
||||
(record-constructor <html-chart>))
|
||||
|
||||
(define (gnc:make-html-chart)
|
||||
(gnc:make-html-chart-internal
|
||||
'(percent . 100) ;;width
|
||||
'(percent . 100) ;;height
|
||||
(list ;;chartjs options object
|
||||
(cons 'type 'bar)
|
||||
(cons 'data (list
|
||||
(cons 'labels #())
|
||||
(cons 'datasets #())))
|
||||
(cons 'options (list
|
||||
(cons 'maintainAspectRatio #f)
|
||||
(cons 'chartArea (list
|
||||
(cons 'backgroundColor "#fffdf6")))
|
||||
(cons 'legend (list
|
||||
(cons 'position 'right)
|
||||
(cons 'reverse #f)
|
||||
(cons 'labels (list
|
||||
(cons 'fontColor 'black)))))
|
||||
|
||||
(cons 'elements (list
|
||||
(cons 'line (list
|
||||
(cons 'tension 0)))
|
||||
(cons 'point (list
|
||||
(cons 'pointStyle #f)))))
|
||||
(cons 'tooltips (list
|
||||
(cons 'callbacks (list
|
||||
(cons 'label #f)))))
|
||||
|
||||
(cons 'scales (list
|
||||
(cons 'xAxes (vector
|
||||
(list
|
||||
(cons 'display #t)
|
||||
(cons 'type 'category)
|
||||
(cons 'distribution 'series)
|
||||
(cons 'offset #t)
|
||||
(cons 'gridLines (list
|
||||
(cons 'display #t)
|
||||
(cons 'lineWidth 1.5)))
|
||||
(cons 'scaleLabel (list
|
||||
(cons 'display #t)
|
||||
(cons 'labelString "")))
|
||||
(cons 'ticks (list
|
||||
(cons 'fontSize 12)
|
||||
(cons 'maxRotation 30))))
|
||||
;; the following another xAxis at the top
|
||||
'((position . top)
|
||||
(ticks . ((display . #f)))
|
||||
(gridLines . ((display . #f)
|
||||
(drawTicks . #f))))
|
||||
))
|
||||
(cons 'yAxes (vector
|
||||
(list
|
||||
(cons 'stacked #f)
|
||||
(cons 'display #t)
|
||||
(cons 'gridLines (list
|
||||
(cons 'display #t)
|
||||
(cons 'lineWidth 1.5)))
|
||||
(cons 'scaleLabel (list
|
||||
(cons 'display 1.5)
|
||||
(cons 'labelString "")))
|
||||
(cons 'ticks (list
|
||||
(cons 'fontSize 10)
|
||||
(cons 'beginAtZero #f))))
|
||||
;; the following another yAxis on the right
|
||||
'((position . right)
|
||||
(ticks . ((display . #f)))
|
||||
(gridLines . ((display . #f)
|
||||
(drawTicks . #f))))
|
||||
))))
|
||||
(cons 'title (list
|
||||
(cons 'display #t)
|
||||
(cons 'fontSize 16)
|
||||
(cons 'fontStyle "")
|
||||
(cons 'text ""))))))
|
||||
"XXX" ;currency-iso
|
||||
"\u00A4" ;currency-symbol
|
||||
#t ;custom x-axis ticks?
|
||||
#t ;custom y-axis ticks?
|
||||
))
|
||||
|
||||
(define gnc:html-chart-width
|
||||
(record-accessor <html-chart> 'width))
|
||||
|
||||
(define gnc:html-chart-set-width!
|
||||
(record-modifier <html-chart> 'width))
|
||||
|
||||
(define gnc:html-chart-height
|
||||
(record-accessor <html-chart> 'height))
|
||||
|
||||
(define gnc:html-chart-set-height!
|
||||
(record-modifier <html-chart> 'height))
|
||||
|
||||
(define (gnc:html-chart-type chart)
|
||||
(gnc:html-chart-get chart '(type)))
|
||||
|
||||
(define (gnc:html-chart-set-type! chart type)
|
||||
(gnc:html-chart-set! chart '(type) type))
|
||||
|
||||
(define (gnc:html-chart-title chart)
|
||||
(gnc:html-chart-get chart '(options title text)))
|
||||
|
||||
(define-public (gnc:html-chart-set-title! chart title)
|
||||
(gnc:html-chart-set! chart '(options title text) title))
|
||||
|
||||
(define-public (gnc:html-chart-set-data-labels! chart labels)
|
||||
(gnc:html-chart-set! chart '(data labels) labels))
|
||||
|
||||
(define-public (gnc:html-chart-set-axes-display! chart display?)
|
||||
(gnc:html-chart-set! chart '(options scales xAxes (0) display) display?)
|
||||
(gnc:html-chart-set! chart '(options scales yAxes (0) display) display?))
|
||||
|
||||
(export gnc:html-chart-add-data-series!)
|
||||
;; e.g.:
|
||||
;; (gnc:html-chart-add-data-series! chart "label" list-of-numbers color
|
||||
;; 'fill #t
|
||||
;; 'urls "gnc-report:id=13#")
|
||||
;;
|
||||
;; chart - html-chart object
|
||||
;; "label" - data series label eg. "Income"
|
||||
;; data - a list-of-numbers specifying series data
|
||||
;; color - a string specifying series colour
|
||||
;;
|
||||
;; other keys may be specified, see ChartJS documentation
|
||||
;; 'fill - fill bar, or fill under line?
|
||||
;; 'borderWidth - line width
|
||||
;; 'urls - either a string (same url for whole data series)
|
||||
;; or a list-of-string (individual url for each data point)
|
||||
;; see javascript onClick event handler how they are decoded
|
||||
(define* (gnc:html-chart-add-data-series! chart label data color . rest)
|
||||
(let loop ((rest rest)
|
||||
(newseries (list
|
||||
(cons 'data (list-to-vec data))
|
||||
(cons 'label label)
|
||||
(cons 'backgroundColor (list-to-vec color))
|
||||
(cons 'borderColor (list-to-vec color)))))
|
||||
(if (null? rest)
|
||||
(gnc:html-chart-set!
|
||||
chart '(data datasets)
|
||||
(list->vector
|
||||
(append (vector->list
|
||||
(or (gnc:html-chart-get chart '(data datasets))
|
||||
#()))
|
||||
(list newseries))))
|
||||
(loop (cddr rest)
|
||||
(assq-set! newseries
|
||||
(car rest)
|
||||
(list-to-vec (cadr rest)))))))
|
||||
|
||||
(define-public (gnc:html-chart-clear-data-series! chart)
|
||||
(gnc:html-chart-set! chart '(data datasets) #()))
|
||||
|
||||
(define-public (gnc:html-chart-set-x-axis-label! chart label)
|
||||
(gnc:html-chart-set! chart '(options scales xAxes (0) scaleLabel labelString) label))
|
||||
|
||||
(define-public (gnc:html-chart-set-stacking?! chart stack?)
|
||||
(gnc:html-chart-set! chart '(options scales xAxes (0) stacked) stack?)
|
||||
(gnc:html-chart-set! chart '(options scales yAxes (0) stacked) stack?))
|
||||
|
||||
(define-public (gnc:html-chart-set-grid?! chart grid?)
|
||||
(gnc:html-chart-set! chart '(options scales xAxes (0) gridLines display) grid?)
|
||||
(gnc:html-chart-set! chart '(options scales yAxes (0) gridLines display) grid?))
|
||||
|
||||
(define-public (gnc:html-chart-set-y-axis-label! chart label)
|
||||
(gnc:html-chart-set! chart '(options scales yAxes (0) scaleLabel labelString) label))
|
||||
|
||||
(define gnc:html-chart-get-options-internal
|
||||
(record-accessor <html-chart> 'chart-options))
|
||||
|
||||
(define gnc:html-chart-set-options-internal!
|
||||
(record-modifier <html-chart> 'chart-options))
|
||||
|
||||
(define (gnc:html-chart-get chart path)
|
||||
(let ((options (gnc:html-chart-get-options-internal chart)))
|
||||
(nested-alist-get options path)))
|
||||
|
||||
(define (gnc:html-chart-set! chart path val)
|
||||
(let ((options (gnc:html-chart-get-options-internal chart))
|
||||
(val-vec (list-to-vec val)))
|
||||
(nested-alist-set! options path val-vec)
|
||||
(gnc:html-chart-set-options-internal! chart options)))
|
||||
|
||||
(define gnc:html-chart-currency-iso
|
||||
(record-accessor <html-chart> 'currency-iso))
|
||||
|
||||
(define gnc:html-chart-set-currency-iso!
|
||||
(record-modifier <html-chart> 'currency-iso))
|
||||
|
||||
(define gnc:html-chart-currency-symbol
|
||||
(record-accessor <html-chart> 'currency-symbol))
|
||||
|
||||
(define gnc:html-chart-set-currency-symbol!
|
||||
(record-modifier <html-chart> 'currency-symbol))
|
||||
|
||||
(define gnc:html-chart-custom-x-axis-ticks?
|
||||
(record-accessor <html-chart> 'custom-x-axis-ticks?))
|
||||
|
||||
(define-public gnc:html-chart-set-custom-x-axis-ticks?!
|
||||
(record-modifier <html-chart> 'custom-x-axis-ticks?))
|
||||
|
||||
(define gnc:html-chart-custom-y-axis-ticks?
|
||||
(record-accessor <html-chart> 'custom-y-axis-ticks?))
|
||||
|
||||
(define-public gnc:html-chart-set-custom-y-axis-ticks?!
|
||||
(record-modifier <html-chart> 'custom-y-axis-ticks?))
|
||||
|
||||
(define JS-Number-to-String "
|
||||
// The following snippet from MDN
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString
|
||||
var toLocaleStringSupportsOptions = (typeof Intl == 'object' && Intl && typeof Intl.NumberFormat == 'function');
|
||||
|
||||
// format a number e.g. 2.5 into monetary e.g. \"$2.50\"
|
||||
function numformat(amount) {
|
||||
if (toLocaleStringSupportsOptions) {
|
||||
return amount.toLocaleString(undefined, {style:'currency', currency:curriso});
|
||||
} else {
|
||||
return currsym + amount.toLocaleString();
|
||||
}
|
||||
}
|
||||
")
|
||||
|
||||
|
||||
(define JS-setup "
|
||||
function tooltipLabel(tooltipItem,data) {
|
||||
var datasetLabel = data.datasets[tooltipItem.datasetIndex].label || 'Other';
|
||||
var label = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
|
||||
switch (typeof(label)) {
|
||||
case 'number':
|
||||
return datasetLabel + ': ' + numformat(label);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
function tooltipTitle(array,data) {
|
||||
return chartjsoptions.data.labels[array[0].index]; }
|
||||
|
||||
// draw the background color
|
||||
Chart.pluginService.register({
|
||||
beforeDraw: function (chart, easing) {
|
||||
if (chart.config.options.chartArea && chart.config.options.chartArea.backgroundColor) {
|
||||
var ctx = chart.chart.ctx;
|
||||
var chartArea = chart.chartArea;
|
||||
ctx.save();
|
||||
ctx.fillStyle = chart.config.options.chartArea.backgroundColor;
|
||||
ctx.fillRect(chartArea.left, chartArea.top, chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById(chartid).onclick = function(evt) {
|
||||
var activepoints = myChart.getElementAtEvent(evt);
|
||||
var anchor = document.getElementById(jumpid);
|
||||
switch (activepoints.length) {
|
||||
case 0:
|
||||
anchor.href = '';
|
||||
anchor.textContent = '';
|
||||
anchor.style = 'display: none';
|
||||
break;
|
||||
default:
|
||||
var index = activepoints[0]['_index'];
|
||||
var datasetIndex = activepoints[0]['_datasetIndex'];
|
||||
var datasetURLs = myChart.data.datasets[datasetIndex].urls;
|
||||
// console.log('index=',index,'datasetIndex=',datasetIndex);
|
||||
anchor.style = 'position:absolute; top:' + (evt.clientY - 30) + 'px; left:' + (evt.clientX - 20) + 'px; display: block; padding: 5px; border-radius: 5px; background: #4E9CAF; text-align:center; color:white; ';
|
||||
switch (typeof(datasetURLs)) {
|
||||
case 'string':
|
||||
anchor.href = datasetURLs;
|
||||
anchor.textContent = loadstring;
|
||||
break;
|
||||
case 'object':
|
||||
anchor.href = datasetURLs[index];
|
||||
anchor.textContent = loadstring;
|
||||
break;
|
||||
default:
|
||||
anchor.href = '';
|
||||
anchor.textContent = '';
|
||||
anchor.style = 'display: none';
|
||||
}
|
||||
}
|
||||
}\n\n")
|
||||
|
||||
(define (get-options-string chart)
|
||||
(scm->json-string
|
||||
(gnc:html-chart-get-options-internal chart)
|
||||
#:pretty #t))
|
||||
|
||||
(define (gnc:html-chart-render chart doc)
|
||||
|
||||
(define (size->str size)
|
||||
(string-append
|
||||
(number->string (cdr size))
|
||||
(case (car size)
|
||||
((pixels) "px")
|
||||
((percent) "%"))))
|
||||
|
||||
(let* ((retval '())
|
||||
(push (lambda (l) (set! retval (cons l retval))))
|
||||
;; Use a unique chart-id for each chart. This prevents charts
|
||||
;; clashing on multi-column reports
|
||||
(id (random 99999999)))
|
||||
|
||||
(push (format #f "<script language='javascript' type='text/javascript' src='file://~a'></script>\n"
|
||||
(gnc-path-find-localized-html-file "chartjs/Chart.bundle.min.js")))
|
||||
|
||||
(push (format #f "<div style='width:~a;height:~a;'>\n"
|
||||
(size->str (gnc:html-chart-width chart))
|
||||
(size->str (gnc:html-chart-height chart))))
|
||||
(push (format #f "<a id='jump-~a' href='' style='display:none'></a>\n" id))
|
||||
(push (format #f "<canvas id='chart-~a'></canvas>\n" id))
|
||||
(push "</div>\n")
|
||||
(push (format #f "<script id='script-~a'>\n" id))
|
||||
(push (format #f "var curriso = ~s;\n" (gnc:html-chart-currency-iso chart)))
|
||||
(push (format #f "var currsym = ~s;\n" (gnc:html-chart-currency-symbol chart)))
|
||||
(push (format #f "var chartid = 'chart-~a';\n" id))
|
||||
(push (format #f "var jumpid = 'jump-~a';\n" id))
|
||||
(push (format #f "var loadstring = ~s;\n" (_ "Load")))
|
||||
(push (format #f "var chartjsoptions = ~a;\n\n"
|
||||
(get-options-string chart)))
|
||||
|
||||
(push JS-Number-to-String)
|
||||
(when (gnc:html-chart-custom-y-axis-ticks? chart)
|
||||
(push "chartjsoptions.options.scales.yAxes[0].ticks.callback = yAxisDisplay;\n")
|
||||
(push "function yAxisDisplay(value,index,values) { return numformat(value); };\n"))
|
||||
(when (gnc:html-chart-custom-x-axis-ticks? chart)
|
||||
(push "chartjsoptions.options.scales.xAxes[0].ticks.callback = xAxisDisplay;\n")
|
||||
(push "function xAxisDisplay(value,index,values) { return chartjsoptions.data.labels[index]; };\n"))
|
||||
|
||||
(push "chartjsoptions.options.tooltips.callbacks.label = tooltipLabel;\n")
|
||||
(push "chartjsoptions.options.tooltips.callbacks.title = tooltipTitle;\n")
|
||||
(push "Chart.defaults.global.defaultFontFamily = \"'Trebuchet MS', Arial, Helvetica, sans-serif\";\n")
|
||||
(push JS-setup)
|
||||
|
||||
(push "var myChart = new Chart(chartid, chartjsoptions);\n")
|
||||
(push "</script>")
|
||||
|
||||
retval))
|
@ -369,6 +369,9 @@
|
||||
((gnc:html-anytag? obj)
|
||||
(gnc:make-html-object-internal gnc:html-anytag-render obj))
|
||||
|
||||
((gnc:html-chart? obj)
|
||||
(gnc:make-html-object-internal gnc:html-chart-render obj))
|
||||
|
||||
((gnc:html-table-cell? obj)
|
||||
(gnc:make-html-object-internal gnc:html-table-cell-render obj))
|
||||
|
||||
|
@ -427,6 +427,7 @@
|
||||
(export gnc:html-linechart-render linechart)
|
||||
(export gnc:html-linechart-set-line-width!)
|
||||
(export gnc:html-linechart-line-width)
|
||||
|
||||
;; html-style-info.scm
|
||||
|
||||
(export <html-markup-style-info>)
|
||||
@ -558,6 +559,27 @@
|
||||
(export gnc-commodity-table)
|
||||
(export gnc:uniform-commodity?)
|
||||
|
||||
;; html-chart.scm
|
||||
|
||||
(export gnc:html-chart?)
|
||||
(export gnc:make-html-chart)
|
||||
(export gnc:html-chart-data)
|
||||
(export gnc:html-chart-set-data!)
|
||||
(export gnc:html-chart-width)
|
||||
(export gnc:html-chart-set-width!)
|
||||
(export gnc:html-chart-height)
|
||||
(export gnc:html-chart-set-height!)
|
||||
(export gnc:html-chart-type)
|
||||
(export gnc:html-chart-set-type!)
|
||||
(export gnc:html-chart-title)
|
||||
(export gnc:html-chart-get)
|
||||
(export gnc:html-chart-set!)
|
||||
(export gnc:html-chart-currency-iso)
|
||||
(export gnc:html-chart-set-currency-iso!)
|
||||
(export gnc:html-chart-currency-symbol)
|
||||
(export gnc:html-chart-set-currency-symbol!)
|
||||
(export gnc:html-chart-render)
|
||||
|
||||
;; html-table.scm
|
||||
|
||||
(export <html-table>)
|
||||
@ -762,6 +784,7 @@
|
||||
|
||||
|
||||
(load-from-path "commodity-utilities")
|
||||
(load-from-path "html-chart")
|
||||
(load-from-path "html-barchart")
|
||||
(load-from-path "html-document")
|
||||
(load-from-path "html-piechart")
|
||||
|
@ -19,6 +19,7 @@ set (scm_test_report_system_with_srfi64_SOURCES
|
||||
test-report-utilities.scm
|
||||
test-html-utilities-srfi64.scm
|
||||
test-html-fonts.scm
|
||||
test-html-chart.scm
|
||||
test-report-html.scm
|
||||
test-report-system.scm
|
||||
)
|
||||
|
111
gnucash/report/report-system/test/test-html-chart.scm
Normal file
111
gnucash/report/report-system/test/test-html-chart.scm
Normal file
@ -0,0 +1,111 @@
|
||||
(use-modules (gnucash gnc-module))
|
||||
|
||||
(gnc:module-begin-syntax (gnc:module-load "gnucash/app-utils" 0))
|
||||
(gnc:module-begin-syntax (gnc:module-load "gnucash/report/report-system" 0))
|
||||
|
||||
(use-modules (srfi srfi-64))
|
||||
(use-modules (tests srfi64-extras))
|
||||
(use-modules (tests test-engine-extras))
|
||||
(use-modules (tests test-report-system-extras))
|
||||
(use-modules (gnucash report report-system))
|
||||
|
||||
(define (run-test)
|
||||
(test-runner-factory gnc:test-runner)
|
||||
(test-begin "test-html-chart.scm")
|
||||
(test-html-chart)
|
||||
(test-end "test-html-chart.scm"))
|
||||
|
||||
|
||||
(define (test-html-chart)
|
||||
|
||||
(let ((chart (gnc:make-html-chart)))
|
||||
|
||||
(gnc:html-chart-add-data-series! chart "label" '(2 3 4) "red")
|
||||
|
||||
;; general setters and getters
|
||||
(gnc:html-chart-set! chart '(data datasets (0) data) #(1 2 3))
|
||||
(test-equal "data setter & getter"
|
||||
#(1 2 3)
|
||||
(gnc:html-chart-get chart '(data datasets (0) data)))
|
||||
|
||||
(gnc:html-chart-set! chart '(type) 'scatter)
|
||||
(test-equal "type setter & getter"
|
||||
'scatter
|
||||
(gnc:html-chart-get chart '(type)))
|
||||
|
||||
;; options setters and getters
|
||||
;;
|
||||
;; options are stored in a nested list of pairs, in which the car
|
||||
;; is a symbol, the cdr is either a value (bool/string/number)
|
||||
;; another list of pairs, or another simple list
|
||||
|
||||
;; (list (cons 'maintainAspectRatio #f)
|
||||
;; (cons 'chartArea (list (cons 'backgroundColor "white")))
|
||||
;; (cons 'scales (list (cons 'xAxes (list
|
||||
;; (list (cons 'display #t)
|
||||
;; (cons 'gridlines (list (cons 'display #t)
|
||||
;; (cons 'lineWidth 1.5)))
|
||||
;; (cons 'ticks (list (cons 'fontSize 12)))))))))
|
||||
|
||||
;; traversal is accomplished as a list of symbols or numbers
|
||||
;; e.g. '(maintainAspectRatio), '(chartArea backgroundColor),
|
||||
;; '(scales xAxes (0) display). NOTE: xAxes specifies a number to
|
||||
;; identify the kth element in the list. this is required as per
|
||||
;; chartjs specification.
|
||||
;;
|
||||
;; syntax is: (gnc:html-chart-set! chart path newval) or
|
||||
;; (gnc:html-chart-get chart path)
|
||||
|
||||
(gnc:html-chart-set! chart '(options maintainAspectRatio) 'abc)
|
||||
(test-equal "root option setter & getter"
|
||||
'abc
|
||||
(gnc:html-chart-get chart '(options maintainAspectRatio)))
|
||||
|
||||
(gnc:html-chart-set! chart '(options legend position) 'de)
|
||||
(test-equal "1st level option setter & getter"
|
||||
'de
|
||||
(gnc:html-chart-get chart '(options legend position)))
|
||||
|
||||
(test-error
|
||||
"1st level option fails - cannot traverse through existing path"
|
||||
'invalid-path
|
||||
(gnc:html-chart-set! chart '(options legend position invalid) 'de))
|
||||
|
||||
(test-equal "deep nested new path - inexistent"
|
||||
#f
|
||||
(gnc:html-chart-get chart '(create new nested path)))
|
||||
|
||||
(gnc:html-chart-set! chart '(create new nested path) 'newpath)
|
||||
(test-equal "created deep nested new path"
|
||||
'newpath
|
||||
(gnc:html-chart-get chart '(create new nested path)))
|
||||
|
||||
(gnc:html-chart-set! chart '(create list-kth (4) nested path) 'k4th)
|
||||
(test-equal "deep nested new path - created 4th list item"
|
||||
'k4th
|
||||
(gnc:html-chart-get chart '(create list-kth (4) nested path)))
|
||||
|
||||
(gnc:html-chart-set! chart '(create list-kth (1) nested path) 'k1th)
|
||||
(test-equal "deep nested new path - created 1th list item"
|
||||
'k1th
|
||||
(gnc:html-chart-get chart '(create list-kth (1) nested path)))
|
||||
|
||||
(gnc:html-chart-set! chart '(create list-kth (0) nested path) 'k0th)
|
||||
(test-equal "deep nested new path - created 0th list item"
|
||||
'k0th
|
||||
(gnc:html-chart-get chart '(create list-kth (0) nested path)))
|
||||
|
||||
(test-equal "deep nested new path - 4th list item intact"
|
||||
'k4th
|
||||
(gnc:html-chart-get chart '(create list-kth (4) nested path)))
|
||||
|
||||
(gnc:html-chart-set! chart '(create list-kth (3)) 'three)
|
||||
(test-equal "deep nested new path - 3th list item is the last path"
|
||||
'three
|
||||
(gnc:html-chart-get chart '(create list-kth (3))))
|
||||
|
||||
(test-error
|
||||
"deep nested new path - cannot set 6th index"
|
||||
'error
|
||||
(gnc:html-chart-set! chart '(create list-kth (6) nested path) 'k4th))
|
||||
))
|
@ -480,6 +480,7 @@ gnucash/report/report-system/gnc-report.c
|
||||
gnucash/report/report-system/html-acct-table.scm
|
||||
gnucash/report/report-system/html-anytag.scm
|
||||
gnucash/report/report-system/html-barchart.scm
|
||||
gnucash/report/report-system/html-chart.scm
|
||||
gnucash/report/report-system/html-document.scm
|
||||
gnucash/report/report-system/html-fonts.scm
|
||||
gnucash/report/report-system/html-linechart.scm
|
||||
|
Loading…
Reference in New Issue
Block a user