From 5b983027e09f43a16ab6af2fafeeba474654ea9a Mon Sep 17 00:00:00 2001 From: skhilton Date: Tue, 28 Jan 2020 16:39:06 -0800 Subject: [PATCH 1/8] export state as a json --- docs/_javascript/fileSaver.js | 184 +++++++++++++++++++++++++++++ docs/_javascript/line_plot_zoom.js | 16 +++ docs/_javascript/main.js | 7 ++ docs/index.html | 1 + 4 files changed, 208 insertions(+) create mode 100644 docs/_javascript/fileSaver.js diff --git a/docs/_javascript/fileSaver.js b/docs/_javascript/fileSaver.js new file mode 100644 index 00000000..da8d6ef9 --- /dev/null +++ b/docs/_javascript/fileSaver.js @@ -0,0 +1,184 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define([], factory); + } else if (typeof exports !== "undefined") { + factory(); + } else { + var mod = { + exports: {} + }; + factory(); + global.FileSaver = mod.exports; + } +})(this, function () { + "use strict"; + + /* + * FileSaver.js + * A saveAs() FileSaver implementation. + * + * By Eli Grey, http://eligrey.com + * + * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) + * source : http://purl.eligrey.com/github/FileSaver.js + */ + // The one and only way of getting global scope in all environments + // https://stackoverflow.com/q/3277182/1008999 + var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0; + + function bom(blob, opts) { + if (typeof opts === 'undefined') opts = { + autoBom: false + };else if (typeof opts !== 'object') { + console.warn('Deprecated: Expected third argument to be a object'); + opts = { + autoBom: !opts + }; + } // prepend BOM for UTF-8 XML and text/* types (including HTML) + // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF + + if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { + return new Blob([String.fromCharCode(0xFEFF), blob], { + type: blob.type + }); + } + + return blob; + } + + function download(url, name, opts) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url); + xhr.responseType = 'blob'; + + xhr.onload = function () { + saveAs(xhr.response, name, opts); + }; + + xhr.onerror = function () { + console.error('could not download file'); + }; + + xhr.send(); + } + + function corsEnabled(url) { + var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker + + xhr.open('HEAD', url, false); + + try { + xhr.send(); + } catch (e) {} + + return xhr.status >= 200 && xhr.status <= 299; + } // `a.click()` doesn't work for all browsers (#465) + + + function click(node) { + try { + node.dispatchEvent(new MouseEvent('click')); + } catch (e) { + var evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); + node.dispatchEvent(evt); + } + } + + var saveAs = _global.saveAs || ( // probably in some web worker + typeof window !== 'object' || window !== _global ? function saveAs() {} + /* noop */ + // Use download attribute first if possible (#193 Lumia mobile) + : 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) { + var URL = _global.URL || _global.webkitURL; + var a = document.createElement('a'); + name = name || blob.name || 'download'; + a.download = name; + a.rel = 'noopener'; // tabnabbing + // TODO: detect chrome extensions & packaged apps + // a.target = '_blank' + + if (typeof blob === 'string') { + // Support regular links + a.href = blob; + + if (a.origin !== location.origin) { + corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); + } else { + click(a); + } + } else { + // Support blobs + a.href = URL.createObjectURL(blob); + setTimeout(function () { + URL.revokeObjectURL(a.href); + }, 4E4); // 40s + + setTimeout(function () { + click(a); + }, 0); + } + } // Use msSaveOrOpenBlob as a second approach + : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { + name = name || blob.name || 'download'; + + if (typeof blob === 'string') { + if (corsEnabled(blob)) { + download(blob, name, opts); + } else { + var a = document.createElement('a'); + a.href = blob; + a.target = '_blank'; + setTimeout(function () { + click(a); + }); + } + } else { + navigator.msSaveOrOpenBlob(bom(blob, opts), name); + } + } // Fallback to using FileReader and a popup + : function saveAs(blob, name, opts, popup) { + // Open a popup immediately do go around popup blocker + // Mostly only available on user interaction and the fileReader is async so... + popup = popup || open('', '_blank'); + + if (popup) { + popup.document.title = popup.document.body.innerText = 'downloading...'; + } + + if (typeof blob === 'string') return download(blob, name, opts); + var force = blob.type === 'application/octet-stream'; + + var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; + + var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); + + if ((isChromeIOS || force && isSafari) && typeof FileReader !== 'undefined') { + // Safari doesn't allow downloading of blob URLs + var reader = new FileReader(); + + reader.onloadend = function () { + var url = reader.result; + url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); + if (popup) popup.location.href = url;else location = url; + popup = null; // reverse-tabnabbing #460 + }; + + reader.readAsDataURL(blob); + } else { + var URL = _global.URL || _global.webkitURL; + var url = URL.createObjectURL(blob); + if (popup) popup.location = url;else location.href = url; + popup = null; // reverse-tabnabbing #460 + + setTimeout(function () { + URL.revokeObjectURL(url); + }, 4E4); // 40s + } + }); + _global.saveAs = saveAs.saveAs = saveAs; + + if (typeof module !== 'undefined') { + module.exports = saveAs; + } +}); diff --git a/docs/_javascript/line_plot_zoom.js b/docs/_javascript/line_plot_zoom.js index 2ccd1796..5da7175d 100644 --- a/docs/_javascript/line_plot_zoom.js +++ b/docs/_javascript/line_plot_zoom.js @@ -460,7 +460,23 @@ function genomeLineChart() { focus.classed("brush_select", true).classed("brush_deselect", false) } }); + exportbuttonchange = function(){ + var state = { + "site": d3.selectAll('.selected').data().map(d => +d.site), + "condition": d3.select("#condition").property('value'), + "site-metric": d3.select("#site").property('value'), + "mut-metric": d3.select("#mutation_metric").property('value'), + "protein-representation": polymerSelect.value + } + var fname = prompt("File name: ") + if(fname === null){ + fname = "dms-view.json" + } + state = new Blob([JSON.stringify(state)], {type: "text/plain;charset=utf-8"}); + saveAs(state, fname); + }; + // brush select/deselect choices d3.selectAll("input[name='mode']").on("change", function(){ lastBrushTypeClick = this.value; if ( this.value === 'select' ) { diff --git a/docs/_javascript/main.js b/docs/_javascript/main.js index ebbe0d15..99967abf 100644 --- a/docs/_javascript/main.js +++ b/docs/_javascript/main.js @@ -80,6 +80,13 @@ window.addEventListener('DOMContentLoaded', (event) => { .classed("button", true) .on('click', clearbuttonchange); + var exportButton = d3.select("#line_plot") + .insert("button", "svg") + .text("export state") + .attr("id", "exportButton") + .classed("button", true) + .on('click', exportbuttonchange); + var conditiondropdown = d3.select("#line_plot") .insert("select", "svg") .attr("id", 'condition') diff --git a/docs/index.html b/docs/index.html index e69a0bc4..c805af66 100644 --- a/docs/index.html +++ b/docs/index.html @@ -12,6 +12,7 @@ + From 3ee0f845da0d3f4519395b9e4959216671e6444e Mon Sep 17 00:00:00 2001 From: skhilton Date: Tue, 4 Feb 2020 16:41:17 -0800 Subject: [PATCH 2/8] Move state code to own script and read in / update state --- docs/_javascript/line_plot_zoom.js | 17 +--------- docs/_javascript/state.js | 53 ++++++++++++++++++++++++++++++ docs/index.html | 7 ++++ 3 files changed, 61 insertions(+), 16 deletions(-) create mode 100644 docs/_javascript/state.js diff --git a/docs/_javascript/line_plot_zoom.js b/docs/_javascript/line_plot_zoom.js index 5da7175d..4218b905 100644 --- a/docs/_javascript/line_plot_zoom.js +++ b/docs/_javascript/line_plot_zoom.js @@ -256,7 +256,7 @@ function genomeLineChart() { updateLogoPlot(); } - var selectSite = function(circlePoint){ + selectSite = function(circlePoint){ var circleData = circlePoint.data()[0]; // update the FOCUS plot circlePoint.style("fill", color_key[circleData.site]) @@ -460,21 +460,6 @@ function genomeLineChart() { focus.classed("brush_select", true).classed("brush_deselect", false) } }); - exportbuttonchange = function(){ - var state = { - "site": d3.selectAll('.selected').data().map(d => +d.site), - "condition": d3.select("#condition").property('value'), - "site-metric": d3.select("#site").property('value'), - "mut-metric": d3.select("#mutation_metric").property('value'), - "protein-representation": polymerSelect.value - } - var fname = prompt("File name: ") - if(fname === null){ - fname = "dms-view.json" - } - state = new Blob([JSON.stringify(state)], {type: "text/plain;charset=utf-8"}); - saveAs(state, fname); - }; // brush select/deselect choices d3.selectAll("input[name='mode']").on("change", function(){ diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js new file mode 100644 index 00000000..cd0b2e49 --- /dev/null +++ b/docs/_javascript/state.js @@ -0,0 +1,53 @@ +exportbuttonchange = function(){ + var state = { + "site": d3.selectAll('.selected').data().map(d => +d.site), + "condition": d3.select("#condition").property('value'), + "site-metric": d3.select("#site").property('value'), + "mut-metric": d3.select("#mutation_metric").property('value'), + "protein-representation": polymerSelect.value + } + var fname = prompt("File name: ") + if(fname === null){ + fname = "dms-view.json" + } + state = new Blob([JSON.stringify(state)], {type: "text/plain;charset=utf-8"}); + saveAs(state, fname); +}; + +function markdownButtonChange () { + // Try to load the user's provided URL to a Markdown document. + const markdownUrl = d3.select("#state-url").property('value'); + if (markdownUrl.length > 0) { + d3.json(markdownUrl).then(updateState); + } +} + +var markdownButton = d3.select("#state-url-submit") + .on("click", markdownButtonChange); + +function updateState(state){ + // select sites + state["site"].forEach(function(site){ + selectSite(d3.select("#site_" + site)) + }) + + // update condition + updateDropDownMenu("#condition", state["condition"]) + + // update site metric + updateDropDownMenu("#site", state["site-metric"]) + + // update mut metric + updateDropDownMenu("#mutation_metric", state["mut-metric"]) + +// update protein representation +polymerSelect.value = state["protein-representation"] +changeProteinRepresentation(state["protein-representation"]) +} + +function updateDropDownMenu(dropdownid, target){ + d3.select(dropdownid) + .selectAll("option") + .property('selected', function(d){return d === target;}) + d3.select(dropdownid).dispatch("change") +} diff --git a/docs/index.html b/docs/index.html index c805af66..d5a3258d 100644 --- a/docs/index.html +++ b/docs/index.html @@ -29,6 +29,12 @@

Instructions:

Select points of interest by clicking or brushing (click, hold and swipe). Deselect points by clicking again or brushing after changing the dropdown from select to deselect. Change between different sera, different site-level metrics and different mutation-level metrics using the dropwdown menus. +

+

+ + +
+

@@ -53,5 +59,6 @@

site-level metric

+ From 8b74aa50fe19f739237d60d918c6a45d487c891b Mon Sep 17 00:00:00 2001 From: skhilton Date: Tue, 4 Feb 2020 20:35:39 -0800 Subject: [PATCH 3/8] protein representation added to save state --- docs/_javascript/prot_struct.js | 43 ++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/_javascript/prot_struct.js b/docs/_javascript/prot_struct.js index b82e84ae..36197eca 100644 --- a/docs/_javascript/prot_struct.js +++ b/docs/_javascript/prot_struct.js @@ -88,31 +88,36 @@ var polymerSelect = createSelect([ ["surface", "surface"] ], { onchange: function(e) { - stage.getRepresentationsByName("polymer").dispose() - stage.eachComponent(function(o) { - o.addRepresentation(e.target.value, { - sele: "polymer", - name: "polymer", - color: greyColor - }) - // on change, reselect the points so they are "on top" - d3.selectAll(".selected").data().forEach(function(element) { - element.protein_chain.forEach(function(chain){ - deselectSiteOnProtein(":" + chain + " and " + element.protein_site) - selectSiteOnProtein( - ":" + chain + " and " + element.protein_site, - color_key[element.site] - ) - }) - - }); - }) + const representation = e.target.value; + changeProteinRepresentation(representation) } }, { top: "36px", left: "12px" }) +function changeProteinRepresentation(representation){ + stage.getRepresentationsByName("polymer").dispose() + stage.eachComponent(function(o) { + o.addRepresentation(representation, { + sele: "polymer", + name: "polymer", + color: greyColor + }) + // on change, reselect the points so they are "on top" + d3.selectAll(".selected").data().forEach(function(element) { + element.protein_chain.forEach(function(chain){ + deselectSiteOnProtein(":" + chain + " and " + element.protein_site) + selectSiteOnProtein( + ":" + chain + " and " + element.protein_site, + color_key[element.site] + ) + }) + + }); + }) +} + // tooltip setup tooltip = createElement("div", {}, { display: "none", From 83d38ce468cb1f5ffb4ce9dc1ac8ed3e22e7b9d9 Mon Sep 17 00:00:00 2001 From: skhilton Date: Wed, 5 Feb 2020 09:08:00 -0800 Subject: [PATCH 4/8] removed reliance on fileSave.js --- docs/_javascript/fileSaver.js | 184 ---------------------------------- docs/_javascript/state.js | 14 ++- docs/index.html | 1 - 3 files changed, 12 insertions(+), 187 deletions(-) delete mode 100644 docs/_javascript/fileSaver.js diff --git a/docs/_javascript/fileSaver.js b/docs/_javascript/fileSaver.js deleted file mode 100644 index da8d6ef9..00000000 --- a/docs/_javascript/fileSaver.js +++ /dev/null @@ -1,184 +0,0 @@ -(function (global, factory) { - if (typeof define === "function" && define.amd) { - define([], factory); - } else if (typeof exports !== "undefined") { - factory(); - } else { - var mod = { - exports: {} - }; - factory(); - global.FileSaver = mod.exports; - } -})(this, function () { - "use strict"; - - /* - * FileSaver.js - * A saveAs() FileSaver implementation. - * - * By Eli Grey, http://eligrey.com - * - * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT) - * source : http://purl.eligrey.com/github/FileSaver.js - */ - // The one and only way of getting global scope in all environments - // https://stackoverflow.com/q/3277182/1008999 - var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof global === 'object' && global.global === global ? global : void 0; - - function bom(blob, opts) { - if (typeof opts === 'undefined') opts = { - autoBom: false - };else if (typeof opts !== 'object') { - console.warn('Deprecated: Expected third argument to be a object'); - opts = { - autoBom: !opts - }; - } // prepend BOM for UTF-8 XML and text/* types (including HTML) - // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF - - if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { - return new Blob([String.fromCharCode(0xFEFF), blob], { - type: blob.type - }); - } - - return blob; - } - - function download(url, name, opts) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url); - xhr.responseType = 'blob'; - - xhr.onload = function () { - saveAs(xhr.response, name, opts); - }; - - xhr.onerror = function () { - console.error('could not download file'); - }; - - xhr.send(); - } - - function corsEnabled(url) { - var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker - - xhr.open('HEAD', url, false); - - try { - xhr.send(); - } catch (e) {} - - return xhr.status >= 200 && xhr.status <= 299; - } // `a.click()` doesn't work for all browsers (#465) - - - function click(node) { - try { - node.dispatchEvent(new MouseEvent('click')); - } catch (e) { - var evt = document.createEvent('MouseEvents'); - evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null); - node.dispatchEvent(evt); - } - } - - var saveAs = _global.saveAs || ( // probably in some web worker - typeof window !== 'object' || window !== _global ? function saveAs() {} - /* noop */ - // Use download attribute first if possible (#193 Lumia mobile) - : 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) { - var URL = _global.URL || _global.webkitURL; - var a = document.createElement('a'); - name = name || blob.name || 'download'; - a.download = name; - a.rel = 'noopener'; // tabnabbing - // TODO: detect chrome extensions & packaged apps - // a.target = '_blank' - - if (typeof blob === 'string') { - // Support regular links - a.href = blob; - - if (a.origin !== location.origin) { - corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank'); - } else { - click(a); - } - } else { - // Support blobs - a.href = URL.createObjectURL(blob); - setTimeout(function () { - URL.revokeObjectURL(a.href); - }, 4E4); // 40s - - setTimeout(function () { - click(a); - }, 0); - } - } // Use msSaveOrOpenBlob as a second approach - : 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) { - name = name || blob.name || 'download'; - - if (typeof blob === 'string') { - if (corsEnabled(blob)) { - download(blob, name, opts); - } else { - var a = document.createElement('a'); - a.href = blob; - a.target = '_blank'; - setTimeout(function () { - click(a); - }); - } - } else { - navigator.msSaveOrOpenBlob(bom(blob, opts), name); - } - } // Fallback to using FileReader and a popup - : function saveAs(blob, name, opts, popup) { - // Open a popup immediately do go around popup blocker - // Mostly only available on user interaction and the fileReader is async so... - popup = popup || open('', '_blank'); - - if (popup) { - popup.document.title = popup.document.body.innerText = 'downloading...'; - } - - if (typeof blob === 'string') return download(blob, name, opts); - var force = blob.type === 'application/octet-stream'; - - var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari; - - var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent); - - if ((isChromeIOS || force && isSafari) && typeof FileReader !== 'undefined') { - // Safari doesn't allow downloading of blob URLs - var reader = new FileReader(); - - reader.onloadend = function () { - var url = reader.result; - url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;'); - if (popup) popup.location.href = url;else location = url; - popup = null; // reverse-tabnabbing #460 - }; - - reader.readAsDataURL(blob); - } else { - var URL = _global.URL || _global.webkitURL; - var url = URL.createObjectURL(blob); - if (popup) popup.location = url;else location.href = url; - popup = null; // reverse-tabnabbing #460 - - setTimeout(function () { - URL.revokeObjectURL(url); - }, 4E4); // 40s - } - }); - _global.saveAs = saveAs.saveAs = saveAs; - - if (typeof module !== 'undefined') { - module.exports = saveAs; - } -}); diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js index cd0b2e49..2839c7ac 100644 --- a/docs/_javascript/state.js +++ b/docs/_javascript/state.js @@ -10,10 +10,20 @@ exportbuttonchange = function(){ if(fname === null){ fname = "dms-view.json" } - state = new Blob([JSON.stringify(state)], {type: "text/plain;charset=utf-8"}); - saveAs(state, fname); + state = JSON.stringify(state); + download(fname, state); }; +function download(filename, text) { + var element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); + element.setAttribute('download', filename); + element.style.display = 'none'; + document.body.appendChild(element); + element.click(); + document.body.removeChild(element); +} + function markdownButtonChange () { // Try to load the user's provided URL to a Markdown document. const markdownUrl = d3.select("#state-url").property('value'); diff --git a/docs/index.html b/docs/index.html index d5a3258d..f226d706 100644 --- a/docs/index.html +++ b/docs/index.html @@ -12,7 +12,6 @@ - From 8f9888f9156dcff42e4ccb0beb025b6c10d940b2 Mon Sep 17 00:00:00 2001 From: skhilton Date: Wed, 5 Feb 2020 13:18:44 -0800 Subject: [PATCH 5/8] add checks to state file and contents --- docs/_javascript/state.js | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js index 2839c7ac..85fd5658 100644 --- a/docs/_javascript/state.js +++ b/docs/_javascript/state.js @@ -24,18 +24,24 @@ function download(filename, text) { document.body.removeChild(element); } -function markdownButtonChange () { +function JSONButtonChange () { // Try to load the user's provided URL to a Markdown document. - const markdownUrl = d3.select("#state-url").property('value'); - if (markdownUrl.length > 0) { - d3.json(markdownUrl).then(updateState); + const JSONUrl = d3.select("#state-url").property('value'); + if (JSONUrl.length > 0) { + d3.json(JSONUrl) + .then(updateState) + .catch(err =>alert("Couldn't parse " + JSONUrl + ".\nIs it a proper JSON?")) + }else{ + alert("No state URL entered.") } } var markdownButton = d3.select("#state-url-submit") - .on("click", markdownButtonChange); + .on("click", JSONButtonChange); function updateState(state){ + // check state form + checkState(state) // select sites state["site"].forEach(function(site){ selectSite(d3.select("#site_" + site)) @@ -61,3 +67,16 @@ function updateDropDownMenu(dropdownid, target){ .property('selected', function(d){return d === target;}) d3.select(dropdownid).dispatch("change") } + +function checkState(state){ + var alertMsg; + ["condition", "site-metric", "mut-metric", "protein-representation"] + .forEach(function(target){ + if(!(target in state)){ + alertMsg = alertMsg + "\nCouldn't find " + target + " in JSON. Reverting to current value." + } + }) + if(alertMsg){ + alert(alertMsg) + } +} From 55ee846820534e1b6752e6c966662e062f633d0d Mon Sep 17 00:00:00 2001 From: skhilton Date: Wed, 5 Feb 2020 13:32:12 -0800 Subject: [PATCH 6/8] sites are deselected during state update --- docs/_javascript/line_plot_zoom.js | 2 +- docs/_javascript/state.js | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/_javascript/line_plot_zoom.js b/docs/_javascript/line_plot_zoom.js index 4218b905..0b0dfd5d 100644 --- a/docs/_javascript/line_plot_zoom.js +++ b/docs/_javascript/line_plot_zoom.js @@ -272,7 +272,7 @@ function genomeLineChart() { }); }; - var deselectSite = function(circlePoint){ + deselectSite = function(circlePoint){ var circleData = circlePoint.data()[0]; // update FOCUS plot circlePoint.style("fill", greyColor) diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js index 85fd5658..e1f13696 100644 --- a/docs/_javascript/state.js +++ b/docs/_javascript/state.js @@ -30,7 +30,7 @@ function JSONButtonChange () { if (JSONUrl.length > 0) { d3.json(JSONUrl) .then(updateState) - .catch(err =>alert("Couldn't parse " + JSONUrl + ".\nIs it a proper JSON?")) + // .catch(err =>alert("Couldn't parse " + JSONUrl + ".\nIs it a proper JSON?")) }else{ alert("No state URL entered.") } @@ -42,8 +42,16 @@ var markdownButton = d3.select("#state-url-submit") function updateState(state){ // check state form checkState(state) - // select sites - state["site"].forEach(function(site){ + // figure out what sites to select/deselect + var current_selection = d3.selectAll(".selected").data().map(d => +d.site), + sites_to_deselect = _.without.apply(_, [current_selection].concat(state["site"])), + sites_to_select = _.without.apply(_, [state["site"]].concat(current_selection)) + // deselect sites. + sites_to_deselect.forEach(function(site){ + deselectSite(d3.select("#site_" + site)) + }) + // select sites. + sites_to_select.forEach(function(site){ selectSite(d3.select("#site_" + site)) }) @@ -59,13 +67,15 @@ function updateState(state){ // update protein representation polymerSelect.value = state["protein-representation"] changeProteinRepresentation(state["protein-representation"]) + +// call change on dropdowns to re-up chart +d3.select("#site").dispatch("change") } function updateDropDownMenu(dropdownid, target){ d3.select(dropdownid) .selectAll("option") .property('selected', function(d){return d === target;}) - d3.select(dropdownid).dispatch("change") } function checkState(state){ From 2cdf48a2a03c1997caa9e1c7b8026af33d4df730 Mon Sep 17 00:00:00 2001 From: skhilton Date: Wed, 5 Feb 2020 13:32:53 -0800 Subject: [PATCH 7/8] added back in file type check --- docs/_javascript/state.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js index e1f13696..4082d44a 100644 --- a/docs/_javascript/state.js +++ b/docs/_javascript/state.js @@ -30,7 +30,7 @@ function JSONButtonChange () { if (JSONUrl.length > 0) { d3.json(JSONUrl) .then(updateState) - // .catch(err =>alert("Couldn't parse " + JSONUrl + ".\nIs it a proper JSON?")) + .catch(err =>alert("Couldn't parse " + JSONUrl + ".\nIs it a proper JSON?")) }else{ alert("No state URL entered.") } From 3e41219058034acc030adf62b178c4c149ce1abe Mon Sep 17 00:00:00 2001 From: skhilton Date: Wed, 5 Feb 2020 13:38:08 -0800 Subject: [PATCH 8/8] changed variable name --- docs/_javascript/state.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_javascript/state.js b/docs/_javascript/state.js index 4082d44a..ef8e5568 100644 --- a/docs/_javascript/state.js +++ b/docs/_javascript/state.js @@ -36,7 +36,7 @@ function JSONButtonChange () { } } -var markdownButton = d3.select("#state-url-submit") +var JSONButton = d3.select("#state-url-submit") .on("click", JSONButtonChange); function updateState(state){