summaryrefslogtreecommitdiff
path: root/docs/res/graphplot.js
diff options
context:
space:
mode:
Diffstat (limited to 'docs/res/graphplot.js')
-rw-r--r--docs/res/graphplot.js239
1 files changed, 239 insertions, 0 deletions
diff --git a/docs/res/graphplot.js b/docs/res/graphplot.js
new file mode 100644
index 000000000..b06f67f16
--- /dev/null
+++ b/docs/res/graphplot.js
@@ -0,0 +1,239 @@
+
+function GraphPlot(canvas) {
+ this.canvas = canvas
+ const g = canvas.getContext('2d')
+ if (g == null) {
+ throw new Error('failed to acquire 2d context')
+ }
+
+ this.width = 0 // dp
+ this.height = 0 // dp
+ this.widthPx = 0 // px
+ this.heightPx = 0 // px
+ this.pixelRatio = 1
+ this.g = g
+ this.dataSegments = []
+ this.axes = {
+ x0: .5, // % from left to x=0
+ y0: .5, // % from top to y=0
+ scalex: 40, // pixels from x=0 to x=1
+ scaley: 40, // pixels from y=0 to y=1
+ negativeX: true,
+ }
+
+ if (!this.autosize()) {
+ this.setSize(256, 256)
+ }
+}
+
+GraphPlot.prototype.autosize = function() {
+ try {
+ this.canvas.width = null
+ this.canvas.height = null
+ this.canvas.style.width = null
+ this.canvas.style.height = null
+ var cs = window.getComputedStyle(this.canvas)
+ var width = parseFloat(cs.width)
+ var height = parseFloat(cs.height)
+ this.setSize(width, height)
+ return true
+ } catch (err) {
+ if (typeof console != 'undefined' && console.warn) {
+ console.warn('GraphPlot.autosize failed: ' + err)
+ }
+ }
+ return false
+}
+
+// setOrigin sets the origin of axis x and y
+// The values should be in the range [0-1] and maps to the extremes
+// of the canvas.
+//
+GraphPlot.prototype.setOrigin = function(x, y) {
+ var p = this
+ p.axes.x0 = x
+ p.axes.y0 = y
+}
+
+// setScale sets the value scale for x and y axis.
+// The values should be provided as display points.
+//
+GraphPlot.prototype.setScale = function(x, y) {
+ var p = this
+ if (y === undefined) {
+ y = x
+ }
+ p.axes.scalex = x
+ p.axes.scaley = y
+}
+
+// setSize sets the size of canvas in display points
+//
+GraphPlot.prototype.setSize = function(width, height) {
+ var p = this
+ p.width = width
+ p.height = height
+ const el = p.canvas, g = p.g
+ p.pixelRatio = window.devicePixelRatio || 1
+ if (p.pixelRatio != 1) {
+ el.width = p.widthPx = width * p.pixelRatio
+ el.height = p.heightPx = height * p.pixelRatio
+ g.scale(p.pixelRatio, p.pixelRatio)
+ } else {
+ el.width = p.widthPx = width
+ el.height = p.heightPx = height
+ g.scale(1, 1)
+ }
+ el.style.width = `${width}px`
+ el.style.height = `${height}px`
+}
+
+
+GraphPlot.prototype.renderAxes = function() {
+ var p = this
+ , g = p.g
+ , x0 = Math.round(p.axes.x0 * p.widthPx) / p.pixelRatio
+ , y0 = Math.round(p.axes.y0 * p.heightPx) / p.pixelRatio
+
+ g.beginPath()
+ g.strokeStyle = "rgb(0, 0, 0, 0.2)"
+ if (y0 > 0 && y0 < p.width) {
+ g.moveTo(0, y0); g.lineTo(p.width, y0) // X axis
+ }
+ if (x0 > 0 && x0 < p.height) {
+ g.moveTo(x0, 0); g.lineTo(x0, p.height) // Y axis
+ }
+ g.stroke()
+}
+
+
+// plotf plots an arbitrary function on the graph
+//
+GraphPlot.prototype.plotf = function(f, color) {
+ var p = this
+ , g = p.g
+ , w = p.width
+ , h = p.height
+ , x0 = p.axes.x0 * p.width
+ , y0 = p.axes.y0 * p.height
+ , x = 0
+ , y = 0
+ , dx = 4 / p.pixelRatio // smaller means finer curves and more CPU
+ , scalex = p.axes.scalex * w
+ , scaley = p.axes.scaley * h
+ , iMax = Math.round((w - x0) / dx)
+ , iMin = p.axes.negativeX ? Math.round(-x0 / dx) : 0
+
+ g.beginPath()
+ g.lineWidth = 1
+ g.strokeStyle = color || "rgb(0, 0, 0, 0.8)"
+
+ for (var i = iMin; i <= iMax; i++) {
+ x = dx * i
+ y = f(x / scalex) * scaley
+ if (i == iMin) {
+ g.moveTo(x0 + x, y0 - y)
+ } else {
+ g.lineTo(x0 + x, y0 - y)
+ }
+ }
+
+ g.stroke()
+}
+
+
+// plotLines draws straight lines between a collection of points
+//
+GraphPlot.prototype.plotLine = function(points, color) {
+ var p = this
+ , g = p.g
+ , x0 = p.axes.x0 * p.width
+ , y0 = p.axes.y0 * p.height
+ , x = 0
+ , y = 0
+ , scalex = p.axes.scalex * p.width
+ , scaley = p.axes.scaley * p.height
+ , pt
+
+ g.beginPath()
+ g.lineWidth = 1
+ g.strokeStyle = color || "rgb(0, 0, 0, 0.8)"
+
+ var i = 0
+ for (; i < points.length; i++) {
+ pt = points[i]
+ x = pt[0] * scalex
+ y = pt[1] * scaley
+ if (i == 0) {
+ g.moveTo(x0 + x, y0 - y)
+ } else {
+ g.lineTo(x0 + x, y0 - y)
+ }
+ }
+
+ g.stroke()
+}
+
+
+// plotPoints draws points
+//
+GraphPlot.prototype.plotPoints = function(points, color) {
+ var p = this
+ , g = p.g
+ , x0 = p.axes.x0 * p.width
+ , y0 = p.axes.y0 * p.height
+ , x = 0
+ , y = 0
+ , scalex = p.axes.scalex * p.width
+ , scaley = p.axes.scaley * p.height
+ , pt
+ , i = 0
+
+ g.fillStyle = color || "rgb(0, 0, 0, 0.8)"
+
+ for (; i < points.length; i++) {
+ pt = points[i]
+ x = x0 + pt[0] * scalex
+ y = y0 - pt[1] * scaley
+ g.beginPath()
+ g.arc(x, y, 3, 0, Math.PI + (Math.PI * 2) / 2, false)
+ g.fill()
+ }
+}
+
+
+GraphPlot.prototype.clear = function() {
+ var p = this
+ p.g.clearRect(0, 0, p.width, p.height)
+ p.renderAxes()
+}
+
+
+GraphPlot.prototype.renderDemo = function() {
+ var p = this
+ , g = p.g
+ , dpscale = p.pixelRatio
+ , w = p.widthPx
+ , h = p.heightPx
+
+ p.clear()
+
+ p.plotf(
+ function(x) { return Math.sin(x) },
+ 'blue'
+ )
+
+ p.plotf(
+ function(x) { return Math.cos(3*x) },
+ 'hotpink'
+ )
+
+ // var scale = p.height / 4
+ // g.moveTo(0, scale)
+ // var i, sine, lines = 200, frag = p.width / lines
+ // for (i = 0; i < lines; i++) {
+ // sine = Math.sin(i / scale * 2) * scale
+ // g.lineTo(i * frag, -sine + scale)
+ // }
+ // g.stroke()
+}