summaryrefslogtreecommitdiff
path: root/docs/res
diff options
context:
space:
mode:
authorRasmus Andersson <rasmus@notion.se>2018-02-20 12:38:51 +0300
committerRasmus Andersson <rasmus@notion.se>2018-02-20 12:38:51 +0300
commit9f367901ef4e6df00eb786ac99fcdc21ed5e69f0 (patch)
tree44ea3e320dd96f541ed94f5a032bff70050afc51 /docs/res
parent761638ef42ec443429889c548b758c06a516839a (diff)
downloadinter-9f367901ef4e6df00eb786ac99fcdc21ed5e69f0.tar.xz
website: major update
Diffstat (limited to 'docs/res')
-rw-r--r--docs/res/base.css550
-rw-r--r--docs/res/base.js74
-rw-r--r--docs/res/bindings.js167
-rw-r--r--docs/res/favicon.pngbin0 -> 700 bytes
-rw-r--r--docs/res/graphplot.js239
5 files changed, 1030 insertions, 0 deletions
diff --git a/docs/res/base.css b/docs/res/base.css
new file mode 100644
index 000000000..5cc6cc39d
--- /dev/null
+++ b/docs/res/base.css
@@ -0,0 +1,550 @@
+* { margin:0; padding:0; }
+html { }
+body {
+ background-color: #f4f4f4;
+ color: #414141;
+ font: 15px/22px 'Inter UI', system-ui, sans-serif;
+
+ font-size: 15px;
+ line-height: 1.5;
+ letter-spacing: -0.002em;
+
+ font-weight: 400;
+ padding-bottom: 30px;
+
+ -webkit-text-size-adjust: 100%;
+ -ms-text-size-adjust: 100%;
+ -webkit-overflow-scrolling: touch;
+ scroll-behavior: smooth;
+
+ font-kerning: normal;
+ -moz-font-feature-settings:"kern" 1, "liga" 1;
+ -ms-font-feature-settings:"kern" 1, "liga" 1;
+ -o-font-feature-settings:"kern" 1, "liga" 1;
+ -webkit-font-feature-settings:"kern" 1, "liga" 1;
+ font-feature-settings:"kern" 1, "liga" 1;
+}
+
+:target:before {
+ content:"";
+ display: block;
+ height: 20px; /* fixed header height*/
+ margin: -20px 0 0; /* negative fixed header height */
+}
+
+a {
+ text-decoration: underline rgba(0, 0, 0, 0.3);
+ color: black;
+ word-break: break-word;
+ word-wrap: break-word;
+}
+a.fat {
+ font-weight:500;
+ color: #333;
+}
+a:hover {
+ color: rgb(3, 102, 214);
+ text-decoration: underline rgba(3, 102, 214, 0.6);
+}
+a.plain, a.fat {
+ background: none;
+ text-shadow: none;
+ text-decoration: none;
+ cursor: pointer;
+}
+a[href^="#"]:hover {
+ text-decoration-style: dashed;
+}
+
+p {
+ margin: 20px 0;
+}
+code, pre, q {
+ font-family: "SFMono-Regular", Menlo, Consolas, Inconsolata, monospace;
+ font-size:0.96em;
+}
+code {
+ display: block;
+ border-radius:1px;
+ padding: 0.5em 0;
+ overflow: auto;
+}
+pre, q {
+ display: inline;
+ white-space: pre-wrap;
+}
+q {
+ display: inline;
+}
+q:before {
+ content: "";
+}
+q:after {
+ content: "";
+}
+kbd {
+ -moz-font-feature-settings: 'kern' 1, 'case' 1;
+ -ms-font-feature-settings: 'kern' 1, 'case' 1;
+ -o-font-feature-settings: 'kern' 1, 'case' 1;
+ -webkit-font-feature-settings: 'kern' 1, 'case' 1;
+ font-feature-settings: 'kern' 1, 'case' 1;
+ border: 1px solid rgba(0,0,0,0.18);
+ border-radius: 3px;
+ padding:0.1em 0.2em;
+ margin:0 0.1em;
+}
+dem { /* de-emphasize */
+ font-weight: 400;
+ opacity: 0.7;
+}
+num { /* number */
+ /*-moz-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -ms-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -o-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'ss01' 1;
+ font-feature-settings: 'calt' 1, 'ss01' 1;*/
+ letter-spacing:0.02em;
+ white-space: pre;
+}
+
+small {
+ font-size: 11px;
+ letter-spacing: 0.013em;
+}
+
+h1, h2, h3 {
+ font-weight: 500;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+h1 {
+ color: #222;
+ font-size: 55px;
+ letter-spacing: -0.03em;
+ line-height: 1.1em;
+ text-indent: -2px;
+ margin-bottom: 30px;
+ margin-top: 10px;
+ font-weight: 700;
+}
+h2 {
+ font-size: 24px;
+ letter-spacing: -0.4px;
+ line-height: 30px;
+ margin-bottom: 25px;
+ margin-top: 10px;
+}
+h2.back {
+ color:rgba(0,0,0,0.2);
+ font-size: inherit;
+ letter-spacing: inherit;
+ font-weight:400;
+ margin:0;
+ margin-top:-1.9em;
+}
+h2.back a:hover {
+ color: black;
+ margin-left:-1.3em;
+}
+h2.back a:hover::before {
+ content: "<- ";
+}
+h2.banner {
+ text-align: center;
+ display: flex;
+ justify-content: center;
+}
+ h2.banner > * {
+ flex: 0 1 auto;
+ padding: 0.8em 1.2em;
+ border-radius: 4em;
+ display: block;
+ background: white;
+ }
+ h2.banner > a:hover {
+ color: black;
+ background: rgba(0,0,0,0.1);
+ }
+
+h3 {
+ font-size: inherit;
+}
+
+h1 > a, h2 > a, h3 > a {
+ color: inherit;
+ text-decoration: none !important;
+ text-shadow: none;
+ background: none;
+}
+
+.row {
+ padding: 50px;
+ display: flex;
+ justify-content: center;
+}
+ .row > * {
+ width:100%;
+ max-width: 888px;
+ flex: 1 0 100%;
+ }
+ .row .learn-more {
+ margin-top: 2em;
+ text-align: center;
+ font-size: 11px;
+ letter-spacing: 0.007em;
+ }
+ .row .learn-more a {
+ color: rgba(0,0,0,0.4);
+ text-decoration-color: rgba(0, 0, 0, 0);
+ }
+ .row .learn-more a:hover {
+ color: inherit;
+ }
+
+.row.full-width {
+ padding: 50px 0;
+ justify-content: flex-start;
+}
+ .row.full-width > * {
+ max-width: initial;
+ }
+
+.row-divider {
+ margin:0 auto;
+ max-width: 888px;
+ height: 1px;
+ border-bottom: 1px dashed rgba(0,0,0,0.09);
+}
+
+.row.menu {
+ padding: 0;
+ border-bottom:1px solid rgba(0,0,0,0.1);
+}
+ .row.menu ul {
+ width: auto;
+ max-width: 888px;
+ flex: 1 1 auto;
+ list-style: none;
+ padding: 0;
+ margin: 0 50px;
+ display: flex;
+ flex-wrap: wrap;
+ white-space: nowrap;
+ }
+ .row.menu ul li {
+ margin-right: 30px;
+ margin-bottom: -1px;
+ }
+ .row.menu ul li > a {
+ color: inherit;
+ opacity: 0.6;
+ text-decoration:none;
+ display: inline-block;
+ padding: 15px 0 13px 0;
+ transition: 300ms opacity cubic-bezier(0.25, 0.47, 0.44, 0.93);
+ border-bottom: 3px solid transparent;
+ }
+ .row.menu ul li > a:hover, .row.menu ul li > a.active {
+ color: black;
+ border-bottom-color: black;
+ opacity: 1;
+ }
+ .row.menu ul li.home > a {
+ font-weight: 500;
+ color: black;
+ opacity: 1;
+ }
+
+
+.row.white {
+ background: white;
+}
+
+.row.dark {
+ background: #2b2b2b;
+ color: #99999b;
+}
+.row.dark a {
+ text-decoration-color: rgba(255, 255, 255, 0.2);
+ color: #aaa;
+}
+.row.dark a:hover {
+ color: rgba(160, 190, 255, 1);
+ text-decoration: underline rgba(164, 188, 255, 0.6);
+}
+.row.dark h2, .row.dark h2 > a {
+ color: #ccc;
+ background: none;
+}
+
+.row.color1 {
+ background: #C0CDE2;
+ color: #3B414A;
+}
+
+ul {
+ margin-left:1.1em;
+}
+
+a > img {
+ display: block;
+}
+
+#repertoire-image {
+ display:block;
+ width:100%;
+ height:40vw;
+ background-image: url(res/repertoire.png);
+ background-repeat: no-repeat;
+ background-size: cover;
+ background-blend-mode: multiply;
+ background-color: #f4f4f4;
+}
+
+.sample-images {}
+ .sample-images img, .sample-images svg {
+ display: block;
+ width: 100%;
+ }
+
+
+/* FAQ */
+ul.faq {
+ list-style:none;
+ display: flex;
+ flex-direction: column;
+ margin-left:0;
+}
+ul.faq > li {
+ padding-right: 6px;
+ margin-bottom: 6px;
+ padding-left: 1.5em;
+ text-indent: -1.5em;
+}
+
+ul.faq > li:target {
+ background: #fafa88;
+ margin-left: -1.5em;
+}
+ul.faq > li > a.anchor {
+ visibility: hidden;
+ height:0;
+ position:relative;
+}
+
+li.q {
+ font-weight: 500;
+ margin-top:1.5em;
+}
+ul > li.q:first-child, ul > li.q:not([id]) {
+ margin-top:0;
+}
+
+tablex {
+ display: flex;
+}
+ tablex > t {
+ display: table;
+ }
+ tablex > t > h {
+ display: table-row;
+ opacity:0.4;
+ }
+ tablex > t > h > * {
+ padding-bottom:1em;
+ }
+ tablex > t > h to {
+ visibility: hidden;
+ }
+ tablex > t > r {
+ text-decoration: none;
+ display: table-row;
+ }
+ tablex in, tablex to, tablex out {
+ display: table-cell;
+ width: 5%;
+ white-space: pre;
+ padding-bottom:0.5em;
+ }
+ /*tablex to {
+ width:0;
+ }*/
+ tablex to::after {
+ -moz-font-feature-settings: 'calt' 1, 'case' 1;
+ -ms-font-feature-settings: 'calt' 1, 'case' 1;
+ -o-font-feature-settings: 'calt' 1, 'case' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'case' 1;
+ font-feature-settings: 'calt' 1, 'case' 1;
+ content: " → ";
+ color: rgba(0,0,0,0.2);
+ }
+ tablex in, tablex out {
+ color: rgba(0,0,0,0.8);
+ }
+ tablex in {
+ -moz-font-feature-settings: 'calt' 0;
+ -ms-font-feature-settings: 'calt' 0;
+ -o-font-feature-settings: 'calt' 0;
+ -webkit-font-feature-settings: 'calt' 0;
+ font-feature-settings: 'calt' 0;
+ }
+ tablex out {
+ -moz-font-feature-settings: 'calt' 1;
+ -ms-font-feature-settings: 'calt' 1;
+ -o-font-feature-settings: 'calt' 1;
+ -webkit-font-feature-settings: 'calt' 1;
+ font-feature-settings: 'calt' 1;
+ }
+ tablex out.zero {
+ -moz-font-feature-settings: 'calt' 1, 'zero' 1;
+ -ms-font-feature-settings: 'calt' 1, 'zero' 1;
+ -o-font-feature-settings: 'calt' 1, 'zero' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'zero' 1;
+ font-feature-settings: 'calt' 1, 'zero' 1;
+ }
+ tablex out.tnum {
+ -moz-font-feature-settings: 'calt' 1, 'tnum' 1;
+ -ms-font-feature-settings: 'calt' 1, 'tnum' 1;
+ -o-font-feature-settings: 'calt' 1, 'tnum' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'tnum' 1;
+ font-feature-settings: 'calt' 1, 'tnum' 1;
+ }
+ tablex out.case {
+ -moz-font-feature-settings: 'calt' 1, 'case' 1;
+ -ms-font-feature-settings: 'calt' 1, 'case' 1;
+ -o-font-feature-settings: 'calt' 1, 'case' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'case' 1;
+ font-feature-settings: 'calt' 1, 'case' 1;
+ }
+ tablex out.frac {
+ -moz-font-feature-settings: 'calt' 1, 'frac' 1;
+ -ms-font-feature-settings: 'calt' 1, 'frac' 1;
+ -o-font-feature-settings: 'calt' 1, 'frac' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'frac' 1;
+ font-feature-settings: 'calt' 1, 'frac' 1;
+ }
+ tablex out.ss01 {
+ -moz-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -ms-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -o-font-feature-settings: 'calt' 1, 'ss01' 1;
+ -webkit-font-feature-settings: 'calt' 1, 'ss01' 1;
+ font-feature-settings: 'calt' 1, 'ss01' 1;
+ }
+ tablex em {
+ font-style: inherit;
+ background: #FBE9A3;
+ color: rgba(0,0,0,1);
+ }
+
+
+boxes {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: stretch;
+ margin-right:-1em;
+}
+box {
+ overflow: auto;
+ flex: 1 1 0;
+ min-width: 280px;
+ max-width: 100%;
+ display: flex;
+ flex-direction: column;
+ background: white;
+ padding: 2em;
+ border-radius: 3px;
+ margin-right:1em;
+ margin-bottom:1em;
+}
+body.safari box {
+ /* Fix for broken flex wrap in safari */
+ flex-basis: 40%;
+}
+box:first-child {
+ margin-left:0;
+}
+box h3 {
+ margin-bottom:0.8em;
+}
+
+
+/* ------------------------------------------------------ */
+
+/* narrow windows */
+@media only screen and (max-width: 565px) {
+ .row.menu ul {
+ justify-content: space-between;
+ }
+ .row.menu ul li {
+ margin-right: 15px;
+ }
+ .row.menu ul li:last-child {
+ margin-right: 0;
+ }
+ .row.menu ul li.home {
+ /*color: red;
+ clear: both;*/
+ /*display: block;*/
+ text-align:center;
+ margin:0 0 -12px 0;
+ width: 100%;
+ }
+ .row.menu ul li.home > a {
+ border-bottom: none;
+ padding: 0 1em;
+ margin: 0.5em 0;
+ line-height:34px;
+ border-radius: 90px;
+
+ /*color: white;
+ background-color: rgba(3, 102, 214, 1);*/
+ }
+ .row.menu ul li.home > a:hover {
+ color: white;
+ background-color: #222;
+ }
+}
+
+/* small devices (<= iPhone 6+) */
+@media only screen and (max-device-width: 414px) {
+ box { padding: 1em; }
+ box tablex r { font-size: 0.9em; }
+ body {
+ font-size: 14px;
+ line-height: 20px;
+ }
+ .row {
+ padding-left: 20px;
+ padding-right: 20px;
+ }
+ .row.menu ul {
+ margin-left: 20px;
+ margin-right: 20px;
+ }
+}
+
+/* small devices (<= iPhone 5) */
+@media only screen and (max-device-width: 320px) {
+ box {
+ font-size: 0.8em;
+ min-width: 240px;
+ }
+ /*.row.menu {
+ font-size:13px;
+ }
+ .row.menu ul {
+ margin-left: 0;
+ margin-right: 0;
+ }
+ .row.menu ul li {
+ flex: 1 0 auto;
+ text-align: center;
+ border-right: 1px solid rgba(0,0,0,0.1);
+ margin-left:0;
+ margin-right:0;
+ }
+ .row.menu ul li:last-child {
+ border-right: none;
+ }*/
+}
+
diff --git a/docs/res/base.js b/docs/res/base.js
new file mode 100644
index 000000000..3ef970cc3
--- /dev/null
+++ b/docs/res/base.js
@@ -0,0 +1,74 @@
+
+function $$(query, el) {
+ return [].slice.call((el || document).querySelectorAll(query))
+}
+
+function $(query, el) {
+ return (el || document).querySelector(query)
+}
+
+// fetchjson(url string) :Promise<Object>
+//
+var fetchjson = (
+ typeof window.fetch == 'function' ? (
+ function _fetchjson(url, cb) {
+ return window.fetch(url).then(function(r) { return r.json() })
+ }
+ ) :
+ function _fetchjson(url, cb) {
+ return new Promise(function(resolve, reject) {
+ var r = new XMLHttpRequest()
+ r.addEventListener("load", function(){
+ try {
+ resolve(JSON.parse(r.responseText))
+ } catch (err) {
+ reject(err)
+ }
+ })
+ r.addEventListener("error", function(ev) {
+ reject(ev.error || ev || new Error('network error'))
+ })
+ r.open("GET", url)
+ r.send()
+ })
+ }
+)
+
+
+// timeNow() :float
+//
+var timeNow = (
+ window.performance !== undefined && window.performance.now ? function() {
+ return window.performance.now()
+ } : Date.now ? function() {
+ return Date.now()
+ } : function() {
+ return (new Date()).getTime()
+ }
+)
+
+
+// Mac or not? Maybe even a buggy Safari?
+var isMac = false
+if (!window.MSStream &&
+ /mac|ipad|iphone|ipod/i.test(navigator.userAgent))
+{
+ isMac = true
+ if (navigator.userAgent.indexOf('Safari') != -1 &&
+ navigator.userAgent.indexOf('Chrome') == -1)
+ {
+ document.body.classList.add('safari')
+ }
+}
+
+
+// Google Analytics
+// ;(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
+// (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
+// m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
+// })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
+// ga('create', 'UA-105091131-2', 'auto');
+// ga('send', 'pageview');
+window.dataLayer = window.dataLayer || [];
+window.dataLayer.push(['js', new Date()])
+window.dataLayer.push(['config', 'UA-105091131-2'])
diff --git a/docs/res/bindings.js b/docs/res/bindings.js
new file mode 100644
index 000000000..eb51b87d5
--- /dev/null
+++ b/docs/res/bindings.js
@@ -0,0 +1,167 @@
+// requires index.js
+
+function passThrough(v) { return v }
+
+function Binding(name){
+ this.name = name
+ this.value = undefined
+ this.inputs = []
+ this.listeners = []
+ this.parser = undefined
+ this.formatter = passThrough
+}
+
+
+Binding.prototype.addInput = function(el) {
+ var binding = this
+ var _onInput = function(ev) {
+ binding.setValue(el.value, el)
+ }
+ var input = {
+ el: el,
+ _onInput: _onInput,
+ }
+ this.inputs.push(input)
+ if (this.value === undefined) {
+ this.value = el.value
+ } else {
+ input.el.value = this.formatter(this.value)
+ }
+ el.addEventListener('input', _onInput, {passive:true})
+}
+
+
+// listener signature:
+// function(nextval string, prevval string, b Binding)void
+//
+Binding.prototype.addListener = function(listener) {
+ this.listeners.push(listener)
+}
+
+
+Binding.prototype.setValue = function(nextval, origin) {
+ // console.log('Binding.setValue nextval:', nextval, {origin})
+ var prevval = this.value
+ if (this.parser) {
+ nextval = this.parser(nextval, prevval)
+ }
+ if (this.value === nextval) {
+ return
+ }
+ var binding = this
+ this.value = nextval
+ this.inputs.forEach(function(input) {
+ if (input.el !== origin) {
+ input.el.value = binding.formatter(nextval)
+ }
+ })
+ this.listeners.forEach(function(listener) {
+ listener(nextval, prevval, this)
+ })
+}
+
+
+function Bindings() {
+ this.bindings = {}
+}
+
+Bindings.prototype.getBinding = function(name, input) {
+ var binding = this.bindings[name]
+ if (!binding) {
+ binding = new Binding(name)
+ this.bindings[name] = binding
+ }
+ return binding
+}
+
+Bindings.prototype.bindInput = function(name, input) {
+ // console.log('bindInput', name, input)
+ var binding = this.getBinding(name)
+ binding.addInput(input)
+}
+
+Bindings.prototype.bindAllInputs = function(queryOrInputElementList) {
+ var bindings = this
+
+ var inputs = (
+ typeof queryOrInputElementList == 'string' ? $$(queryOrInputElementList) :
+ queryOrInputElementList
+ )
+
+ inputs.forEach(function(input) {
+ var bindingName = input.dataset.binding
+ if (bindingName) {
+ bindings.bindInput(bindingName, input)
+ }
+ })
+}
+
+// listener signature:
+// function(nextval string, prevval string, b Binding)void
+//
+Bindings.prototype.addListener = function(name, listener) {
+ var binding = this.getBinding(name)
+ binding.addListener(listener)
+}
+
+Bindings.prototype.setValue = function(name, value) {
+ var binding = this.getBinding(name)
+ binding.setValue(value)
+}
+
+Bindings.prototype.setFormatter = function(name, formatter) {
+ var binding = this.getBinding(name)
+ binding.formatter = formatter || passThrough
+}
+
+
+Bindings.prototype.value = function(name, defaultValue) {
+ var binding = this.bindings[name]
+ return binding && binding.value !== undefined ? binding.value : defaultValue
+}
+
+
+function fmt_float(nextval, prevval) {
+ var n = parseFloat(nextval)
+ return isNaN(n) ? 0 : n
+}
+
+function fmt_int(nextval, prevval) {
+ var n = parseInt(nextval)
+ return isNaN(n) ? 0 : n
+}
+
+
+// configure is convenience function for setting value, adding a
+// listener and associating a parser with a binding.
+// If a listener and a value is provided, the value is set and the listener
+// is immediately invoked.
+//
+Bindings.prototype.configure = function(name, value, parser, listener) {
+ var binding = this.getBinding(name)
+ if (listener) {
+ binding.addListener(listener)
+ }
+ if (value !== undefined && value !== null) {
+ binding.setValue(value)
+ }
+ if (parser) {
+ if (typeof parser == 'string') {
+ switch (parser) {
+ case 'number':
+ case 'float':
+ parser = fmt_float; break;
+
+ case 'int':
+ case 'integer':
+ parser = fmt_int; break;
+
+ default:
+ throw new Error('unknown parser "' + parser + '"')
+ }
+ } else if (typeof parser != 'function') {
+ throw new Error('parser should be a string or function')
+ }
+ binding.parser = parser
+ }
+}
diff --git a/docs/res/favicon.png b/docs/res/favicon.png
new file mode 100644
index 000000000..5caeaf04a
--- /dev/null
+++ b/docs/res/favicon.png
Binary files differ
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()
+}