From c00b602e1002f2ecf09a0370196926fd4ad12ec5 Mon Sep 17 00:00:00 2001 From: Eike Cochu <eike@cochu.com> Date: Thu, 2 Jun 2016 12:08:06 +0200 Subject: [PATCH] explorer resizable layout --- vipra-ui/app/html/explorer.html | 150 ++++++++++++++++---------------- vipra-ui/app/js/controllers.js | 44 ++++++++-- vipra-ui/app/js/directives.js | 3 +- vipra-ui/app/less/app.less | 21 +++-- vipra-ui/gulpfile.js | 7 +- 5 files changed, 130 insertions(+), 95 deletions(-) diff --git a/vipra-ui/app/html/explorer.html b/vipra-ui/app/html/explorer.html index f7b6bad7..f6f84ae3 100644 --- a/vipra-ui/app/html/explorer.html +++ b/vipra-ui/app/html/explorer.html @@ -1,6 +1,6 @@ -<div class="fullsize navpadding container-fluid explorer" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'explorer'"> - <div class="row row-50"> - <div class="sidebar"> +<div class="fullsize navpadding explorer" ng-cloak ng-hide="!rootModels.topicModel || state.name !== 'explorer'" id="outer"> + <div class="ui-layout-center no-padding no-border" id="upper"> + <div class="ui-layout-west explorer-sidebar no-border"> <div class="btn-group btn-group-justified" role="group" aria-label="..."> <a tabindex="0" class="btn btn-sm btn-default" ng-click="checkTopics(true)" title="Select all topics">All</a> <a tabindex="0" class="btn btn-sm btn-default" ng-click="checkTopics(false)" title="Deselect all topics">None</a> @@ -43,37 +43,35 @@ </li> </ul> </div> - <div class="center"> - <div class="wrapper"> - <div class="topbar"> - <small>Values:</small> - <div class="btn-group"> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'absolute'">Absolute</a> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'relative'">Relative</a> - </div> - - <small>Chart:</small> - <div class="btn-group"> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'areaspline'">Area</a> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'spline'">Line</a> - </div> - - <small>Stacking:</small> - <div class="btn-group"> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'none'">None</a> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'normal'">Value</a> - <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'percent'">Percent</a> - </div> - <div class="pull-right"> - <a tabindex="0" class="btn btn-sm btn-default" ng-click="resetZoom()" ng-show="topicsSelected" ng-cloak>Reset zoom</a> - </div> + <div class="ui-layout-center no-padding no-border"> + <div class="topbar"> + <small>Values:</small> + <div class="btn-group"> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'absolute'">Absolute</a> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.seqstyle" bs-radio="'relative'">Relative</a> + </div> + + <small>Chart:</small> + <div class="btn-group"> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'areaspline'">Area</a> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstyle" bs-radio="'spline'">Line</a> + </div> + + <small>Stacking:</small> + <div class="btn-group"> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'none'">None</a> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'normal'">Value</a> + <a tabindex="0" class="btn btn-sm btn-default" ng-model="explorerModels.chartstack" bs-radio="'percent'">Percent</a> + </div> + <div class="pull-right"> + <a tabindex="0" class="btn btn-sm btn-default" ng-click="resetZoom()" ng-show="topicsSelected" ng-cloak>Reset zoom</a> </div> - <div id="topicRelChart" class="chart" highcharts="topicSeq" style="height:500px"></div> </div> + <div id="topicRelChart" class="chart" highcharts="topicSeq" style="height:500px"></div> </div> </div> - <div class="row row-50"> - <div class="sidebar"> + <div class="ui-layout-south no-padding no-border" id="lower"> + <div class="ui-layout-west explorer-sidebar no-border"> <ul class="list-unstyled item-choice no-offset"> <li ng-repeat="topic in selectedTopics = (topics | filter:{selected: true} | filter:search | orderBy:explorerModels.sorttopics:explorerModels.sortdir)" ng-mouseenter="highlightSeries(topic.id, true)" ng-mouseleave="highlightSeries(topic.id, false)" ng-class="{active:explorerModels.activeTopic.id===topic.id}" class="pointer text-muted"> <div class="radio radio-condensed"> @@ -93,54 +91,52 @@ </li> </ul> </div> - <div class="center"> - <div class="wrapper"> - <div class="topbar tabs"> - <ul class="nav nav-tabs" role="tablist"> - <li class="active"> - <a data-target=".tab-evolution" data-toggle="tab" bs-tab>Word Evolution</a> - </li> - <li> - <a data-target=".tab-articles" data-toggle="tab" bs-tab>Articles</a> - </li> - </ul> + <div class="ui-layout-center no-padding no-border"> + <div class="topbar tabs"> + <ul class="nav nav-tabs" role="tablist"> + <li class="active"> + <a data-target=".tab-evolution" data-toggle="tab" bs-tab>Word Evolution</a> + </li> + <li> + <a data-target=".tab-articles" data-toggle="tab" bs-tab>Articles</a> + </li> + </ul> + </div> + <div class="tab-content fullsize"> + <div role="tabpanel" class="tab-pane active tab-evolution"> + <word-evolution chart-id="wordEvoChart" topic="explorerModels.activeTopic"/> </div> - <div class="tab-content fullsize"> - <div role="tabpanel" class="tab-pane active tab-evolution"> - <word-evolution topic="explorerModels.activeTopic"/> - </div> - <div role="tabpanel" class="tab-pane tab-articles auto-overflow"> - <div class="panel panel-default"> - <div class="topbar"> - <small>Sequence:</small> - <sequence-dropdown ng-model="explorerModels.activeSequence" sequences="explorerModels.activeTopic.sequences"></sequence-dropdown> - <button class="btn btn-sm btn-default" ng-click="clearSequence()" ng-disabled="!explorerModels.activeSequence">Clear</button> - </div> - <table class="table table-bordered table-condensed table-fixed"> - <thead> - <tr> - <th ng-model="explorerModels.articlesSort" sort-by="title">Article</th> - </tr> - </thead> - <tbody> - <tr ng-repeat="article in articles | orderBy:explorerModels.articlesSort"> - <td> - <article-link article="::article" /> - </td> - </tr> - <tr ng-show="loadingArticles"> - <td>Loading...</td> - </tr> - <tr ng-show="!loadingArticles&&!articles.length"> - <td>No Articles</td> - </tr> - </tbody> - </table> - <div class="panel-footer"> - <ng-pluralize count="articles.length" when="{0:'No articles',1:'First entity',other:'First {} articles'}"></ng-pluralize> - <button class="btn btn-default btn-sm" ng-click="showMoreArticles()" ng-show="articles.length<articlesTotal" ng-cloak>Show more</button> - <button class="btn btn-default btn-sm" ng-click="showAllArticles()" ng-show="articles.length<articlesTotal" ng-cloak>Show all</button> - </div> + <div role="tabpanel" class="tab-pane tab-articles auto-overflow"> + <div class="panel panel-default"> + <div class="topbar"> + <small>Sequence:</small> + <sequence-dropdown ng-model="explorerModels.activeSequence" sequences="explorerModels.activeTopic.sequences"></sequence-dropdown> + <button class="btn btn-sm btn-default" ng-click="clearSequence()" ng-disabled="!explorerModels.activeSequence">Clear</button> + </div> + <table class="table table-bordered table-condensed table-fixed"> + <thead> + <tr> + <th ng-model="explorerModels.articlesSort" sort-by="title">Article</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="article in articles | orderBy:explorerModels.articlesSort"> + <td> + <article-link article="::article" /> + </td> + </tr> + <tr ng-show="loadingArticles"> + <td>Loading...</td> + </tr> + <tr ng-show="!loadingArticles&&!articles.length"> + <td>No Articles</td> + </tr> + </tbody> + </table> + <div class="panel-footer"> + <ng-pluralize count="articles.length" when="{0:'No articles',1:'First entity',other:'First {} articles'}"></ng-pluralize> + <button class="btn btn-default btn-sm" ng-click="showMoreArticles()" ng-show="articles.length<articlesTotal" ng-cloak>Show more</button> + <button class="btn btn-default btn-sm" ng-click="showAllArticles()" ng-show="articles.length<articlesTotal" ng-cloak>Show all</button> </div> </div> </div> diff --git a/vipra-ui/app/js/controllers.js b/vipra-ui/app/js/controllers.js index 590242e0..31e0a483 100644 --- a/vipra-ui/app/js/controllers.js +++ b/vipra-ui/app/js/controllers.js @@ -669,6 +669,38 @@ if (!$scope.rootModels.topicModel) $scope.chooseTopicModel(); + $scope.reflowCharts = function() { + var topicHC = $('#topicRelChart').highcharts(); + if (topicHC) topicHC.reflow(); + var wordHC = $('#wordEvoChart').highcharts(); + if (wordHC) wordHC.reflow(); + }; + + $timeout(function() { + $('#outer').layout({ + applyDefaultStyles: true, + south__size: '50%' + }); + $('#upper').layout({ + applyDefaultStyles: true, + center__onresize: function() { + $scope.reflowCharts(); + }, + west: { + size: 250 + } + }); + $('#lower').layout({ + applyDefaultStyles: true, + center__onresize: function() { + $scope.reflowCharts(); + }, + west: { + size: 250 + } + }); + }); + var avgMax = 0, varMax = 0, fallingMax = 0, @@ -792,10 +824,9 @@ return (percent * 100) + '%'; }; - var topicRelChartElement = $('#topicRelChart'); $scope.highlightSeries = function(id, toggle) { if (!$scope.topicsSelected) return; - var highcharts = topicRelChartElement.highcharts(); + var highcharts = $('#topicRelChart').highcharts(); if (!highcharts) return; var series = highcharts.get(id); if (!series) return; @@ -814,7 +845,7 @@ $scope.resetZoom = function() { if (!$scope.topicsSelected) return; - var highcharts = topicRelChartElement.highcharts(); + var highcharts = $('#topicRelChart').highcharts(); if (!highcharts) return; highcharts.xAxis[0].setExtremes(null, null); @@ -840,7 +871,7 @@ delete $scope.explorerModels.activeSequence; delete $scope.articles; - var selectedPoints = topicRelChartElement.highcharts().getSelectedPoints(); + var selectedPoints = $('#topicRelChart').highcharts().getSelectedPoints(); for(var i = 0; i < selectedPoints.length; i++) { selectedPoints[i].select(false); } @@ -1204,10 +1235,9 @@ }], 'Topic Relevance', $scope.topicsShowModels.relChartstyle); }; - var topicRelChartElement = $('#topicRelChart'); $scope.resetRelZoom = function() { if (!$scope.topic) return; - var highcharts = topicRelChartElement.highcharts(); + var highcharts = $('#topicRelChart').highcharts(); if (!highcharts) return; highcharts.xAxis[0].setExtremes(null, null); @@ -1667,7 +1697,7 @@ app.controller('WordEvolutionController', ['$scope', function($scope) { - $scope.chartId = Vipra.randomId(); + $scope.chartId = $scope.chartId || Vipra.randomId(); $scope.wordSeqstyle = 'absolute'; $scope.wordChartstyle = 'spline'; diff --git a/vipra-ui/app/js/directives.js b/vipra-ui/app/js/directives.js index 6b79e440..7d0db883 100644 --- a/vipra-ui/app/js/directives.js +++ b/vipra-ui/app/js/directives.js @@ -498,7 +498,8 @@ app.directive('wordEvolution', [function() { return { scope: { - topic: '=' + topic: '=', + chartId: '@' }, replace: true, controller: 'WordEvolutionController', diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index a08f5295..45677f85 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -327,6 +327,10 @@ a:hover { } } +.explorer-sidebar { + background: @bar-color !important; + padding: @sidebar-padding !important; +} .sidebar { background: @bar-color; padding: @sidebar-padding; @@ -686,15 +690,6 @@ entity-menu { } } -.row-50 { - height: 50%; - position: relative; - - & + & { - border-top: 1px solid #888; - } -} - .excerpt { padding-top: 10px; color: #555; @@ -927,6 +922,14 @@ entity-menu { } } +.no-border { + border: 0 !important; +} + +.no-padding { + padding: 0 !important; +} + @keyframes spin { 100% { -webkit-transform: rotateY(360deg); diff --git a/vipra-ui/gulpfile.js b/vipra-ui/gulpfile.js index 28223ec7..4a08eb00 100644 --- a/vipra-ui/gulpfile.js +++ b/vipra-ui/gulpfile.js @@ -13,6 +13,10 @@ var gulp = require('gulp'), var assets = { js: [ 'bower_components/jquery/dist/jquery.min.js', + 'bower_components/jquery-ui/ui/core.js', + 'bower_components/jquery-ui/ui/widget.js', + 'bower_components/jquery-ui/ui/mouse.js', + 'bower_components/jquery-ui/ui/draggable.js', 'bower_components/angular/angular.min.js', 'bower_components/angular-resource/angular-resource.min.js', 'bower_components/angular-sanitize/angular-sanitize.min.js', @@ -30,7 +34,8 @@ var assets = { 'bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js', 'bower_components/reconnectingWebsocket/reconnecting-websocket.min.js', 'bower_components/angulartics/dist/angulartics.min.js', - 'bower_components/angulartics-google-analytics/dist/angulartics-google-analytics.min.js' + 'bower_components/angulartics-google-analytics/dist/angulartics-google-analytics.min.js', + 'bower_components/jquery-layout/source/stable/jquery.layout.min.js' ], css: [ 'bower_components/bootstrap/dist/css/bootstrap.min.css', -- GitLab