Merge branch 'master-jqplot-redirect'

This commit is contained in:
Christopher Lam 2020-01-24 07:13:48 +08:00
commit c77e197570
4 changed files with 293 additions and 852 deletions

View File

@ -43,6 +43,17 @@
button-2-legend-urls button-2-legend-urls
button-3-legend-urls))) button-3-legend-urls)))
(define-syntax-rule (gnc:guard-html-chart api)
;; this macro applied to old html-bar/line/scatter/pie apis will
;; guard a report writer from passing html-chart objects. this
;; should be removed in 5.x series.
(let ((old-api api))
(set! api
(lambda args
(if (and (pair? args) (gnc:html-chart? (car args)))
(gnc:warn "using old-api " (procedure-name api) " on html-chart object. set options via gnc:html-chart-set! or its shortcuts gnc:html-chart-set-title! etc, and set data via gnc:html-chart-add-data-series! see sample-graphs.scm for examples.")
(apply old-api args))))))
(define gnc:html-barchart? (define gnc:html-barchart?
(record-predicate <html-barchart>)) (record-predicate <html-barchart>))
@ -55,6 +66,8 @@
(record-constructor <html-barchart>)) (record-constructor <html-barchart>))
(define (gnc:make-html-barchart) (define (gnc:make-html-barchart)
(issue-deprecation-warning
"(gnc:make-html-barchart) is deprecated. use gnc:make-html-chart instead.")
(gnc:make-html-barchart-internal '(pixels . -1) '(pixels . -1) #f #f #f #f '() '() '() (gnc:make-html-barchart-internal '(pixels . -1) '(pixels . -1) #f #f #f #f '() '() '()
#f #f #f '() #f #f #f #f #f #f)) #f #f #f '() #f #f #f #f #f #f))
@ -272,308 +285,70 @@
newcol))) newcol)))
(define (gnc:html-barchart-render barchart doc) (define (gnc:html-barchart-render barchart doc)
(define (ensure-numeric elt) (let* ((chart (gnc:make-html-chart))
(cond ((number? elt) (data (gnc:html-barchart-data barchart)))
(exact->inexact elt)) (cond
((string? elt) ((and (pair? data) (gnc:not-all-zeros data))
(with-input-from-string elt (gnc:html-chart-set-type! chart 'bar)
(lambda () (gnc:html-chart-set-width! chart (gnc:html-barchart-width barchart))
(let ((n (read))) (gnc:html-chart-set-height! chart (gnc:html-barchart-height barchart))
(if (number? n) n 0.0))))) (gnc:html-chart-set-data-labels! chart (gnc:html-barchart-row-labels barchart))
(#t (for-each
0.0))) (lambda (label series color)
(gnc:html-chart-add-data-series! chart label series color))
(gnc:html-barchart-col-labels barchart)
data
(gnc:html-barchart-col-colors barchart))
(gnc:html-chart-set-title! chart (list
(gnc:html-barchart-title barchart)
(gnc:html-barchart-subtitle barchart)))
(gnc:html-chart-set-stacking?! chart (gnc:html-barchart-stacked? barchart))
(gnc:html-chart-render chart doc))
(define (catenate-escaped-strings nlist) (else
(if (not (list? nlist)) (gnc:warn "null-data, not rendering barchart")
"" ""))))
(with-output-to-string
(lambda ()
(for-each
(lambda (s)
(let ((escaped
(regexp-substitute/global
#f " "
(regexp-substitute/global
#f "\\\\" s
'pre "\\\\" 'post)
'pre "\\ " 'post)))
(display escaped)
(display " ")))
nlist)))))
(let* ((retval '()) (gnc:guard-html-chart gnc:html-barchart-data)
(push (lambda (l) (set! retval (cons l retval)))) (gnc:guard-html-chart gnc:html-barchart-set-data!)
(title (gnc:html-barchart-title barchart)) (gnc:guard-html-chart gnc:html-barchart-width)
(subtitle (gnc:html-barchart-subtitle barchart)) (gnc:guard-html-chart gnc:html-barchart-set-width!)
(url-1 (gnc:guard-html-chart gnc:html-barchart-height)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-set-height!)
(gnc:html-barchart-button-1-bar-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-x-axis-label)
(url-2 (gnc:guard-html-chart gnc:html-barchart-set-x-axis-label!)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-y-axis-label)
(gnc:html-barchart-button-2-bar-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-set-y-axis-label!)
(url-3 (gnc:guard-html-chart gnc:html-barchart-row-labels)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-set-row-labels!)
(gnc:html-barchart-button-3-bar-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-row-labels-rotated?)
(legend-1 (gnc:guard-html-chart gnc:html-barchart-set-row-labels-rotated?!)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-stacked?)
(gnc:html-barchart-button-1-legend-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-set-stacked?!)
(legend-2 (gnc:guard-html-chart gnc:html-barchart-col-labels)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-set-col-labels!)
(gnc:html-barchart-button-2-legend-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-col-colors)
(legend-3 (gnc:guard-html-chart gnc:html-barchart-set-col-colors!)
(catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-legend-reversed?)
(gnc:html-barchart-button-3-legend-urls barchart))) (gnc:guard-html-chart gnc:html-barchart-set-legend-reversed?!)
(x-label (gnc:html-barchart-x-axis-label barchart)) (gnc:guard-html-chart gnc:html-barchart-title)
(y-label (gnc:html-barchart-y-axis-label barchart)) (gnc:guard-html-chart gnc:html-barchart-set-title!)
(data (gnc:html-barchart-data barchart)) (gnc:guard-html-chart gnc:html-barchart-subtitle)
(dummy1 (gnc:debug "data " data)) (gnc:guard-html-chart gnc:html-barchart-set-subtitle!)
(row-labels (catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-button-1-bar-urls)
(gnc:html-barchart-row-labels barchart))) (gnc:guard-html-chart gnc:html-barchart-set-button-1-bar-urls!)
(col-labels (catenate-escaped-strings (gnc:guard-html-chart gnc:html-barchart-button-2-bar-urls)
(gnc:html-barchart-col-labels barchart))) (gnc:guard-html-chart gnc:html-barchart-set-button-2-bar-urls!)
;; convert color list to string with valid js array of strings, example: "\"blue\", \"red\"" (gnc:guard-html-chart gnc:html-barchart-button-3-bar-urls)
(colors-str (string-join (map (lambda (color) (gnc:guard-html-chart gnc:html-barchart-set-button-3-bar-urls!)
(string-append "\"" color "\"")) (gnc:guard-html-chart gnc:html-barchart-button-1-legend-urls)
(gnc:html-barchart-col-colors barchart)) ", ")) (gnc:guard-html-chart gnc:html-barchart-set-button-1-legend-urls!)
(series-data-start (lambda (series-index) (gnc:guard-html-chart gnc:html-barchart-button-2-legend-urls)
(push "var d") (gnc:guard-html-chart gnc:html-barchart-set-button-2-legend-urls!)
(push series-index) (gnc:guard-html-chart gnc:html-barchart-button-3-legend-urls)
(push " = [];\n"))) (gnc:guard-html-chart gnc:html-barchart-set-button-3-legend-urls!)
(series-data-add (lambda (series-index x y) (gnc:guard-html-chart gnc:html-barchart-append-row!)
(push (string-append (gnc:guard-html-chart gnc:html-barchart-prepend-row!)
" d" (gnc:guard-html-chart gnc:html-barchart-append-column!)
(number->string series-index) (gnc:guard-html-chart gnc:html-barchart-prepend-column!)
".push([" (gnc:guard-html-chart gnc:html-barchart-render)
(number->string x)
", "
(number->string y)
"]);\n"))))
(series-data-end (lambda (series-index label)
(push "data.push(d")
(push series-index)
(push ");\n")
(push (format #f "series.push({ label: ~s });\n\n"
(gnc:html-string-sanitize label)))
))
; Use a unique chart-id for each chart. This prevents chart
; clashed on multi-column reports
(chart-id (string-append "chart-" (number->string (random 999999)))))
(if (and (list? data)
(not (null? data))
(gnc:not-all-zeros data))
(begin
(push (gnc:html-js-include "jqplot/jquery.min.js"))
(push (gnc:html-js-include "jqplot/jquery.jqplot.js"))
(push (gnc:html-js-include "jqplot/jqplot.barRenderer.js"))
(push (gnc:html-js-include "jqplot/jqplot.cursor.js"))
(push (gnc:html-js-include "jqplot/jqplot.categoryAxisRenderer.js"))
(push (gnc:html-js-include "jqplot/jqplot.highlighter.js"))
(push (gnc:html-js-include "jqplot/jqplot.canvasTextRenderer.js"))
(push (gnc:html-js-include "jqplot/jqplot.canvasAxisTickRenderer.js"))
(push (gnc:html-css-include "jqplot/jquery.jqplot.css"))
(push "<div id=\"")(push chart-id)(push "\" style=\"width:")
(push (cdr (gnc:html-barchart-width barchart)))
(if (eq? 'pixels (car (gnc:html-barchart-width barchart)))
(push "px;height:")
(push "%;height:"))
(push (cdr (gnc:html-barchart-height barchart)))
(if (eq? 'pixels (car (gnc:html-barchart-height barchart)))
(push "px;\"></div>\n")
(push "%;\"></div>\n"))
(push "<script id=\"source\">\n$(function () {")
(push "var data = [];")
(push "var series = [];\n")
(if (and data (list? data))
(let ((rows (length data))
(cols 0))
(let loop ((col 0) (rowcnt 1))
(series-data-start col)
(if (list? (car data))
(begin
(set! cols (length (car data)))))
(for-each
(lambda (row)
(if (<= rowcnt rows)
(series-data-add col rowcnt
(ensure-numeric (list-ref-safe row col)))
)
(set! rowcnt (+ rowcnt 1)))
data)
(series-data-end col (list-ref-safe (gnc:html-barchart-col-labels barchart) col))
(if (< col (- cols 1))
(loop (+ 1 col) 1)))))
(push "var all_ticks = [")
(for-each
(lambda (val)
(push "\"")
(push val)
(push "\","))
(gnc:html-barchart-row-labels barchart))
(push "];\n")
(push "var options = {
shadowAlpha: 0.07,
stackSeries: false,
legend: {
show: true,
placement: \"outsideGrid\", },
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
rendererOptions: {
shadowAlpha: 0.04,
shadowDepth: 3,
},
fillToZero: true,
},
series: series,
axesDefaults: {
},
grid: {
},
axes: {
xaxis: {
renderer:$.jqplot.CategoryAxisRenderer,
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: {
angle: -30,
fontSize: '10pt',
},
},
yaxis: {
autoscale: true,
},
},
highlighter: {
tooltipContentEditor: formatTooltip,
},
cursor:{
show: true,
showTooltip: false,
zoom: true,
},
seriesColors: false,
};\n")
(push " options.stackSeries = ")
(push (if (gnc:html-barchart-stacked? barchart)
"true;\n"
"false;\n"))
(if title
(push (format #f " options.title = ~s;\n"
(gnc:html-string-sanitize title))))
(if subtitle
(push (format #f " options.title += ' <br />' + ~s;\n"
(gnc:html-string-sanitize subtitle))))
(if (and (string? x-label) (> (string-length x-label) 0))
(begin
(push " options.axes.xaxis.label = \"")
(push x-label)
(push "\";\n")))
(if (and (string? y-label) (> (string-length y-label) 0))
(begin
(push " options.axes.yaxis.label = \"")
(push y-label)
(push "\";\n")))
(push " options.axes.xaxis.ticks = all_ticks;\n")
(if (not (equal? colors-str ""))
(begin ; example: options.seriesColors= ["blue", "red"];
(push "options.seriesColors = [")
(push colors-str)
(push "];\n")
(push "options.negativeSeriesColors = [")
(push colors-str)
(push "];\n")
)
)
(push "$.jqplot.config.enablePlugins = true;\n")
(push "$(document).ready(function() {
var plot = $.jqplot('")(push chart-id)(push"', data, options);
plot.axes.xaxis.ticks = getVisualTicks();
plot.replot();
var timer;
var load_timer;
// var win_width = $(window).width();
// var win_height = $(window).height();
// console.log( 'Window Width ' + win_width + ' Height ' + win_height);
// var doc_width = document.body.clientWidth;
// var doc_height = document.body.clientHeight;
// console.log( 'Doc Width ' + doc_width + ' Height ' + doc_height);
$(window).resize(function () {
clearTimeout(timer);
timer = setTimeout(function () {
plot.replot({resetAxes: true });
$.each(plot.series, function(index, series) {
series.barWidth = undefined;
});
plot.axes.xaxis.ticks = getVisualTicks();
// console.log( 'Resize Timer!' );
plot.replot();
}, 100);
});
$(window).on('load', function () {
var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
clearTimeout(load_timer);
load_timer = setTimeout(function () {
// console.log( 'Load Timer!' );
if(hasVScroll)
{
// console.log( 'Load Timer Replot!' );
plot.replot();
}
},100);
});
});
function formatTooltip(str, seriesIndex, pointIndex) {
if (options.axes.xaxis.ticks[pointIndex] !== undefined)
x = options.axes.xaxis.ticks[pointIndex];
else
x = pointIndex;
y = data[seriesIndex][pointIndex][1].toFixed(2);
return options.series[seriesIndex].label + '<br/>' + x + '<br/><b>' + y + '</b>';
}
function getVisualTicks() {
var chart_width = document.getElementById(\"")(push chart-id)(push"\").getElementsByClassName(\"jqplot-zoom-canvas\")[0].width;
var num_ticks = all_ticks.length;
var label_width = 25;
var num_labels = chart_width / label_width;
var show_every_nth_label = Math.ceil (num_ticks / num_labels);
var visual_ticks = [];
if (show_every_nth_label == 0)
show_every_nth_label = 1;
for (counter = 0; counter < all_ticks.length; counter++) {
if ((counter % show_every_nth_label) == 0)
visual_ticks.push (all_ticks[counter]);
else
visual_ticks.push (' ');
}
// console.log( 'getVis chart_width ' + chart_width );
return visual_ticks;
}\n")
(push "});\n</script>")
(gnc:msg (string-join (reverse (map (lambda (e) (if (number? e) (number->string e) e)) retval)) ""))
)
(begin
(gnc:warn "barchart has no non-zero data.")
" "))
retval))

View File

@ -50,6 +50,17 @@
button-3-legend-urls button-3-legend-urls
line-width))) line-width)))
(define-syntax-rule (gnc:guard-html-chart api)
;; this macro applied to old html-bar/line/scatter/pie apis will
;; guard a report writer from passing html-chart objects. this
;; should be removed in 5.x series.
(let ((old-api api))
(set! api
(lambda args
(if (and (pair? args) (gnc:html-chart? (car args)))
(gnc:warn "using old-api " (procedure-name api) " on html-chart object. set options via gnc:html-chart-set! or its shortcuts gnc:html-chart-set-title! etc, and set data via gnc:html-chart-add-data-series! see sample-graphs.scm for examples.")
(apply old-api args))))))
(define gnc:html-linechart? (define gnc:html-linechart?
(record-predicate <html-linechart>)) (record-predicate <html-linechart>))
@ -62,6 +73,8 @@
(record-constructor <html-linechart>)) (record-constructor <html-linechart>))
(define (gnc:make-html-linechart) (define (gnc:make-html-linechart)
(issue-deprecation-warning
"(gnc:make-html-linechart) is deprecated. use gnc:make-html-chart instead.")
(gnc:make-html-linechart-internal (gnc:make-html-linechart-internal
'(pixels . -1) ;;width '(pixels . -1) ;;width
'(pixels . -1) ;;height '(pixels . -1) ;;height
@ -327,284 +340,84 @@
newcol))) newcol)))
(define (gnc:html-linechart-render linechart doc) (define (gnc:html-linechart-render linechart doc)
(define (ensure-numeric elt) (let* ((chart (gnc:make-html-chart))
(cond ((number? elt)
(exact->inexact elt))
((string? elt)
(with-input-from-string elt
(lambda ()
(let ((n (read)))
(if (number? n) n 0.0)))))
(#t
0.0)))
(define (catenate-escaped-strings nlist)
(if (not (list? nlist))
""
(with-output-to-string
(lambda ()
(for-each
(lambda (s)
(let ((escaped
(regexp-substitute/global
#f " "
(regexp-substitute/global
#f "\\\\" s
'pre "\\\\" 'post)
'pre "\\ " 'post)))
(display escaped)
(display " ")))
nlist)))))
(let* ((retval '())
(push (lambda (l) (set! retval (cons l retval))))
(title (gnc:html-linechart-title linechart))
(subtitle (gnc:html-linechart-subtitle linechart))
(url-1
(catenate-escaped-strings
(gnc:html-linechart-button-1-line-urls linechart)))
(url-2
(catenate-escaped-strings
(gnc:html-linechart-button-2-line-urls linechart)))
(url-3
(catenate-escaped-strings
(gnc:html-linechart-button-3-line-urls linechart)))
(legend-1
(catenate-escaped-strings
(gnc:html-linechart-button-1-legend-urls linechart)))
(legend-2
(catenate-escaped-strings
(gnc:html-linechart-button-2-legend-urls linechart)))
(legend-3
(catenate-escaped-strings
(gnc:html-linechart-button-3-legend-urls linechart)))
(x-label (gnc:html-linechart-x-axis-label linechart))
(y-label (gnc:html-linechart-y-axis-label linechart))
(data (gnc:html-linechart-data linechart)) (data (gnc:html-linechart-data linechart))
(dummy1 (gnc:debug "data " data))
(row-labels (catenate-escaped-strings
(gnc:html-linechart-row-labels linechart)))
(col-labels (catenate-escaped-strings
(gnc:html-linechart-col-labels linechart)))
;; convert color list to string with valid js array of strings, example: "\"blue\", \"red\""
(colors-str (string-join (map (lambda (color)
(string-append "\"" color "\""))
(gnc:html-linechart-col-colors linechart)) ", "))
(line-width (gnc:html-linechart-line-width linechart)) (line-width (gnc:html-linechart-line-width linechart))
(series-data-start (lambda (series-index) (radius (if (gnc:html-linechart-markers? linechart) 3 0)))
(push "var d") (cond
(push series-index) ((and (pair? data) (gnc:not-all-zeros data))
(push " = [];\n"))) (gnc:html-chart-set-type! chart 'line)
(series-data-add (lambda (series-index date y) (gnc:html-chart-set-width! chart (gnc:html-linechart-width linechart))
(push (string-append (gnc:html-chart-set-height! chart (gnc:html-linechart-height linechart))
" d" (gnc:html-chart-set-data-labels! chart (gnc:html-linechart-row-labels linechart))
(number->string series-index) (for-each
".push([" (lambda (label series color)
"\"" date "\"" (gnc:html-chart-add-data-series! chart label series color
", " 'borderWidth line-width
(number->string y) 'pointRadius radius
"]);\n")))) 'fill #f))
(series-data-end (lambda (series-index label) (gnc:html-linechart-col-labels linechart)
(push "data.push(d") (apply zip data)
(push series-index) (gnc:html-linechart-col-colors linechart))
(push ");\n") (gnc:html-chart-set-title! chart (list
(push (format #f "series.push({ label: ~s });\n\n" (gnc:html-linechart-title linechart)
(gnc:html-string-sanitize label))))) (gnc:html-linechart-subtitle linechart)))
; Use a unique chart-id for each chart. This prevents chart (gnc:html-chart-set-stacking?! chart (gnc:html-linechart-stacked? linechart))
; clashed on multi-column reports (gnc:html-chart-render chart doc))
(chart-id (string-append "chart-" (number->string (random 999999)))))
(if (and (list? data)
(not (null? data))
(gnc:not-all-zeros data))
(begin
(push (gnc:html-js-include "jqplot/jquery.min.js"))
(push (gnc:html-js-include "jqplot/jquery.jqplot.js"))
(push (gnc:html-js-include "jqplot/jqplot.cursor.js"))
(push (gnc:html-js-include "jqplot/jqplot.dateAxisRenderer.js"))
(push (gnc:html-js-include "jqplot/jqplot.highlighter.js"))
(push (gnc:html-js-include "jqplot/jqplot.canvasTextRenderer.js"))
(push (gnc:html-js-include "jqplot/jqplot.canvasAxisTickRenderer.js"))
(push (gnc:html-css-include "jqplot/jquery.jqplot.css"))
(push "<div id=\"")(push chart-id)(push "\" style=\"width:") (else
(push (cdr (gnc:html-linechart-width linechart))) (gnc:warn "null-data, not rendering linechart")
(if (eq? 'pixels (car (gnc:html-linechart-width linechart))) ""))))
(push "px;height:")
(push "%;height:"))
(push (cdr (gnc:html-linechart-height linechart)))
(if (eq? 'pixels (car (gnc:html-linechart-height linechart)))
(push "px;\"></div>\n")
(push "%;\"></div>\n"))
(push "<script id=\"source\">\n$(function () {")
(push "var data = [];")
(push "var series = [];\n")
(if (and data (list? data))
(let ((rows (length data))
(cols 0))
(let loop ((col 0) (rowcnt 0))
(series-data-start col)
(if (list? (car data))
(begin
(set! cols (length (car data)))))
(for-each
(lambda (row)
(if (< rowcnt rows)
(series-data-add col
(list-ref (gnc:html-linechart-row-labels linechart) rowcnt)
(ensure-numeric (list-ref-safe row col))
)
)
(set! rowcnt (+ rowcnt 1)))
data)
(series-data-end col (list-ref-safe (gnc:html-linechart-col-labels linechart) col))
(if (< col (- cols 1))
(loop (+ 1 col) 0)))))
(push "var options = { (gnc:guard-html-chart gnc:html-linechart-data)
shadowAlpha: 0.07, (gnc:guard-html-chart gnc:html-linechart-set-data!)
legend: { (gnc:guard-html-chart gnc:html-linechart-width)
show: true, (gnc:guard-html-chart gnc:html-linechart-set-width!)
placement: \"outsideGrid\", }, (gnc:guard-html-chart gnc:html-linechart-height)
seriesDefaults: { (gnc:guard-html-chart gnc:html-linechart-set-height!)
lineWidth: ") (gnc:guard-html-chart gnc:html-linechart-x-axis-label)
(push (ensure-numeric line-width)) (gnc:guard-html-chart gnc:html-linechart-set-x-axis-label!)
(push ", (gnc:guard-html-chart gnc:html-linechart-y-axis-label)
showMarker: true, (gnc:guard-html-chart gnc:html-linechart-set-y-axis-label!)
}, (gnc:guard-html-chart gnc:html-linechart-row-labels)
series: series, (gnc:guard-html-chart gnc:html-linechart-set-row-labels!)
axesDefaults: { (gnc:guard-html-chart gnc:html-linechart-row-labels-rotated?)
}, (gnc:guard-html-chart gnc:html-linechart-set-row-labels-rotated?!)
grid: { (gnc:guard-html-chart gnc:html-linechart-stacked?)
}, (gnc:guard-html-chart gnc:html-linechart-set-stacked?!)
axes: { (gnc:guard-html-chart gnc:html-linechart-markers?)
xaxis: { (gnc:guard-html-chart gnc:html-linechart-set-markers?!)
renderer:$.jqplot.DateAxisRenderer, (gnc:guard-html-chart gnc:html-linechart-major-grid?)
tickRenderer: $.jqplot.CanvasAxisTickRenderer, (gnc:guard-html-chart gnc:html-linechart-set-major-grid?!)
tickOptions: { (gnc:guard-html-chart gnc:html-linechart-minor-grid?)
angle: -30, (gnc:guard-html-chart gnc:html-linechart-set-minor-grid?!)
fontSize: '10pt', (gnc:guard-html-chart gnc:html-linechart-col-labels)
}, (gnc:guard-html-chart gnc:html-linechart-set-col-labels!)
}, (gnc:guard-html-chart gnc:html-linechart-col-colors)
yaxis: { (gnc:guard-html-chart gnc:html-linechart-set-col-colors!)
autoscale: true, (gnc:guard-html-chart gnc:html-linechart-legend-reversed?)
}, (gnc:guard-html-chart gnc:html-linechart-set-legend-reversed?!)
}, (gnc:guard-html-chart gnc:html-linechart-title)
highlighter: { (gnc:guard-html-chart gnc:html-linechart-set-title!)
tooltipContentEditor: formatTooltip, (gnc:guard-html-chart gnc:html-linechart-subtitle)
tooltipLocation: 'ne', (gnc:guard-html-chart gnc:html-linechart-set-subtitle!)
}, (gnc:guard-html-chart gnc:html-linechart-button-1-line-urls)
cursor: { (gnc:guard-html-chart gnc:html-linechart-set-button-1-line-urls!)
show: true, (gnc:guard-html-chart gnc:html-linechart-button-2-line-urls)
zoom: true (gnc:guard-html-chart gnc:html-linechart-set-button-2-line-urls!)
}, (gnc:guard-html-chart gnc:html-linechart-button-3-line-urls)
seriesColors: false, (gnc:guard-html-chart gnc:html-linechart-set-button-3-line-urls!)
};\n") (gnc:guard-html-chart gnc:html-linechart-button-1-legend-urls)
(gnc:guard-html-chart gnc:html-linechart-set-button-1-legend-urls!)
(push " options.stackSeries = ") (gnc:guard-html-chart gnc:html-linechart-button-2-legend-urls)
(push (if (gnc:html-linechart-stacked? linechart) (gnc:guard-html-chart gnc:html-linechart-set-button-2-legend-urls!)
"true;\n" (gnc:guard-html-chart gnc:html-linechart-button-3-legend-urls)
"false;\n")) (gnc:guard-html-chart gnc:html-linechart-set-button-3-legend-urls!)
(gnc:guard-html-chart gnc:html-linechart-append-row!)
(push " options.seriesDefaults.showMarker = ") (gnc:guard-html-chart gnc:html-linechart-prepend-row!)
(push (if (gnc:html-linechart-markers? linechart) (gnc:guard-html-chart gnc:html-linechart-append-column!)
"true;\n" (gnc:guard-html-chart gnc:html-linechart-prepend-column!)
"false;\n")) (gnc:guard-html-chart gnc:html-linechart-render)
(gnc:guard-html-chart gnc:html-linechart-set-line-width!)
(push " options.axesDefaults.drawMajorGridlines = ") (gnc:guard-html-chart gnc:html-linechart-line-width)
(push (if (gnc:html-linechart-major-grid? linechart)
"true;\n"
"false;\n"))
(push " options.axesDefaults.drawMinorGridlines = ")
(push (if (gnc:html-linechart-minor-grid? linechart)
"true;\n"
"false;\n"))
(if title
(push (format #f " options.title = ~s;\n"
(gnc:html-string-sanitize title))))
(if subtitle
(push (format #f " options.title += ' <br />' + ~s;\n"
(gnc:html-string-sanitize subtitle))))
(if (and (string? x-label) (> (string-length x-label) 0))
(begin
(push " options.axes.xaxis.label = \"")
(push x-label)
(push "\";\n")))
(if (and (string? y-label) (> (string-length y-label) 0))
(begin
(push " options.axes.yaxis.label = \"")
(push y-label)
(push "\";\n")))
(if (not (equal? colors-str ""))
(begin ; example: options.seriesColors= ["blue", "red"];
(push "options.seriesColors = [")
(push colors-str)
(push "];\n")
)
)
;; adjust the date string format to the one given by the preferences
(push " options.axes.xaxis.tickOptions.formatString = '")
(push (qof-date-format-get-string (qof-date-format-get)))
(push "';\n")
(push "$.jqplot.config.enablePlugins = true;\n")
(push "$(document).ready(function() {
var plot = $.jqplot('")(push chart-id)(push"', data, options);
plot.replot();
var timer;
var load_timer;
// var win_width = $(window).width();
// var win_height = $(window).height();
// console.log( 'Window Width ' + win_width + ' Height ' + win_height);
// var doc_width = document.body.clientWidth;
// var doc_height = document.body.clientHeight;
// console.log( 'Doc Width ' + doc_width + ' Height ' + doc_height);
$(window).resize(function () {
clearTimeout(timer);
timer = setTimeout(function () {
// console.log( 'Resize Timer!' );
plot.replot();
}, 100);
});
$(window).on('load', function () {
var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
clearTimeout(load_timer);
load_timer = setTimeout(function () {
// console.log( 'Load Timer!' );
if(hasVScroll)
{
// console.log( 'Load Timer Replot!' );
plot.replot();
}
},100);
});
});
function formatTooltip(str, seriesIndex, pointIndex) {
x = $.jqplot.DateTickFormatter (options.axes.xaxis.tickOptions.formatString,
data[seriesIndex][pointIndex][0]);
y = data[seriesIndex][pointIndex][1].toFixed(2);
return options.series[seriesIndex].label + ' ' + x + '<br><b>' + y + '</b>';
}\n")
(push "});\n</script>")
(gnc:msg (string-join (reverse (map (lambda (e) (if (number? e) (number->string e) e)) retval)) ""))
)
(begin
(gnc:warn "linechart has no non-zero data.")
" "))
retval))

View File

@ -41,6 +41,16 @@
(define gnc:html-piechart? (define gnc:html-piechart?
(record-predicate <html-piechart>)) (record-predicate <html-piechart>))
(define-syntax-rule (gnc:guard-html-chart api)
;; this macro applied to old html-bar/line/scatter/pie apis will
;; guard a report writer from passing html-chart objects. this
;; should be removed in 5.x series.
(let ((old-api api))
(set! api
(lambda args
(if (and (pair? args) (gnc:html-chart? (car args)))
(gnc:warn "using old-api " (procedure-name api) " on html-chart object. set options via gnc:html-chart-set! or its shortcuts gnc:html-chart-set-title! etc, and set data via gnc:html-chart-add-data-series! see sample-graphs.scm for examples.")
(apply old-api args))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; <html-piechart> class ;; <html-piechart> class
@ -51,6 +61,8 @@
(record-constructor <html-piechart>)) (record-constructor <html-piechart>))
(define (gnc:make-html-piechart) (define (gnc:make-html-piechart)
(issue-deprecation-warning
"(gnc:make-html-piechart) is deprecated. use gnc:make-html-chart instead.")
(gnc:make-html-piechart-internal '(pixels . -1) '(pixels . -1) #f #f #f #f #f #f #f #f #f #f #f)) (gnc:make-html-piechart-internal '(pixels . -1) '(pixels . -1) #f #f #f #f #f #f #f #f #f #f #f))
(define gnc:html-piechart-data (define gnc:html-piechart-data
@ -140,153 +152,50 @@
(record-modifier <html-piechart> 'button-3-legend-urls)) (record-modifier <html-piechart> 'button-3-legend-urls))
(define (gnc:html-piechart-render piechart doc) (define (gnc:html-piechart-render piechart doc)
(define (ensure-positive-numbers nlist) (let* ((chart (gnc:make-html-chart))
(map
(lambda (elt)
(cond ((number? elt)
(exact->inexact (abs elt)))
((string? elt)
(with-input-from-string elt
(lambda ()
(let ((n (read)))
(if (number? n) (abs n) 0.0)))))
(#t
0.0)))
nlist))
(define (catenate-escaped-strings nlist)
(if (not (list? nlist))
""
(with-output-to-string
(lambda ()
(for-each
(lambda (s)
(let ((escaped
(regexp-substitute/global
#f " "
(regexp-substitute/global
#f "\\\\" s
'pre "\\\\" 'post)
'pre "\\ " 'post)))
(display escaped)
(display " ")))
nlist)))))
(let* ((retval '())
(push (lambda (l) (set! retval (cons l retval))))
(title (gnc:html-piechart-title piechart)) (title (gnc:html-piechart-title piechart))
(subtitle (gnc:html-piechart-subtitle piechart)) (subtitle (gnc:html-piechart-subtitle piechart))
(url-1 (data (gnc:html-piechart-data piechart))
(catenate-escaped-strings (colors (gnc:html-piechart-colors piechart)))
(gnc:html-piechart-button-1-slice-urls piechart))) (cond
(url-2 ((and (pair? data) (gnc:not-all-zeros data))
(catenate-escaped-strings (gnc:html-chart-set-type! chart 'pie)
(gnc:html-piechart-button-2-slice-urls piechart))) (gnc:html-chart-set-axes-display! chart #f)
(url-3 (gnc:html-chart-set-width! chart (gnc:html-piechart-width piechart))
(catenate-escaped-strings (gnc:html-chart-set-height! chart (gnc:html-piechart-height piechart))
(gnc:html-piechart-button-3-slice-urls piechart))) (gnc:html-chart-set-data-labels! chart (gnc:html-piechart-labels piechart))
(legend-1 (gnc:html-chart-add-data-series! chart "" data colors)
(catenate-escaped-strings (gnc:html-chart-set-title! chart (list title subtitle))
(gnc:html-piechart-button-1-legend-urls piechart))) (gnc:html-chart-render chart doc))
(legend-2
(catenate-escaped-strings
(gnc:html-piechart-button-2-legend-urls piechart)))
(legend-3
(catenate-escaped-strings
(gnc:html-piechart-button-3-legend-urls piechart)))
(data
(ensure-positive-numbers (gnc:html-piechart-data piechart)))
;; convert color list to string with valid js array of strings, example: "\"blue\", \"red\""
(colors-str (string-join (map (lambda (color)
(string-append "\"" color "\""))
(gnc:html-piechart-colors piechart)) ", "))
; Use a unique chart-id for each chart. This prevents chart
; clashed on multi-column reports
(chart-id (string-append "chart-" (number->string (random 999999)))))
(if (and (list? data)
(not (null? data)))
(begin
(push (gnc:html-js-include "jqplot/jquery.min.js"))
(push (gnc:html-js-include "jqplot/jquery.jqplot.js"))
(push (gnc:html-js-include "jqplot/jqplot.pieRenderer.js"))
(push (gnc:html-css-include "jqplot/jquery.jqplot.css"))
(push "<div id=\"")(push chart-id)(push "\" style=\"width:") (else
(push (cdr (gnc:html-piechart-width piechart))) (gnc:warn "null-data, not rendering piechart")
(if (eq? 'pixels (car (gnc:html-piechart-width piechart))) ""))))
(push "px;height:")
(push "%;height:"))
(push (cdr (gnc:html-piechart-height piechart))) (gnc:guard-html-chart gnc:html-piechart-data)
(if (eq? 'pixels (car (gnc:html-piechart-height piechart))) (gnc:guard-html-chart gnc:html-piechart-set-data!)
(push "px;\"></div>\n") (gnc:guard-html-chart gnc:html-piechart-width)
(push "%;\"></div>\n")) (gnc:guard-html-chart gnc:html-piechart-set-width!)
(push "<script id=\"source\">\n$(function () {") (gnc:guard-html-chart gnc:html-piechart-height)
(gnc:guard-html-chart gnc:html-piechart-set-height!)
(push "var data = [];\n") (gnc:guard-html-chart gnc:html-piechart-labels)
(gnc:guard-html-chart gnc:html-piechart-set-labels!)
(if (and data (list? data)) (gnc:guard-html-chart gnc:html-piechart-colors)
(begin (gnc:guard-html-chart gnc:html-piechart-set-colors!)
(for-each (gnc:guard-html-chart gnc:html-piechart-title)
(lambda (datum label) (gnc:guard-html-chart gnc:html-piechart-set-title!)
(push (format #f " data.push([~s,~a]);\n" (gnc:guard-html-chart gnc:html-piechart-subtitle)
(gnc:html-string-sanitize label) (gnc:guard-html-chart gnc:html-piechart-set-subtitle!)
datum))) (gnc:guard-html-chart gnc:html-piechart-button-1-slice-urls)
data (gnc:html-piechart-labels piechart)))) (gnc:guard-html-chart gnc:html-piechart-set-button-1-slice-urls!)
(gnc:guard-html-chart gnc:html-piechart-button-2-slice-urls)
(push "var options = { (gnc:guard-html-chart gnc:html-piechart-set-button-2-slice-urls!)
seriesDefaults: { (gnc:guard-html-chart gnc:html-piechart-button-3-slice-urls)
renderer: $.jqplot.PieRenderer, (gnc:guard-html-chart gnc:html-piechart-set-button-3-slice-urls!)
}, (gnc:guard-html-chart gnc:html-piechart-button-1-legend-urls)
legend: { (gnc:guard-html-chart gnc:html-piechart-set-button-1-legend-urls!)
show: true, (gnc:guard-html-chart gnc:html-piechart-button-2-legend-urls)
placement: \"outsideGrid\", }, (gnc:guard-html-chart gnc:html-piechart-set-button-2-legend-urls!)
highlighter: { (gnc:guard-html-chart gnc:html-piechart-button-3-legend-urls)
show: false }, (gnc:guard-html-chart gnc:html-piechart-set-button-3-legend-urls!)
cursor: { (gnc:guard-html-chart gnc:html-piechart-render)
showTooltip: false },
seriesColors: false,
};\n")
(if title
(push (format #f " options.title = ~s;\n"
(gnc:html-string-sanitize title))))
(if subtitle
(push (format #f " options.title += ' (' + ~s + ')';\n"
(gnc:html-string-sanitize subtitle))))
(if (not (equal? colors-str ""))
(begin ; example: options.seriesColors= ["blue", "red"];
(push "options.seriesColors = [")
(push colors-str)
(push "];\n")
)
)
(push "$.jqplot.config.enablePlugins = true;\n")
(push "$(document).ready(function() {
var plot = $.jqplot('")(push chart-id)(push "', [data], options);
plot.replot();
var timer;
// var win_width = $(window).width();
// var win_height = $(window).height();
// console.log( 'Window Width ' + win_width + ' Height ' + win_height);
// var doc_width = document.body.clientWidth;
// var doc_height = document.body.clientHeight;
// console.log( 'Doc Width ' + doc_width + ' Height ' + doc_height);
$(window).resize(function () {
clearTimeout(timer);
timer = setTimeout(function () {
// console.log( 'Resize Timer!' );
plot.replot();
}, 100);
});
});\n")
(push "});\n</script>"))
(begin (gnc:warn "null-data, not rendering piechart")
" "))
retval))

View File

@ -44,6 +44,17 @@
markercolor markercolor
))) )))
(define-syntax-rule (gnc:guard-html-chart api)
;; this macro applied to old html-bar/line/scatter/pie apis will
;; guard a report writer from passing html-chart objects. this
;; should be removed in 5.x series.
(let ((old-api api))
(set! api
(lambda args
(if (and (pair? args) (gnc:html-chart? (car args)))
(gnc:warn "using old-api " (procedure-name api) " on html-chart object. set options via gnc:html-chart-set! or its shortcuts gnc:html-chart-set-title! etc, and set data via gnc:html-chart-add-data-series! see sample-graphs.scm for examples.")
(apply old-api args))))))
(define gnc:html-scatter? (define gnc:html-scatter?
(record-predicate <html-scatter>)) (record-predicate <html-scatter>))
@ -56,6 +67,8 @@
(record-constructor <html-scatter>)) (record-constructor <html-scatter>))
(define (gnc:make-html-scatter) (define (gnc:make-html-scatter)
(issue-deprecation-warning
"(gnc:make-html-scatter) is deprecated. use gnc:make-html-chart instead.")
(gnc:make-html-scatter-internal '(pixels . -1) '(pixels . -1) #f #f #f #f '() #f #f)) (gnc:make-html-scatter-internal '(pixels . -1) '(pixels . -1) #f #f #f #f '() #f #f))
(define gnc:html-scatter-width (define gnc:html-scatter-width
@ -121,132 +134,63 @@
;; The Renderer ;; The Renderer
(define (gnc:html-scatter-render scatter doc) (define (gnc:html-scatter-render scatter doc)
(define (ensure-numeric elt) (let* ((chart (gnc:make-html-chart))
(cond ((number? elt) (mcolor (gnc:html-scatter-markercolor scatter))
(exact->inexact elt)) (data (gnc:html-scatter-data scatter)))
((string? elt) (cond
(with-input-from-string elt ((and (pair? data) (gnc:not-all-zeros data))
(lambda () (gnc:html-chart-set-type! chart 'scatter)
(let ((n (read))) (gnc:html-chart-set-width! chart (gnc:html-scatter-width scatter))
(if (number? n) n 0.0))))) (gnc:html-chart-set-height! chart (gnc:html-scatter-height scatter))
(#t (gnc:html-chart-set-data-labels! chart (make-list (length data) #f))
0.0))) (gnc:html-chart-add-data-series! chart "scatter"
(map
(lambda (datum)
(list
(cons 'x (car datum))
(cons 'y (cadr datum))))
data)
(make-list (length data) mcolor)
'showLine #t
'fill #f
'borderColor mcolor)
(gnc:html-chart-set-title! chart (list
(gnc:html-scatter-title scatter)
(gnc:html-scatter-subtitle scatter)))
(gnc:html-chart-set! chart
'(options elements point pointStyle)
(case (gnc:html-scatter-marker scatter)
((filleddiamond diamond) "rectRot")
((filledcircle circle) "circle")
((filledsquare square) "rect")
((cross) "crossRot")
((plus) "cross")
((dash) "line")
(else #f)))
(gnc:html-chart-set! chart '(options scales xAxes (0) type) "linear")
(gnc:html-chart-render chart doc))
(let* ((retval '()) (else
(push (lambda (l) (set! retval (cons l retval)))) (gnc:warn "null-data, not rendering scatter")
(title (gnc:html-scatter-title scatter)) ""))))
(subtitle (gnc:html-scatter-subtitle scatter))
(x-label (gnc:html-scatter-x-axis-label scatter))
(y-label (gnc:html-scatter-y-axis-label scatter))
(data (gnc:html-scatter-data scatter))
(marker (gnc:html-scatter-marker scatter))
(markercolor (string-append "#" (gnc:html-scatter-markercolor scatter)))
; Use a unique chart-id for each chart. This prevents chart
; clashed on multi-column reports
(chart-id (string-append "chart-" (number->string (random 999999)))))
(if (and (list? data)
(not (null? data)))
(begin
(push (gnc:html-js-include "jqplot/jquery.min.js"))
(push (gnc:html-js-include "jqplot/jquery.jqplot.js"))
(push (gnc:html-css-include "jqplot/jquery.jqplot.css"))
(push "<div id=\"")(push chart-id)(push "\" style=\"width:") (gnc:guard-html-chart gnc:html-scatter-width)
(push (cdr (gnc:html-scatter-width scatter))) (gnc:guard-html-chart gnc:html-scatter-set-width!)
(if (eq? 'pixels (car (gnc:html-scatter-width scatter))) (gnc:guard-html-chart gnc:html-scatter-height)
(push "px;height:") (gnc:guard-html-chart gnc:html-scatter-set-height!)
(push "%;height:")) (gnc:guard-html-chart gnc:html-scatter-title)
(gnc:guard-html-chart gnc:html-scatter-set-title!)
(push (cdr (gnc:html-scatter-height scatter))) (gnc:guard-html-chart gnc:html-scatter-subtitle)
(if (eq? 'pixels (car (gnc:html-scatter-height scatter))) (gnc:guard-html-chart gnc:html-scatter-set-subtitle!)
(push "px;\"></div>\n") (gnc:guard-html-chart gnc:html-scatter-x-axis-label)
(push "%;\"></div>\n")) (gnc:guard-html-chart gnc:html-scatter-set-x-axis-label!)
(push "<script id=\"source\">\n$(function () {") (gnc:guard-html-chart gnc:html-scatter-y-axis-label)
(gnc:guard-html-chart gnc:html-scatter-set-y-axis-label!)
(push "var data = [];") (gnc:guard-html-chart gnc:html-scatter-data)
(push "var series = [];\n") (gnc:guard-html-chart gnc:html-scatter-set-data!)
(gnc:guard-html-chart gnc:html-scatter-marker)
(if (and data (list? data)) (gnc:guard-html-chart gnc:html-scatter-set-marker!)
(let ((x-data (map-in-order car data)) (gnc:guard-html-chart gnc:html-scatter-markercolor)
(y-data (map-in-order cadr data))) (gnc:guard-html-chart gnc:html-scatter-set-markercolor!)
(for-each (lambda (x y) (gnc:guard-html-chart gnc:html-scatter-add-datapoint!)
(push " data.push([") (gnc:guard-html-chart gnc:html-scatter-render)
(push (ensure-numeric x))
(push ", ")
(push (ensure-numeric y))
(push "]);\n"))
x-data y-data)
))
(push "var options = {
legend: { show: false, },
seriesDefaults: {
markerOptions: {
style: '")
(push marker)
(push "',
color: '")
(push markercolor)
(push "', },
},
series: series,
axesDefaults: {
},
axes: {
xaxis: {
},
yaxis: {
autoscale: true,
},
},
};\n")
(if title
(push (format #f " options.title = ~s;\n"
(gnc:html-string-sanitize title))))
(if subtitle
(push (format #f " options.title += ' (' + ~s + ')';\n"
(gnc:html-string-sanitize subtitle))))
(if (and (string? x-label) (> (string-length x-label) 0))
(begin
(push " options.axes.xaxis.label = \"")
(push x-label)
(push "\";\n")))
(if (and (string? y-label) (> (string-length y-label) 0))
(begin
(push " options.axes.yaxis.label = \"")
(push y-label)
(push "\";\n")))
(push "$.jqplot.config.enablePlugins = true;\n")
(push "$(document).ready(function() {
var plot = $.jqplot('")(push chart-id)(push "', [data], options);
plot.replot();
var timer;
// var win_width = $(window).width();
// var win_height = $(window).height();
// console.log( 'Window Width ' + win_width + ' Height ' + win_height);
// var doc_width = document.body.clientWidth;
// var doc_height = document.body.clientHeight;
// console.log( 'Doc Width ' + doc_width + ' Height ' + doc_height);
$(window).resize(function () {
clearTimeout(timer);
timer = setTimeout(function () {
// console.log( 'Resize Timer!' );
plot.replot();
}, 100);
});
});\n")
(push "});\n</script>"))
(begin
(gnc:warn "Scatter chart has no non-zero data")
" "))
retval))