From 6400d8eb8ec6bbd9a1617c31581ae227f94c178d Mon Sep 17 00:00:00 2001 From: juanf <juanf> Date: Mon, 3 Mar 2014 14:30:58 +0000 Subject: [PATCH] BIS-604 / SP-1211: ELN UI - Hierarchical View (Zoom and Pan Controls) SVN: 30801 --- .../as/webapps/newbrowser/html/css/style.css | 5 ++ .../html/js/views/SampleHierarchy.js | 79 +++++++++++++++++-- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/css/style.css b/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/css/style.css index 61f9510db2d..7399d94a0a0 100644 --- a/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/css/style.css +++ b/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/css/style.css @@ -422,6 +422,11 @@ table.downloads { fill: none; } +.svgButton:hover { + fill: #005580; + stroke: #005580; +} + /* * Storage Widget */ diff --git a/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/js/views/SampleHierarchy.js b/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/js/views/SampleHierarchy.js index cee3eb5b2a2..5c1fcab4291 100644 --- a/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/js/views/SampleHierarchy.js +++ b/plasmid/source/core-plugins/newbrowser/1/as/webapps/newbrowser/html/js/views/SampleHierarchy.js @@ -137,11 +137,12 @@ function SampleHierarchy(serverFacade, inspector, containerId, profile, sample) .append($filtersFormSliderParents) .append("<span style='padding-right:15px;'></span>") .append(' Show Types: ') - .append($filtersFormSampleTypes); + .append($filtersFormSampleTypes) + .append("<span style='position:absolute; left:30px; top:80px;'><svg height='100' width='100'><g id='svgControls'/></svg></span>"); $('#'+this.containerId).append($filtersForm); $('#'+this.containerId).append($('<div>', { 'id' : 'graphContainer' })); - $('#graphContainer').append("<svg><g transform='translate(20,20)'/></svg>"); + $('#graphContainer').append("<svg id='svgMapContainer'><g id='svgMap' transform='translate(20,20) scale(1)'/></svg>"); $('#childrenLimit').slider(); $('#childrenLimit').slider().on('slideStop', function(event){ @@ -159,6 +160,29 @@ function SampleHierarchy(serverFacade, inspector, containerId, profile, sample) }); this._filterSampleAndUpdate(); + + //Add SVG Map Controls + var path1 = this._makeSVG('path', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.pan( 0, 50);', 'd':'M50 10 l12 20 a40, 70 0 0,0 -24, 0z', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var path2 = this._makeSVG('path', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.pan( 50, 0);', 'd':'M10 50 l20 -12 a70, 40 0 0,0 0, 24z', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var path3 = this._makeSVG('path', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.pan( 0,-50);', 'd':'M50 90 l12 -20 a40, 70 0 0,1 -24, 0z', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var path4 = this._makeSVG('path', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.pan(-50, 0);', 'd':'M90 50 l-20 -12 a70, 40 0 0,1 0, 24z', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var circle2 = this._makeSVG('circle', {'cx':'50', 'cy':'50', 'r':'20', 'stroke':'#000', 'stroke-width':'1.5', 'fill':'#fff', 'opacity':'0.75'}); + var rect1 = this._makeSVG('rect', {'x':'46', 'y':'39.5', 'width':'8', 'height':'3' , 'fill':'#fff', 'style' : 'pointer-events: none;'}); + var rect2 = this._makeSVG('rect', {'x':'46', 'y':'57.5', 'width':'8', 'height':'3' , 'fill':'#fff', 'style' : 'pointer-events: none;'}); + var rect3 = this._makeSVG('rect', {'x':'48.5', 'y':'55', 'width':'3', 'height':'8' , 'fill':'#fff', 'style' : 'pointer-events: none;'}); + var circle3 = this._makeSVG('circle', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.zoom(0.8)', 'cx':'50', 'cy':'41', 'r':'8', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var circle4 = this._makeSVG('circle', {'class' : 'svgButton', 'stroke-linecap':'round', 'stroke-miterlimit':'6', 'onclick':'javascript:mainController.currentView.zoom(1.25)', 'cx':'50', 'cy':'59', 'r':'8', 'stroke-width':'1.5', 'fill':'#0088CC', 'stroke': '#0088CC' }); + var svgControls = $("#svgControls") + .append(path1) + .append(path2) + .append(path3) + .append(path4) + .append(circle2) + .append(circle3) + .append(circle4) + .append(rect1) + .append(rect2) + .append(rect3); } this._filterSampleAndUpdate = function() { @@ -380,7 +404,7 @@ function SampleHierarchy(serverFacade, inspector, containerId, profile, sample) addSampleEdges(sample); // Render the directed graph - var svg = d3.select('svg'); + var svgG = d3.select('#svgMap'); var renderer = new dagreD3.Renderer(); // Custom transition function @@ -394,15 +418,54 @@ function SampleHierarchy(serverFacade, inspector, containerId, profile, sample) .nodeSep(20) .rankDir("TB"); - var layout = renderer.layout(layout).run(g, svg.select('g')); - transition(d3.select('svg')) + //Render Layout + renderer.layout(layout).run(g, svgG); + transition(d3.select('#svgMapContainer')) .attr('width', $(document).width() - 30) .attr('height', $(document).height() - 120) - d3.select('svg') + d3.select('#svgMapContainer') .call(d3.behavior.zoom().on('zoom', function() { var ev = d3.event; - svg.select('g').attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')'); - })); + svgG.attr('transform', 'translate(' + ev.translate + ') scale(' + ev.scale + ')'); + })).on("dblclick.zoom", null); } + + this._makeSVG = function(tag, attrs) { + var el= document.createElementNS('http://www.w3.org/2000/svg', tag); + for (var k in attrs) + el.setAttribute(k, attrs[k]); + return el; + } + + // + // Zoom and Pan controls + // + this.pan = function(dx, dy) + { + var svgTransform = d3.select('#svgMap').attr("transform"); + + var svgTransformTranslate = /translate\(\s*([^\s,)]+)[ ,]([^\s,)]+)/.exec(svgTransform); + var translateX = parseFloat(svgTransformTranslate[1]) + dx; + var translateY = parseFloat(svgTransformTranslate[2]) + dy; + + var svgTransformScale = /scale\(([^\s,)]+)/.exec(svgTransform); + var scaleRatio = parseFloat(svgTransformScale[1]); + + d3.select('#svgMap').attr('transform', 'translate(' + translateX + ',' + translateY + ') scale(' + scaleRatio + ')'); + } + + this.zoom = function(scale) + { + var svgTransform = d3.select('#svgMap').attr("transform"); + + var svgTransformTranslate = /translate\(\s*([^\s,)]+)[ ,]([^\s,)]+)/.exec(svgTransform); + var translateX = parseFloat(svgTransformTranslate[1]); + var translateY = parseFloat(svgTransformTranslate[2]); + + var svgTransformScale = /scale\(([^\s,)]+)/.exec(svgTransform); + var scaleRatio = parseFloat(svgTransformScale[1]) * scale; + + d3.select('#svgMap').attr('transform', 'translate(' + translateX + ',' + translateY + ') scale(' + scaleRatio + ')'); + } } -- GitLab