From 6787e426693e4f48207df690d9ad11329ce87158 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Tue, 7 Apr 2015 18:04:56 +0200 Subject: [PATCH 01/21] Added a container screenshot --- doc/img/forna-container-screenshot.png | Bin 0 -> 34433 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/img/forna-container-screenshot.png diff --git a/doc/img/forna-container-screenshot.png b/doc/img/forna-container-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3edddad83698a0df614d9b4e561d33cb38d7d4cd GIT binary patch literal 34433 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

l@5 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 Date: Tue, 7 Apr 2015 18:18:13 +0200 Subject: [PATCH 02/21] Saved README.md with Dillinger.io --- README.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/README.md b/README.md index e69de29..136763d 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,50 @@ +# FornaContainer + +In many situations, the user interaction is superfluous and the desired goal is to simply display a secondary structure on a web page. This is a common scenario in, for example, servers that predict a secondary structure. The output, a dot-bracket string can simply be added to a `FornaContainer` object to display. + +## Trivial Example + +Below is an example of a simple web page which uses a `FornaContainer` to show a simple RNA molecule: + +![blah blah](https://raw.githubusercontent.com/pkerpedjiev/fornac/develop/doc/img/forna-container-screenshot.png "An example of the FornaContainer") + +The code for creating this web page is rather straightforward. After importing some necessary javascript files, we create a container using `new FornaContainer("#rna_ss", {'applyForce': false})`, passing in `#rna_ss` as the id of the `div` which will hold the container and then populate it with a structure and sequence using `container.addRNA`: + +```html + + + +This is an RNA container. + +

+ +This is after the RNA container. + + + + + + + + + +``` +## Options + +The `FornaContainer` supports a number of options to allow users to customize how the RNA will be presented. + +### applyForce + +Indicate whether the force-directed layout will be applied to the displayed molecule. Enabling this option allows users to change the layout of the molecule by selecting and dragging the individual nucleotide nodes + +### allowPanningAndZooming + +Allow users to zoom in and pan the display. If this is enabled then pressing the 'c' key on the keyboard will center the view. From ef6c7c170a0f628565fadb06087f46b014f51d27 Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Wed, 8 Apr 2015 13:46:10 +0200 Subject: [PATCH 03/21] cleaned up, generated makefile and fixed several issues --- .gitmodules | 3 +++ Makefile | 17 +++++++++++++++++ closure-compiler | 1 + example.html | 9 +++------ d3.js => js/d3.js | 0 jquery.js => js/jquery.js | 0 tests.js => js/tests.js | 0 fornaf.js => src/fornaf.js | 0 rnagraph.js => src/rnagraph.js | 0 rnautils.js => src/rnautils.js | 0 simplernaplot.js => src/simplernaplot.js | 0 test.html | 9 ++++----- 12 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 .gitmodules create mode 100644 Makefile create mode 160000 closure-compiler rename d3.js => js/d3.js (100%) rename jquery.js => js/jquery.js (100%) rename tests.js => js/tests.js (100%) rename fornaf.js => src/fornaf.js (100%) rename rnagraph.js => src/rnagraph.js (100%) rename rnautils.js => src/rnautils.js (100%) rename simplernaplot.js => src/simplernaplot.js (100%) diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..0a20249 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "closure-compiler"] + path = closure-compiler + url = https://github.com/google/closure-compiler.git diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5adce0b --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +all: closure-compiler/build/compiler.jar js/fornac.js + +js/fornac.js: + java -jar closure-compiler/build/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js_output_file=js/fornac.js src/*.js + +closure-compiler/build/compiler.jar: + git submodule init closure-compiler + git submodule update closure-compiler + cd closure-compiler; ant jar + +release: js/fornac.js + zip fornac-release.zip js/fornac.js example.html README.md + +clean: + rm -f closure-compiler/build/compiler.jar js/fornac.js fornac-release.zip + +.PHONY: all diff --git a/closure-compiler b/closure-compiler new file mode 160000 index 0000000..377d901 --- /dev/null +++ b/closure-compiler @@ -0,0 +1 @@ +Subproject commit 377d9016a6316d174f9bd9bc1db0d33ee6ede187 diff --git a/example.html b/example.html index 8b21cb2..9ba40a4 100644 --- a/example.html +++ b/example.html @@ -7,12 +7,9 @@ This after the RNA container. - - - - - - + + + - - - + + + From 5b96a90135221e0bb4a337dc9b4783952fc8d0bd Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Wed, 8 Apr 2015 14:16:07 +0200 Subject: [PATCH 04/21] Added installation chapter to README.md and cleaned up example --- README.md | 40 +++++++++++++++++++++++----------------- example.html | 27 ++++++++++++--------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 136763d..4a0ffba 100644 --- a/README.md +++ b/README.md @@ -13,29 +13,23 @@ The code for creating this web page is rather straightforward. After importing s ```html - + This is an RNA container. -
- -This is after the RNA container. - - - - - - - +This after the RNA container. + + + + container.addRNA(options.structure, options); + ``` ## Options @@ -48,3 +42,15 @@ Indicate whether the force-directed layout will be applied to the displayed mole ### allowPanningAndZooming Allow users to zoom in and pan the display. If this is enabled then pressing the 'c' key on the keyboard will center the view. + +### Installation + +You need [ANT](http://ant.apache.org/), [Java](http://java.com) and [GNU Make](https://www.gnu.org/software/make/) installed if you want to produce a release javascript file (compressed and optimized). Then just type: +```sh +$ make +``` +Optionally, you can just cat all javascript files into one file: +```sh +$ cat src/*.js > js/fornac.js +``` +Do not forget to run the unit tests in `test.html` to check for regressions! diff --git a/example.html b/example.html index 9ba40a4..cb2d01e 100644 --- a/example.html +++ b/example.html @@ -1,23 +1,20 @@ - -This is an RNA container. +This is an RNA container.
- This after the RNA container. - - - - - + + + + container.addRNA(options.structure, options); + From 1a9af5504c39fc6ee0150a614f3fc95e65702410 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Wed, 8 Apr 2015 14:51:56 +0200 Subject: [PATCH 05/21] new interface for the graph --- fornaf.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fornaf.js b/fornaf.js index 4590ba6..9a57662 100644 --- a/fornaf.js +++ b/fornaf.js @@ -86,7 +86,6 @@ function FornaContainer(element, passedOptions) { // the default options var options = { 'sequence': '', - 'structure': '', 'name': 'empty', 'positions': [], 'labelInterval': 10, @@ -99,8 +98,7 @@ function FornaContainer(element, passedOptions) { } } - console.log('structure:', structure); - rg = new RNAGraph(options.sequence, options.structure, options.name); + rg = new RNAGraph(options.sequence, structure, options.name); rnaJson = rg.recalculateElements() @@ -118,6 +116,7 @@ function FornaContainer(element, passedOptions) { self.addRNAJSON(rnaJson); + } self.addRNAJSON = function(rnaGraph, avoidOthers) { From 3e205bbdf9db0c00a42bee466ea1072ce1112a8f Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Wed, 8 Apr 2015 15:31:25 +0200 Subject: [PATCH 06/21] include fornac.css file --- Makefile | 2 +- README.md | 1 + css/fornac.css | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++ example.html | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 css/fornac.css diff --git a/Makefile b/Makefile index 5adce0b..b84853f 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ closure-compiler/build/compiler.jar: cd closure-compiler; ant jar release: js/fornac.js - zip fornac-release.zip js/fornac.js example.html README.md + zip fornac-release.zip js/fornac.js css/fornac.css example.html README.md clean: rm -f closure-compiler/build/compiler.jar js/fornac.js fornac-release.zip diff --git a/README.md b/README.md index 4a0ffba..510f2b4 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ This is an RNA container.
This after the RNA container. + diff --git a/css/fornac.css b/css/fornac.css new file mode 100644 index 0000000..4dd1be2 --- /dev/null +++ b/css/fornac.css @@ -0,0 +1,80 @@ +svg { + display: block; + min-width: 100%; + width: 100%; + min-height: 100%; +} + +circle.node { + stroke: #ccc; + stroke-width: 1.5px; + opacity: 1; +} + +circle.node.label { + stroke: transparent; +} + +line.link { + stroke-opacity: .6; +} + +.drag_line { + stroke: #999; + stroke-width: 2; + pointer-events: none; +} + +.drag_line_hidden { + stroke: #999; + stroke-width: 0; + pointer-events: none; +} + +.d3-tip { + line-height: 1; + font-weight: bold; + padding: 6px; + background: rgba(0, 0, 0, 0.6); + color: #fff; + border-radius: 4px; + pointer-events: none; + } + +text.node-label { + font-weight: bold; + font-family: Tahoma, Geneva, sans-serif; + color: rgb(100,100,100); + pointer-events: none; +} + +text { + pointer-events: none; +} + +g.gnode { + +} + +circle.outline_node.selected { + visibility: visible; +} + +circle.outline_node { + visibility: hidden; +} + +.brush .extent { + fill-opacity: .1; + stroke: #fff; + shape-rendering: crispEdges; + } + +.noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } diff --git a/example.html b/example.html index cb2d01e..44ee09b 100644 --- a/example.html +++ b/example.html @@ -5,6 +5,7 @@
This after the RNA container. + From 3b22ed43ba3ba01f376a1ca0eba47582b3851d1b Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Wed, 8 Apr 2015 16:16:51 +0200 Subject: [PATCH 07/21] bugfix for style --- src/fornaf.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fornaf.js b/src/fornaf.js index 90cf981..7754e50 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -1044,7 +1044,6 @@ function FornaContainer(element, passedOptions) { self.displayParameters.nodeStrokeWidth=0; } svg.selectAll('circle').style('stroke-width', self.displayParameters.nodeStrokeWidth); - svg.selectAll('circle').style('stroke', 'gray'); }; From d5103383a6ebed7007282d8d4fdba1efd314ac58 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Thu, 9 Apr 2015 22:02:42 +0200 Subject: [PATCH 08/21] Added example_transition.html --- example.html | 1 + example_transition.html | 30 ++++++++++++++++++++++++++++++ src/fornaf.js | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 example_transition.html diff --git a/example.html b/example.html index 44ee09b..4263086 100644 --- a/example.html +++ b/example.html @@ -9,6 +9,7 @@ + + + + + + diff --git a/src/fornaf.js b/src/fornaf.js index ecc9fc4..1397ff8 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -82,7 +82,8 @@ function FornaContainer(element, passedOptions) { self.rnas = {}; self.extraLinks = []; //store links between different RNAs - self.addRNA = function(structure, passedOptions) { + + self.createInitialLayout = function(structure, passedOptions) { // the default options var options = { 'sequence': '', @@ -114,9 +115,15 @@ function FornaContainer(element, passedOptions) { .reinforceLoops() .connectFakeNodes() + return rnaJson; + + } + self.addRNA = function(structure, passedOptions) { + var rnaJson = self.createInitialLayout(structure, passedOptions); self.addRNAJSON(rnaJson); - + + return rnaJson; } self.addRNAJSON = function(rnaGraph, avoidOthers) { @@ -150,6 +157,22 @@ function FornaContainer(element, passedOptions) { self.center_view(); }; + self.transitionRNA = function(previousRNAJson, newStructure, options) { + //transition from an RNA which is already displayed to a new structure + var newRNAJson = self.createInitialLayout(newStructure, options); + console.log('newRNAJson:', newRNAJson); + + vis_nodes.selectAll('g.gnode').each(function(d) { console.log('d before', d); }); + var gnodes = vis_nodes.selectAll('g.gnode').data(newRNAJson); + + gnodes.each(function(d) { console.log('d after', d); }); + + gnodes.transition().attr('transform', function(d) { + console.log('d after', d); + return 'translate(' + [d.x, d.y] + ')'}).duration(1000); + + }; + self.recalculateGraph = function(rnaGraph) { // Condense all of the individual RNAs into one // collection of nodes and links @@ -692,10 +715,15 @@ function FornaContainer(element, passedOptions) { d1.py += d3.event.dy; }); - self.force.resume(); + self.resumeForce(); d3.event.sourceEvent.preventDefault(); } + self.resumeForce = function() { + if (self.animation) + self.force.resume(); + } + function dragended(d) { var toDrag = selectedNodes(d); @@ -988,17 +1016,17 @@ function FornaContainer(element, passedOptions) { self.setFriction = function(value) { self.force.friction(value); - self.force.resume(); + self.resumeForce(); }; self.setCharge = function(value) { self.force.charge(value); - self.force.resume(); + self.resumeForce(); }; self.setGravity = function(value) { self.force.gravity(value); - self.force.resume(); + self.resumeForce(); }; self.setPseudoknotStrength = function(value) { From 081130db9b3adba0389b897d4c15bb5733c17d74 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 14:27:16 +0200 Subject: [PATCH 09/21] Removed debug statements --- src/fornaf.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index 7754e50..51cd380 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -99,7 +99,6 @@ function FornaContainer(element, passedOptions) { } } - console.log('structure:', structure); rg = new RNAGraph(options.sequence, options.structure, options.name); rnaJson = rg.recalculateElements() @@ -319,11 +318,9 @@ function FornaContainer(element, passedOptions) { }; function setSize() { - console.log('element', $(element)); var svgW = $(element).width(); var svgH = $(element).height(); - console.log('svgW', svgW, 'svgH', svgH); self.options.svgW = svgW; self.options.svgH = svgH; @@ -346,7 +343,6 @@ function FornaContainer(element, passedOptions) { svg.attr("width", svgW) .attr("height", svgH); - console.log('svgW', svgW, 'svgH', svgH); self.center_view(); } @@ -1163,7 +1159,6 @@ function FornaContainer(element, passedOptions) { .attr("link_type", function(d) { return d.link_type; } ) .attr('pointer-events', function(d) { if (d.link_type == 'fake') return 'none'; else return 'all';}); - //all_links.exit().each(function(d) { console.log('link exiting', d); }).remove(); all_links.exit().remove(); /* We don't need to update the positions of the stabilizing links */ From 6a8213f4427517d1fdb4e0875ec2ea8589621628 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 14:46:11 +0200 Subject: [PATCH 10/21] Fixed coloring by position --- src/fornaf.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index 1397ff8..c5bf259 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -318,7 +318,7 @@ function FornaContainer(element, passedOptions) { r.struct_name = rnas[uid].struct_name; r.nodes = rnas[uid].nodes; r.links = rnas[uid].links; - r.rna_length = rnas[uid].rna_length; + r.rnaLength = rnas[uid].rnaLength; r.elements = rnas[uid].elements; r.nucs_to_nodes = rnas[uid].nucs_to_nodes; r.pseudoknot_pairs = rnas[uid].pseudoknot_pairs; @@ -431,8 +431,9 @@ function FornaContainer(element, passedOptions) { scale = d3.scale.linear() .range(["#98df8a", "#dbdb8d", "#ff9896"]) .interpolate(d3.interpolateLab) - .domain([1, 1 + (d.rna.rna_length - 1) / 2, d.rna.rna_length]); + .domain([1, 1 + (d.rna.rnaLength - 1) / 2, d.rna.rnaLength]); + console.log('color d:', d); return scale(d.num); }); } else if (newColorScheme == 'custom') { @@ -866,7 +867,7 @@ function FornaContainer(element, passedOptions) { if (d.source.rna == d.target.rna) { var r = d.source.rna; - r.add_pseudoknots(); + r.addPseudoknots(); r.pairtable[d.source.num] = 0; r.pairtable[d.target.num] = 0; From ca4d97dbbab5cfd6547435250a2d2984d9b018ff Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 14:53:44 +0200 Subject: [PATCH 11/21] Removed debug statement --- src/fornaf.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fornaf.js b/src/fornaf.js index c5bf259..dded3ba 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -433,7 +433,6 @@ function FornaContainer(element, passedOptions) { .interpolate(d3.interpolateLab) .domain([1, 1 + (d.rna.rnaLength - 1) / 2, d.rna.rnaLength]); - console.log('color d:', d); return scale(d.num); }); } else if (newColorScheme == 'custom') { From 7ebd7971e711f44033a8ee2e13cdc89c0797ccfa Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 15:04:22 +0200 Subject: [PATCH 12/21] Removed transitionRNA function (which is present in another branch) as well as debugging statements --- src/fornaf.js | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index dded3ba..3667717 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -157,22 +157,6 @@ function FornaContainer(element, passedOptions) { self.center_view(); }; - self.transitionRNA = function(previousRNAJson, newStructure, options) { - //transition from an RNA which is already displayed to a new structure - var newRNAJson = self.createInitialLayout(newStructure, options); - console.log('newRNAJson:', newRNAJson); - - vis_nodes.selectAll('g.gnode').each(function(d) { console.log('d before', d); }); - var gnodes = vis_nodes.selectAll('g.gnode').data(newRNAJson); - - gnodes.each(function(d) { console.log('d after', d); }); - - gnodes.transition().attr('transform', function(d) { - console.log('d after', d); - return 'translate(' + [d.x, d.y] + ')'}).duration(1000); - - }; - self.recalculateGraph = function(rnaGraph) { // Condense all of the individual RNAs into one // collection of nodes and links @@ -341,12 +325,9 @@ function FornaContainer(element, passedOptions) { }; function setSize() { - console.log('element', $(element)); var svgW = $(element).width(); var svgH = $(element).height(); - console.log('svgW', svgW, 'svgH', svgH); - self.options.svgW = svgW; self.options.svgH = svgH; @@ -368,7 +349,6 @@ function FornaContainer(element, passedOptions) { svg.attr("width", svgW) .attr("height", svgH); - console.log('svgW', svgW, 'svgH', svgH); self.center_view(); } @@ -1190,7 +1170,6 @@ function FornaContainer(element, passedOptions) { .attr("link_type", function(d) { return d.link_type; } ) .attr('pointer-events', function(d) { if (d.link_type == 'fake') return 'none'; else return 'all';}); - //all_links.exit().each(function(d) { console.log('link exiting', d); }).remove(); all_links.exit().remove(); /* We don't need to update the positions of the stabilizing links */ From bf5f9849b6b3c63239c65c9a6b5a17adc259d7e8 Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Mon, 13 Apr 2015 18:19:35 +0200 Subject: [PATCH 13/21] moved as much styling as possible to fornac.css --- css/fornac.css | 53 +++++++++- src/fornaf.js | 274 +++++++++++++++++-------------------------------- 2 files changed, 142 insertions(+), 185 deletions(-) diff --git a/css/fornac.css b/css/fornac.css index 4dd1be2..670ef25 100644 --- a/css/fornac.css +++ b/css/fornac.css @@ -7,16 +7,61 @@ svg { circle.node { stroke: #ccc; - stroke-width: 1.5px; + stroke-width: 1px; opacity: 1; + fill: white; } circle.node.label { stroke: transparent; + stroke-width: 0; + fill: white; } +circle.outline_node { + stroke-width: 1px; + fill: red; +} + +circle.protein { + fill: blue; + fill-opacity: 0.5; + stroke-width: 4; +} + +circle.hidden_outline { + stroke-width: 0px; +} + + line.link { - stroke-opacity: .6; + stroke: #999; + stroke-opacity: 0.8; + stroke-width: 2; +} + +line.basepair { + stroke: red; +} + +line.intermolecule { + stroke: blue; +} + +line.chain_chain { + stroke-dasharray: 3,3; +} + +line.fake { + stroke: green; +} + +.transparent { + fill: transparent; + stroke-width: 0; + stroke-opacity: 0; + opacity: 0; + visibility: hidden; } .drag_line { @@ -68,7 +113,7 @@ circle.outline_node { fill-opacity: .1; stroke: #fff; shape-rendering: crispEdges; - } +} .noselect { -webkit-touch-callout: none; @@ -77,4 +122,4 @@ circle.outline_node { -moz-user-select: none; -ms-user-select: none; user-select: none; - } +} diff --git a/src/fornaf.js b/src/fornaf.js index 7754e50..7369fb6 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -53,25 +53,13 @@ function FornaContainer(element, passedOptions) { }; self.displayParameters = { - "nodeStrokeWidth": 0.8, - "nodeStrokeWidthDefault": 0.8, - "nodeLabelFillDefault": d3.rgb(50,50,50), - "nodeLabelFill": d3.rgb(50,50,50), - "linkOpacityDefault": 0.8, - "linkOpacity": 0.8, - "proteinLinkOpacityDefault": 0.8, - "proteinLinkOpacity": 0.8, - "pseudoknotLinkOpacityDefault": 0.8, - "pseudoknotLinkOpacity": 0.8, - "labelLinkOpacityDefault": 0.8, - "labelTextFillDefault": d3.rgb(50,50,50), - "labelTextFill": d3.rgb(50,50,50), - "labelNodeFillDefault": 'white', - "labelNodeFill": 'white', - "backgroundColorDefault": "white", - "backgroundColor": "white", - "proteinBindingHighlighting": true, - "proteinBindingHighlightingDefault": true + "displayBackground": "true", + "displayNumbering": "true", + "displayNodeOutline": "true", + "displayNodeLabel": "true", + "displayLinks": "true", + "displayPseudoknotLinks": "true", + "displayProteinLinks": "true" }; self.colorScheme = 'structure'; @@ -82,11 +70,11 @@ function FornaContainer(element, passedOptions) { self.rnas = {}; self.extraLinks = []; //store links between different RNAs - self.addRNA = function(structure, passedOptions) { + + self.createInitialLayout = function(structure, passedOptions) { // the default options var options = { 'sequence': '', - 'structure': '', 'name': 'empty', 'positions': [], 'labelInterval': 10 @@ -99,8 +87,7 @@ function FornaContainer(element, passedOptions) { } } - console.log('structure:', structure); - rg = new RNAGraph(options.sequence, options.structure, options.name); + rg = new RNAGraph(options.sequence, structure, options.name); rnaJson = rg.recalculateElements() @@ -116,8 +103,15 @@ function FornaContainer(element, passedOptions) { .reinforceLoops() .connectFakeNodes() + return rnaJson; + + } + self.addRNA = function(structure, passedOptions) { + var rnaJson = self.createInitialLayout(structure, passedOptions); self.addRNAJSON(rnaJson); + + return rnaJson; } self.addRNAJSON = function(rnaGraph, avoidOthers) { @@ -151,6 +145,22 @@ function FornaContainer(element, passedOptions) { self.center_view(); }; + self.transitionRNA = function(previousRNAJson, newStructure, options) { + //transition from an RNA which is already displayed to a new structure + var newRNAJson = self.createInitialLayout(newStructure, options); + console.log('newRNAJson:', newRNAJson); + + vis_nodes.selectAll('g.gnode').each(function(d) { console.log('d before', d); }); + var gnodes = vis_nodes.selectAll('g.gnode').data(newRNAJson); + + gnodes.each(function(d) { console.log('d after', d); }); + + gnodes.transition().attr('transform', function(d) { + console.log('d after', d); + return 'translate(' + [d.x, d.y] + ')'}).duration(1000); + + }; + self.recalculateGraph = function(rnaGraph) { // Condense all of the individual RNAs into one // collection of nodes and links @@ -371,15 +381,9 @@ function FornaContainer(element, passedOptions) { self.changeColorScheme = function(newColorScheme) { var protein_nodes = vis_nodes.selectAll('[node_type=protein]'); - protein_nodes.style('fill', 'grey') - .style('fill-opacity', 0.5) + protein_nodes.classed("protein", true) .attr('r', function(d) { return d.radius; }); - /* - var fake_nodes = vis_nodes.seletAll('[node_type=fake]'); - fake_nodes.style('fill', 'transparent'); - */ - var gnodes = vis_nodes.selectAll('g.gnode'); var circles = vis_nodes.selectAll('g.gnode').selectAll('circle'); var nodes = vis_nodes.selectAll('g.gnode').select('[node_type=nucleotide]'); @@ -424,7 +428,7 @@ function FornaContainer(element, passedOptions) { nodes.style('fill', function(d) { if (typeof self.customColors == 'undefined') { return 'white'; - } + } if (self.customColors.color_values.hasOwnProperty(d.struct_name) && self.customColors.color_values[d.struct_name].hasOwnProperty(d.num)) { @@ -489,9 +493,14 @@ function FornaContainer(element, passedOptions) { .append("svg:svg") .attr("width", self.options.svgW) .attr("height", self.options.svgH) - .style("display", "block") .attr("id", 'plotting-area'); + // set css for svg + var style = svg.append('svg:style'); + $.get("../css/fornac.css", function(content){ + style.text(content.replace(/[\s\n]/g, "")); + }); + self.options.svg = svg; var svg_graph = svg.append('svg:g') @@ -693,10 +702,15 @@ function FornaContainer(element, passedOptions) { d1.py += d3.event.dy; }); - self.force.resume(); + self.resumeForce(); d3.event.sourceEvent.preventDefault(); } + self.resumeForce = function() { + if (self.animation) + self.force.resume(); + } + function dragended(d) { var toDrag = selectedNodes(d); @@ -989,17 +1003,17 @@ function FornaContainer(element, passedOptions) { self.setFriction = function(value) { self.force.friction(value); - self.force.resume(); + self.resumeForce(); }; self.setCharge = function(value) { self.force.charge(value); - self.force.resume(); + self.resumeForce(); }; self.setGravity = function(value) { self.force.gravity(value); - self.force.resume(); + self.resumeForce(); }; self.setPseudoknotStrength = function(value) { @@ -1008,107 +1022,60 @@ function FornaContainer(element, passedOptions) { }; self.displayBackground = function(value) { - if (value === true) { - self.displayParameters.backgroundColor=self.displayParameters.backgroundColorDefault; - } else { - self.displayParameters.backgroundColor='transparent'; - } - rect.attr('fill', self.displayParameters.backgroundColor); - //vis_nodes.selectAll('[label_type=label]').attr('fill', self.displayParameters["backgroundColor"]); + self.displayParameters.displayBackground = value; + self.updateStyle(); }; self.displayNumbering = function(value) { - if (value === true) { - self.displayParameters.labelTextFill=self.displayParameters.labelTextFillDefault; - self.displayParameters.labelLinkOpacity=self.displayParameters.labelLinkOpacityDefault; - self.displayParameters.labelNodeFill = self.displayParameters.labelNodeFillDefault; - } else { - self.displayParameters.labelTextFill='transparent'; - self.displayParameters.labelLinkOpacity=0; - self.displayParameters.labelNodeFill = 'transparent'; - } - - self.updateNumbering(); - }; - - self.updateNumbering = function() { - vis_nodes.selectAll('[node_type=label]').style('fill', self.displayParameters.labelNodeFill); - vis_nodes.selectAll('[label_type=label]').style('fill', self.displayParameters.labelTextFill); - vis_links.selectAll('[link_type=label_link]').style('stroke-opacity', self.displayParameters.labelLinkOpacity); + self.displayParameters.displayNumbering = value; + self.updateStyle(); }; self.displayNodeOutline = function(value) { - if (value === true) { - self.displayParameters.nodeStrokeWidth=self.displayParameters.nodeStrokeWidthDefault; - } else { - self.displayParameters.nodeStrokeWidth=0; - } - svg.selectAll('circle').style('stroke-width', self.displayParameters.nodeStrokeWidth); - + self.displayParameters.displayNodeOutline = value; + self.updateStyle(); }; self.displayNodeLabel = function(value) { - if (value === true) { - self.displayParameters.nodeLabelFill=self.displayParameters.nodeLabelFillDefault; - } else { - self.displayParameters.nodeLabelFill='transparent'; - } - vis_nodes.selectAll('[label_type=nucleotide]').attr('fill', self.displayParameters.nodeLabelFill); + self.displayParameters.displayNodeLabel = value; + self.updateStyle(); }; self.displayLinks = function(value) { - if (value === true) { - self.displayParameters.linkOpacity=self.displayParameters.linkOpacityDefault; - } else { - self.displayParameters.linkOpacity=0; - } - - svg.selectAll("[link_type=real],[link_type=basepair],[link_type=backbone],[link_type=pseudoknot],[link_type=protein_chain],[link_type=chain_chain]").style('stroke-opacity', self.displayParameters.linkOpacity); + self.displayParameters.displayLinks = value; + self.updateStyle(); }; self.displayPseudoknotLinks = function(value) { - if (value === true) { - self.displayParameters.pseudoknotLinkOpacity=self.displayParameters.pseudoknotLinkOpacityDefault; - } else { - self.displayParameters.pseudoknotLinkOpacity=0; - } - - svg.selectAll("[link_type=pseudoknot]").style('stroke-opacity', self.displayParameters.pseudoknotLinkOpacity); + self.displayParameters.displayPseudoknotLinks = value; + self.updateStyle(); }; self.displayProteinLinks = function(value) { - if (value === true) { - self.displayParameters.proteinLinkOpacity=self.displayParameters.proteintLinkOpacityDefault; - } else { - self.displayParameters.proteinLinkOpacity=0; - } - - svg.selectAll("[link_type=protein_chain]").style('stroke-opacity', self.displayParameters.proteinLinkOpacity); + self.displayParameters.displayProteinLinks = value; + self.updateStyle(); + }; + + self.updateStyle = function() { + // Background + rect.classed("transparent", !self.displayParameters.displayBackground); + // Numbering + vis_nodes.selectAll('[node_type=label]').classed("transparent", !self.displayParameters.displayNumbering); + vis_nodes.selectAll('[label_type=label]').classed("transparent", !self.displayParameters.displayNumbering); + vis_links.selectAll('[link_type=label_link]').classed("transparent", !self.displayParameters.displayNumbering); + // Node Outline + svg.selectAll('circle').classed("hidden_outline", !self.displayParameters.displayNodeOutline); + // Node Labels + vis_nodes.selectAll('[label_type=nucleotide]').classed("transparent", !self.displayParameters.displayNodeLabel); + // Links + svg.selectAll("[link_type=real],[link_type=basepair],[link_type=backbone],[link_type=pseudoknot],[link_type=protein_chain],[link_type=chain_chain]").classed("transparent", !self.displayParameters.displayLinks); + // Pseudoknot Links + svg.selectAll("[link_type=pseudoknot]").classed("transparent", !self.displayParameters.displayPseudoknotLinks); + // Protein Links + svg.selectAll("[link_type=protein_chain]").classed("transparent", !self.displayParameters.displayProteinLinks); + // Fake Links + vis_links.selectAll("[link_type=fake]").classed("transparent", !self.options.displayAllLinks); }; - - self.displayProteinBindingHighlighting = function(value) { - if (value == true) { - self.displayParameters.proteinBindingHighlighting=self.displayParameters.proteinBindingHighlightingDefault; - } else { - self.displayParameters.proteinBindingHighlighting=false; - } - - //self.displayNodeOutline(true); - /* - - if (self.displayParameters.proteinBindingHighlighting) { - var protein_links = svg.selectAll('[link_type=protein_chain]'); - protein_links.each(function(d) { - var boundNodes = svg.selectAll("circle") - var onlyThese = boundNodes.filter(function(d1) { - return d1.node_type == 'nucleotide' && (d1 == d.source || d1 == d.target ); - }); - - onlyThese.style('stroke-width', 3).style('stroke', 'red') - }) - } - */ - } function nudge(dx, dy) { node.filter(function(d) { return d.selected; }) @@ -1145,17 +1112,6 @@ function FornaContainer(element, passedOptions) { .text(link_key); link_lines.attr("class", "link") - .style("stroke", "#999") - .style("stroke-opacity", self.displayParameters.linkOpacity) - .style("stroke-width", function(d) { - return 2; - }) - .attr('visibility', function(d) { - if (d.link_type == 'fake') - return 'hidden'; - else - return 'visible'; - }) .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) @@ -1167,22 +1123,17 @@ function FornaContainer(element, passedOptions) { all_links.exit().remove(); /* We don't need to update the positions of the stabilizing links */ - fake_links = vis_links.selectAll("[link_type=fake]"); - if (self.options.displayAllLinks) { - fake_links.style('stroke-width', 1); - } else { - fake_links.style('stroke-width', 0); - } - //fake_links.style('stroke', 'blue') - basepair_links = vis_links.selectAll("[link_type=basepair]"); - basepair_links.style('stroke', 'red'); + basepair_links.classed("basepair", true); + + fake_links = vis_links.selectAll("[link_type=fake]") + fake_links.classed("fake", true); intermolecule_links = vis_links.selectAll("[link_type=intermolecule]"); - intermolecule_links.style('stroke', 'blue'); + intermolecule_links.classed("intermolecule", true); plink = vis_links.selectAll("[link_type=protein_chain],[link_type=chain_chain]"); - plink.style("stroke-dasharray", ("3,3")); + plink.classed("chain_chain", true); if (self.displayFakeLinks) @@ -1221,33 +1172,6 @@ function FornaContainer(element, passedOptions) { .ease("elastic") .attr("r", 6.5); - node_fill = function(d) { - node_fills = {}; - - node_fills.nucleotide = 'white'; - node_fills.label = 'white'; - //node_fills.pseudo = 'transparent'; - //node_fills.pseudo = 'transparent'; - //node_fills.middle = 'transparent'; - //node_fills.middle = 'transparent'; - node_fills.middle = 'white'; - node_fills.protein = 'grey'; - - return node_fills[d.node_type]; - }; - - node_stroke = function(d) { - node_strokes = {}; - - node_strokes.nucleotide = 'gray'; - node_strokes.label = 'transparent'; - node_strokes.pseudo = 'transparent'; - node_strokes.middle = 'transparent'; - node_strokes.protein = 'gray'; - - return node_strokes[d.node_type]; - }; - node_tooltip = function(d) { node_tooltips = {}; @@ -1272,8 +1196,6 @@ function FornaContainer(element, passedOptions) { nucleotide_nodes.append("svg:circle") .attr('class', "outline_node") .attr("r", function(d) { return d.radius+1; }) - .style('stroke_width', 1) - .style('fill', 'red') var node = gnodes_enter.append("svg:circle") .attr("class", "node") @@ -1285,14 +1207,6 @@ function FornaContainer(element, passedOptions) { } }) .attr("node_type", function(d) { return d.node_type; }) - .style('stroke-width', function(d) { - if (d.node_type == 'protein') { - return 10; - } else if (d.node_type == 'label') { - return 0; - }}) - .style('stroke-width', self.displayParameters.nodeStrokeWidth) - .style("fill", node_fill) var labels = gnodes_enter.append("text") .text(function(d) { return d.name; }) @@ -1300,7 +1214,6 @@ function FornaContainer(element, passedOptions) { .attr('font-size', 8.0) .attr('font-weight', 'bold') .attr('y', 2.5) - .attr('fill', self.displayParameters.nodeLabelFill) .attr('class', 'node-label') .attr("label_type", function(d) { return d.node_type; }) .append("svg:title") @@ -1358,9 +1271,8 @@ function FornaContainer(element, passedOptions) { if (self.animation) { self.force.start(); } - - self.updateNumbering(); - self.displayProteinBindingHighlighting(true); + + self.updateStyle(); }; setSize(); From b8a0f8dc9516149da4f59ca88994f0fbbd2921b9 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 20:54:30 +0200 Subject: [PATCH 14/21] Properly position molecules next to each other --- src/fornaf.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index f99e201..f752ac7 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -89,7 +89,8 @@ function FornaContainer(element, passedOptions) { 'sequence': '', 'name': 'empty', 'positions': [], - 'labelInterval': 10 + 'labelInterval': 10, + 'avoidOthers': true }; if (arguments.length == 2) { @@ -121,7 +122,9 @@ function FornaContainer(element, passedOptions) { self.addRNA = function(structure, passedOptions) { var rnaJson = self.createInitialLayout(structure, passedOptions); - self.addRNAJSON(rnaJson); + + console.log('passedOptions', passedOptions); + self.addRNAJSON(rnaJson, passedOptions.avoidOthers); return rnaJson; } @@ -132,7 +135,7 @@ function FornaContainer(element, passedOptions) { // Each RNA will have uid to identify it // when it is modified, it is replaced in the global list of RNAs // - var max_x; + var max_x, min_x; if (avoidOthers) { if (self.graph.nodes.length > 0) @@ -140,9 +143,11 @@ function FornaContainer(element, passedOptions) { else max_x = 0; + min_x = d3.min(rnaGraph.nodes.map(function(d) { return d.x; })); + rnaGraph.nodes.forEach(function(node) { - node.x += max_x; - node.px += max_x; + node.x += (max_x - min_x); + node.px += (max_x - min_x); }); } From cf4c1126855b5a1ad82b4a389e201fcd46772066 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Mon, 13 Apr 2015 21:13:55 +0200 Subject: [PATCH 15/21] Fixed the disappearing labels --- src/fornaf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fornaf.js b/src/fornaf.js index c7c3dee..7c6467a 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -11,7 +11,7 @@ function FornaContainer(element, passedOptions) { self.options = { "displayAllLinks": false, - "labelInterval": 0, + "labelInterval": 10, "applyForce": true, "initialSize": [200,200], "allowPanningAndZooming": true From 737dbf44db553be4df0be58528f3bd9127ce13bc Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Tue, 14 Apr 2015 11:59:15 +0200 Subject: [PATCH 16/21] Default avoidOthers option --- src/fornaf.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index 7c6467a..c224926 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -110,8 +110,13 @@ function FornaContainer(element, passedOptions) { self.addRNA = function(structure, passedOptions) { var rnaJson = self.createInitialLayout(structure, passedOptions); - console.log('passedOptions', passedOptions); - self.addRNAJSON(rnaJson, passedOptions.avoidOthers); + if (arguments.length === 1) + passedOptions = {} + + if ('avoidOthers' in passedOptions) + self.addRNAJSON(rnaJson, passedOptions.avoidOthers); + else + self.addRNAJSON(rnaJson, true); return rnaJson; } From 23907160863dbc2d903649572612c182b276b082 Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Tue, 14 Apr 2015 13:35:38 +0200 Subject: [PATCH 17/21] gray proteins --- css/fornac.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/fornac.css b/css/fornac.css index 670ef25..633f329 100644 --- a/css/fornac.css +++ b/css/fornac.css @@ -24,7 +24,7 @@ circle.outline_node { } circle.protein { - fill: blue; + fill: gray; fill-opacity: 0.5; stroke-width: 4; } From fa8913ca5c40e904134ac69c774b709f73803db7 Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Tue, 14 Apr 2015 13:40:33 +0200 Subject: [PATCH 18/21] fix Makefile to recognize source code changes in js files --- Makefile | 4 ++-- src/fornaf.js | 1 - src/simplernaplot.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index b84853f..275c227 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ all: closure-compiler/build/compiler.jar js/fornac.js -js/fornac.js: +js/fornac.js: src/*.js java -jar closure-compiler/build/compiler.jar --compilation_level=SIMPLE_OPTIMIZATIONS --js_output_file=js/fornac.js src/*.js -closure-compiler/build/compiler.jar: +closure-compiler/build/compiler.jar: closure-compiler/* git submodule init closure-compiler git submodule update closure-compiler cd closure-compiler; ant jar diff --git a/src/fornaf.js b/src/fornaf.js index c224926..81e6d60 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -1188,7 +1188,6 @@ function FornaContainer(element, passedOptions) { return node_tooltips[d.node_type]; }; - xlink.on('click', link_click); var circle_update = gnodes.select('circle'); diff --git a/src/simplernaplot.js b/src/simplernaplot.js index 208ffc2..2f88d2e 100644 --- a/src/simplernaplot.js +++ b/src/simplernaplot.js @@ -78,6 +78,7 @@ simple_xy_coordinates = function(pair_table) loop(k, l, pair_table); } } + polygon = Math.PI*(count-2)/count; /* bending angle in loop polygon */ remember[++r] = j; begin = i_old < 0 ? 0 : i_old; @@ -110,6 +111,5 @@ simple_xy_coordinates = function(pair_table) alpha += Math.PI-angle[i+1]; } - return poss; } From 3a3760387dc93103a4342aca13e331ff70ff1657 Mon Sep 17 00:00:00 2001 From: Stefan Hammer Date: Tue, 14 Apr 2015 18:40:49 +0200 Subject: [PATCH 19/21] fix bug with css classes not being updated --- src/fornaf.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index 81e6d60..1081e71 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -1116,17 +1116,25 @@ function FornaContainer(element, passedOptions) { link_lines.append("svg:title") .text(link_key); - link_lines.attr("class", "link") + link_lines + .classed("link", true) .attr("x1", function(d) { return d.source.x; }) .attr("y1", function(d) { return d.source.y; }) .attr("x2", function(d) { return d.target.x; }) .attr("y2", function(d) { return d.target.y; }) .attr("link_type", function(d) { return d.link_type; } ) + .attr("class", function(d) { return d3.select(this).attr('class') + " " + d.link_type; }) .attr('pointer-events', function(d) { if (d.link_type == 'fake') return 'none'; else return 'all';}); + all_links.attr('class', '') + .classed('link', true) + .attr("link_type", function(d) { return d.link_type; } ) + .attr("class", function(d) { return d3.select(this).attr('class') + " " + d.link_type; }) + all_links.exit().remove(); /* We don't need to update the positions of the stabilizing links */ + /* basepair_links = vis_links.selectAll("[link_type=basepair]"); basepair_links.classed("basepair", true); @@ -1138,7 +1146,7 @@ function FornaContainer(element, passedOptions) { plink = vis_links.selectAll("[link_type=protein_chain],[link_type=chain_chain]"); plink.classed("chain_chain", true); - + */ if (self.displayFakeLinks) xlink = all_links; From 7213f3367516c1b78dce88101a3c16ccaecd5efe Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Tue, 14 Apr 2015 18:51:09 +0200 Subject: [PATCH 20/21] addLabels can take a starting number --- src/fornaf.js | 4 ++-- src/rnagraph.js | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/fornaf.js b/src/fornaf.js index c224926..5d41426 100644 --- a/src/fornaf.js +++ b/src/fornaf.js @@ -99,7 +99,7 @@ function FornaContainer(element, passedOptions) { rnaJson = rnaJson.elementsToJson() .addPositions("nucleotide", options.positions) - .addLabels(options.labelInterval) + .addLabels(1, options.labelInterval) .reinforceStems() .reinforceLoops() .connectFakeNodes() @@ -837,7 +837,7 @@ function FornaContainer(element, passedOptions) { .addPseudoknots() .addPositions('nucleotide', nucleotide_positions) .addUids(uids) - .addLabels(self.options.labelInterval) + .addLabels(1, self.options.labelInterval) .addPositions('label', label_positions) .reinforceStems() .reinforceLoops() diff --git a/src/rnagraph.js b/src/rnagraph.js index 3bebb1b..09d241c 100644 --- a/src/rnagraph.js +++ b/src/rnagraph.js @@ -647,9 +647,14 @@ function RNAGraph(seq, dotbracket, struct_name) { return elements.concat(self.pt_to_elements(pt, level, i, j)); }; - self.addLabels = function(labelInterval) { - if (arguments.length === 0) + self.addLabels = function(startNumber, labelInterval) { + if (arguments.length === 0) { + startNumber = 1; labelInterval = 10; + } + + if (arguments.length === 1) + startNumber = labelInterval = 10; if (labelInterval === 0) return self; @@ -710,7 +715,7 @@ function RNAGraph(seq, dotbracket, struct_name) { newX = self.nodes[i-1].x + offsetVec[0]; newY = self.nodes[i-1].y + offsetVec[1]; - new_node = {'name': i, + new_node = {'name': i + startNumber - 1, 'num': -1, 'radius': 6, 'rna': self, From 796181b96dd55e8bee404af9b8926ab5b032d8b1 Mon Sep 17 00:00:00 2001 From: Peter Kerpedjiev Date: Tue, 14 Apr 2015 19:23:56 +0200 Subject: [PATCH 21/21] Fix the startNumber bug --- src/rnagraph.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rnagraph.js b/src/rnagraph.js index 09d241c..65c90cd 100644 --- a/src/rnagraph.js +++ b/src/rnagraph.js @@ -654,7 +654,7 @@ function RNAGraph(seq, dotbracket, struct_name) { } if (arguments.length === 1) - startNumber = labelInterval = 10; + labelInterval = 10; if (labelInterval === 0) return self;