You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kylin.apache.org by nj...@apache.org on 2017/12/02 17:24:10 UTC

[17/19] kylin git commit: APACHE-KYLIN-2843 Upgrade nvd3 version

APACHE-KYLIN-2843 Upgrade nvd3 version


Project: http://git-wip-us.apache.org/repos/asf/kylin/repo
Commit: http://git-wip-us.apache.org/repos/asf/kylin/commit/c27455fa
Tree: http://git-wip-us.apache.org/repos/asf/kylin/tree/c27455fa
Diff: http://git-wip-us.apache.org/repos/asf/kylin/diff/c27455fa

Branch: refs/heads/master
Commit: c27455fa3b26837d1f0777814b0ae2ac3b8a231f
Parents: 4e8e2f7
Author: liapan <li...@ebay.com>
Authored: Fri Nov 17 14:43:46 2017 +0800
Committer: Zhong <nj...@apache.org>
Committed: Sat Dec 2 23:43:43 2017 +0800

----------------------------------------------------------------------
 webapp/app/index.html                       |   9 +-
 webapp/app/js/app.js                        |   2 +-
 webapp/app/js/controllers/query.js          | 110 ++++++++++++------
 webapp/app/js/factories/graph.js            |  77 -------------
 webapp/app/js/model/queryConfig.js          | 139 +++++++++++++++++++++++
 webapp/app/js/services/graph.js             |  54 ---------
 webapp/app/partials/query/query_detail.html | 100 ++++------------
 webapp/bower.json                           |   8 +-
 webapp/grunt.json                           |   6 +-
 9 files changed, 251 insertions(+), 254 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/index.html
----------------------------------------------------------------------
diff --git a/webapp/app/index.html b/webapp/app/index.html
index 407f179..d235b06 100644
--- a/webapp/app/index.html
+++ b/webapp/app/index.html
@@ -45,7 +45,7 @@
   <link rel="stylesheet" type="text/css" href="components/chosen/chosen.css">
   <link rel="stylesheet" type="text/css" href="components/angular-chosen-localytics/chosen-spinner.css">
   <link rel="stylesheet" type="text/css" href="components/animate.css/animate.css">
-  <link rel="stylesheet" type="text/css" href="components/nvd3/nv.d3.min.css">
+  <link rel="stylesheet" type="text/css" href="components/nvd3/build/nv.d3.min.css">
 
   <link rel="stylesheet" type="text/css" href="css/AdminLTE.css">
   <link rel="stylesheet" type="text/css" href="components/bootstrap-sweetalert/lib/sweet-alert.css">
@@ -102,8 +102,7 @@
 
 <script src="components/moment/moment.js"></script>
 <script src="components/d3/d3.min.js"></script>
-<script src="components/nvd3/nv.d3.min.js"></script>
-<script src="components/angularjs-nvd3-directives/dist/angularjs-nvd3-directives.js"></script>
+<script src="components/nvd3/build/nv.d3.min.js"></script>
 <script src="components/bootstrap-sweetalert/lib/sweet-alert.js"></script>
 <script src="components/angular-sweetalert/SweetAlert.js"></script>
 <script src="components/underscore/underscore.js"></script>
@@ -112,6 +111,7 @@
 <script src="components/angular-ui-sortable/sortable.js"></script>
 <script src="components/angular-toggle-switch/angular-toggle-switch.js"></script>
 <script src="components/angular-sanitize/angular-sanitize.js"></script>
+<script src="components/angular-nvd3/dist/angular-nvd3.min.js"></script>
 
 <script src="js/app.js"></script>
 <script src="js/config.js"></script>
@@ -124,7 +124,6 @@
 <script src="js/directives/select.js"></script>
 <script src="js/directives/ui-grid.js"></script>
 
-<script src="js/factories/graph.js"></script>
 <script src="js/services/cache.js"></script>
 <script src="js/services/message.js"></script>
 <script src="js/services/access.js"></script>
@@ -136,7 +135,6 @@
 <script src="js/services/encodings.js"></script>
 <script src="js/services/cubes.js"></script>
 <script src="js/services/streaming.js"></script>
-<script src="js/services/graph.js"></script>
 <script src="js/services/jobs.js"></script>
 <script src="js/services/message.js"></script>
 <script src="js/services/projects.js"></script>
@@ -164,6 +162,7 @@
 <script src="js/model/cubeListModel.js"></script>
 <script src="js/model/jobListModel.js"></script>
 <script src="js/model/cubesManager.js"></script>
+<script src="js/model/queryConfig.js"></script>
 
 <!--New GUI-->
 <script src="js/model/modelsManager.js"></script>

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/js/app.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/app.js b/webapp/app/js/app.js
index 629617e..44a91ed 100644
--- a/webapp/app/js/app.js
+++ b/webapp/app/js/app.js
@@ -17,4 +17,4 @@
  */
 
 //Kylin Application Module
-KylinApp = angular.module('kylin', ['ngRoute', 'ngResource', 'ngGrid', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.grouping', 'ui.bootstrap', 'ui.ace', 'base64', 'angularLocalStorage', 'localytics.directives', 'treeControl', 'nvd3ChartDirectives', 'ngLoadingRequest', 'oitozero.ngSweetAlert', 'ngCookies', 'angular-underscore', 'ngAnimate', 'ui.sortable', 'angularBootstrapNavTree', 'toggle-switch', 'ngSanitize', 'ui.select', 'ui.bootstrap.datetimepicker']);
+KylinApp = angular.module('kylin', ['ngRoute', 'ngResource', 'ngGrid', 'ui.grid', 'ui.grid.resizeColumns', 'ui.grid.grouping', 'ui.bootstrap', 'ui.ace', 'base64', 'angularLocalStorage', 'localytics.directives', 'treeControl', 'ngLoadingRequest', 'oitozero.ngSweetAlert', 'ngCookies', 'angular-underscore', 'ngAnimate', 'ui.sortable', 'angularBootstrapNavTree', 'toggle-switch', 'ngSanitize', 'ui.select', 'ui.bootstrap.datetimepicker', 'nvd3']);

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/js/controllers/query.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/controllers/query.js b/webapp/app/js/controllers/query.js
index 945ddef..4014093 100644
--- a/webapp/app/js/controllers/query.js
+++ b/webapp/app/js/controllers/query.js
@@ -282,15 +282,6 @@ KylinApp
             $scope.query($scope.curQuery);
         }
 
-        $scope.resetGraph = function (query) {
-            var dimension = (query.graph.meta.dimensions && query.graph.meta.dimensions.length > 0) ? query.graph.meta.dimensions[0] : null;
-            var metrics = (query.graph.meta.metrics && query.graph.meta.metrics.length > 0) ? query.graph.meta.metrics[0] : null;
-            query.graph.state = {
-                dimensions: dimension,
-                metrics: ((query.graph.type.metrics.multiple) ? [metrics] : metrics)
-            };
-        }
-
         $scope.loadMore = function (query) {
             query.result.loading = true;
             var query = query;
@@ -424,7 +415,7 @@ KylinApp
 
 
     })
-    .controller('QueryResultCtrl', function ($scope, storage, $base64, $q, $location, $anchorScroll, $routeParams, QueryService, GraphService) {
+    .controller('QueryResultCtrl', function ($scope, storage, $base64, $q, $location, $anchorScroll, $routeParams, QueryService, queryConfig) {
         $scope.buildGraphMetadata = function (query) {
             if (!query.graph.show) {
                 return;
@@ -467,34 +458,85 @@ KylinApp
             return $scope.curQuery.graph.type.dimension.types.indexOf(dimension.type) > -1;
         }
 
-        $scope.refreshGraphData = function (query) {
-            if (query.graph.show) {
-                query.graph.data = GraphService.buildGraph(query);
-            }
-            else {
-                query.graph.data = [];
-            }
+        $scope.resetGraph = function (query) {
+            var dimension = (query.graph.meta.dimensions && query.graph.meta.dimensions.length > 0) ? query.graph.meta.dimensions[0] : null;
+            var metrics = (query.graph.meta.metrics && query.graph.meta.metrics.length > 0) ? query.graph.meta.metrics[0] : null;
+            query.graph.state = {
+                dimensions: dimension,
+                metrics: ((query.graph.type.metrics.multiple) ? [metrics] : metrics)
+            };
+            $scope.refreshGraphData(query);
         }
 
-        $scope.xAxisTickFormatFunction = function () {
-            return function (d) {
-                return d3.time.format("%Y-%m-%d")(moment.unix(d).toDate());
-            }
-        };
+        $scope.refreshGraphData = function (query) {
+            if (query.graph.show) {
+                $scope.chart = undefined;
+
+                var selectedDimension = query.graph.state.dimensions;
+                if (selectedDimension && query.graph.type.dimension.types.indexOf(selectedDimension.type) > -1) {
+                    $scope.chart = {};
+
+                    var chartType = query.graph.type.value;
+                    var selectedMetric = query.graph.state.metrics;
+
+                    var dataValues = [];
+                    angular.forEach(query.result.results, function(result, ind) {
+                        var data = {
+                            label: result[selectedDimension.index],
+                            value: parseFloat(result[selectedMetric.index])
+                        };
+                        if (selectedDimension.type === 'date' && chartType === 'line') {
+                            data.label = parseInt(moment(data.label).format('X'));
+                        }
+                        dataValues.push(data);
+                    });
 
-        $scope.xFunction = function () {
-            return function (d) {
-                return d.key;
-            }
-        };
+                    dataValues = _.sortBy(dataValues, 'label');
+                    var oldLabel = dataValues[0].label;
+                    var groupValues = [{label: dataValues[0].label, value: 0}];
+                    angular.forEach(dataValues, function(data) {
+                        if (data.label === oldLabel) {
+                            groupValues[groupValues.length-1].value += data.value;
+                        } else {
+                            groupValues.push(data);
+                            oldLabel = data.label;
+                        }
+                    });
 
-        $scope.yFunction = function () {
-            return function (d) {
-                return d.y;
+                    $scope.chart.data = [{
+                        key: selectedMetric.column.label,
+                        values: groupValues
+                    }];
+
+                    if (chartType === 'line') {
+                        $scope.chart.options = angular.copy(queryConfig.lineChartOptions);
+                        if (selectedDimension.type === 'date') {
+                            $scope.chart.options.chart.xAxis.tickFormat = function (d) {
+                                return d3.time.format('%Y-%m-%d')(moment.unix(d).toDate());
+                            };
+                        }
+                    } else if (chartType === 'bar') {
+                        $scope.chart.options = angular.copy(queryConfig.barChartOptions);
+                        if (groupValues.length > 15) {
+                            $scope.chart.options.chart.showLegend = false;
+                            $scope.chart.options.chart.xAxis.height = 100;
+                            $scope.chart.options.chart.margin.bottom =  150;
+                            $scope.chart.options.chart.xAxis.rotateLabels = -90;
+                            if (groupValues.length > 50) {
+                                $scope.chart.options.chart.showXAxis = false;
+                            }
+                        }
+                    } else if (chartType === 'pie') {
+                        $scope.chart.options = angular.copy(queryConfig.pieChartOptions);
+                        $scope.chart.data = groupValues;
+                        if (groupValues.length > 15) {
+                            $scope.chart.options.chart.showLegend = false;
+                            $scope.chart.options.chart.showLabels = false;
+                        }
+                    }
+                }
+            } else {
+                $scope.chart.data = [];
             }
         }
-
-        $scope.$on('elementClick.directive', function (angularEvent, event) {
-            console.log('clicked.');
-        });
     });

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/js/factories/graph.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/factories/graph.js b/webapp/app/js/factories/graph.js
deleted file mode 100644
index e02e13a..0000000
--- a/webapp/app/js/factories/graph.js
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-KylinApp.factory('GraphBuilder', function () {
-  var graphBuilder = {};
-
-  graphBuilder.buildLineGraph = function (dimension, metrics, aggregatedData) {
-    var values = [];
-    angular.forEach(getSortedKeys(aggregatedData), function (sortedKey, index) {
-      values.push([(dimension.type == 'date') ? moment(sortedKey).unix() : sortedKey, aggregatedData[sortedKey]]);
-    });
-
-    var newGraph = [
-      {
-        "key": metrics.column.label,
-        "values": values
-      }
-    ];
-
-    return newGraph;
-  }
-
-  graphBuilder.buildBarGraph = function (dimension, metrics, aggregatedData) {
-    var newGraph = [];
-    angular.forEach(getSortedKeys(aggregatedData), function (sortedKey, index) {
-      newGraph.push({
-        key: sortedKey,
-        values: [
-          [sortedKey, aggregatedData[sortedKey]]
-        ]
-      });
-    });
-
-    return newGraph;
-  }
-
-  graphBuilder.buildPieGraph = function (dimension, metrics, aggregatedData) {
-    var newGraph = [];
-    angular.forEach(getSortedKeys(aggregatedData), function (sortedKey, index) {
-      newGraph.push({
-        key: sortedKey,
-        y: aggregatedData[sortedKey]
-      });
-    });
-
-    return newGraph;
-  }
-
-  function getSortedKeys(results) {
-    var sortedKeys = [];
-    for (var k in results) {
-      if (results.hasOwnProperty(k)) {
-        sortedKeys.push(k);
-      }
-    }
-    sortedKeys.sort();
-
-    return sortedKeys;
-  }
-
-  return graphBuilder;
-});

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/js/model/queryConfig.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/model/queryConfig.js b/webapp/app/js/model/queryConfig.js
new file mode 100644
index 0000000..2f92f57
--- /dev/null
+++ b/webapp/app/js/model/queryConfig.js
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+
+KylinApp.constant('queryConfig', {
+  lineChartOptions: {
+    chart: {
+      type: 'lineChart',
+      height: 500,
+      margin : {
+        top: 20,
+        right: 55,
+        bottom: 60,
+        left: 55
+      },
+      useInteractiveGuideline: true,
+      interpolate: 'cardinal',
+      x: function(d){return d.label;},
+      y: function(d){return d.value;},
+      xAxis: {
+        axisLabelDistance: 50,
+        staggerLabels: false,
+        tickFormat: function(d) {
+          if (d.length > 10) {
+            return d.substring(0,10) + '...';
+          } else {
+            return d;
+          }
+        }
+      },
+      yAxis: {
+        tickFormat: function(d) {
+          if (d < 1000) {
+            if (parseFloat(d) === d) {
+              return d3.format('.1')(d);
+            } else {
+              return d3.format('.2f')(d);
+            }
+          } else {
+            var prefix = d3.formatPrefix(d);
+            return prefix.scale(d) + prefix.symbol;
+          }
+        },
+        showMaxMin: false
+      },
+      valueFormat: function(d){
+        return d3.format('.1')(d);
+      },
+      transitionDuration: 500,
+      tooltipContent: function (key, x, y, e, graph) {
+        return '<h3>' + e.point.label + '</h3>' + '<p>' +  y + '</p>';
+      }
+    }
+  },
+  barChartOptions: {
+    chart: {
+      type: 'discreteBarChart',
+      height: 500,
+      margin : {
+        top: 20,
+        right: 20,
+        bottom: 60,
+        left: 55
+      },
+      x: function(d){return d.label;},
+      y: function(d){return d.value;},
+      xAxis: {
+        axisLabelDistance: 50,
+        staggerLabels: false,
+        tickFormat: function(d) {
+          if (d.length > 10) {
+            return d.substring(0,10) + '...';
+          } else {
+            return d;
+          }
+        }
+      },
+      yAxis: {
+        tickFormat: function(d) {
+          if (d < 1000) {
+            if (parseFloat(d) === d) {
+              return d3.format('.1')(d);
+            } else {
+              return d3.format('.2f')(d);
+            }
+          } else {
+            var prefix = d3.formatPrefix(d);
+            return prefix.scale(d) + prefix.symbol;
+          }
+        },
+        showMaxMin: false
+      },
+      valueFormat: function(d){
+        return d3.format('.1')(d);
+      },
+      transitionDuration: 500,
+      tooltipContent: function (key, x, y, e, graph) {
+        return '<h3>' + e.point.label + '</h3>' + '<p>' +  y + '</p>';
+      }
+    }
+  },
+  pieChartOptions: {
+    chart: {
+      type: 'pieChart',
+      height: 500,
+      showLabels: true,
+      duration: 500,
+      labelThreshold: 0.01,
+      labelSunbeamLayout: true,
+      legend: {
+        margin : {
+          top: 20,
+          right: 20,
+          bottom: 60,
+          left: 55
+        }
+      },
+      x: function(d){return d.label;},
+      y: function(d){return d.value;},
+      valueFormat: function(d){
+        return d3.format('.1')(d);
+      }
+    }
+  }
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/js/services/graph.js
----------------------------------------------------------------------
diff --git a/webapp/app/js/services/graph.js b/webapp/app/js/services/graph.js
deleted file mode 100644
index dc69519..0000000
--- a/webapp/app/js/services/graph.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-KylinApp.service('GraphService', function (GraphBuilder, VdmUtil) {
-
-  this.buildGraph = function (query) {
-    var graphData = null;
-    var dimension = query.graph.state.dimensions;
-
-    if (dimension && query.graph.type.dimension.types.indexOf(dimension.type) > -1) {
-      var metricsList = [];
-      metricsList = metricsList.concat(query.graph.state.metrics);
-      angular.forEach(metricsList, function (metrics, index) {
-        var aggregatedData = {};
-        angular.forEach(query.result.results,function(row,index){
-          angular.forEach(row,function(column,value){
-            var float = VdmUtil.SCToFloat(column);
-              if (float!=""){
-                query.result.results[index][value]=float;
-              }
-          });
-        });
-        angular.forEach(query.result.results, function (data, index) {
-          aggregatedData[data[dimension.index]] = (!!aggregatedData[data[dimension.index]] ? aggregatedData[data[dimension.index]] : 0)
-          + parseFloat(data[metrics.index].replace(/[^\d\.\-]/g, ""));
-        });
-
-        var newData = GraphBuilder["build" + capitaliseFirstLetter(query.graph.type.value) + "Graph"](dimension, metrics, aggregatedData);
-        graphData = (!!graphData) ? graphData.concat(newData) : newData;
-      });
-    }
-
-    return graphData;
-  }
-
-  function capitaliseFirstLetter(string) {
-    return string.charAt(0).toUpperCase() + string.slice(1);
-  }
-});

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/app/partials/query/query_detail.html
----------------------------------------------------------------------
diff --git a/webapp/app/partials/query/query_detail.html b/webapp/app/partials/query/query_detail.html
index 5668f10..0532b19 100644
--- a/webapp/app/partials/query/query_detail.html
+++ b/webapp/app/partials/query/query_detail.html
@@ -82,7 +82,7 @@
       </button>
       </span>
     <div class="pull-right" ng-if="curQuery.status=='success'">
-        <button class="btn btn-default btn-xs"  ng-click="curQuery.graph.show=!curQuery.graph.show;buildGraphMetadata(curQuery);resetGraph(curQuery);refreshGraphData(curQuery)">
+        <button class="btn btn-default btn-xs"  ng-click="curQuery.graph.show=!curQuery.graph.show;buildGraphMetadata(curQuery);resetGraph(curQuery)">
             <span ng-if="!curQuery.graph.show"><i class="fa fa-bar-chart-o"></i> Visualization</span>
             <span ng-if="curQuery.graph.show"><i class="fa fa-list-ul"></i> Grid</span>
         </button>
@@ -126,102 +126,50 @@
     </div>
 
     <div ng-if="curQuery.graph.show" class="row">
-        <div class="col-xs-4 col-lg-3">
+        <div class="col-xs-4">
             <div class="graph_content">
                 <label>Graph Type</label>
-
-                <select ng-model="curQuery.graph.type"
-                        ng-change="resetGraph(curQuery);refreshGraphData(curQuery)"
+                <div>
+                    <select chosen style="width: 100%;"
+                        ng-model="curQuery.graph.type"
+                        ng-change="resetGraph(curQuery)"
                         ng-options="type as type.name for type in chartTypes"></select>
+                </div>
             </div>
-
+        </div>
+        <div class="col-xs-4">
             <div class="graph_content">
                 <label>Dimensions</label>
                 <div>
-                    <select
-                            chosen style="width: 100%;"
+                    <select chosen style="width: 100%;"
                             ng-model="curQuery.graph.state.dimensions" ng-change="refreshGraphData(curQuery)"
                             ng-options="dimension as dimension.column.label for dimension in curQuery.graph.meta.dimensions | filter: mappingToChartype">
                         <option value="">-- choose dimension --</option>
                     </select>
                 </div>
             </div>
-
+        </div>
+        <div class="col-xs-4">
             <div class="graph_content">
                 <label>Metrics</label>
-
-                <div class="chosen-relative">
-                    <select ng-if="curQuery.graph.type.metrics.multiple"
-                            chosen style="width: 100%;"
-                            multiple
-                            data-placeholder="Select Metrics.."
-                            ng-model="curQuery.graph.state.metrics"
-                            ng-options="metrics as metrics.column.label for metrics in curQuery.graph.meta.metrics"
-                            ng-change="refreshGraphData(curQuery)">
-                        <option value="">-- choose metrics --</option>
-                    </select>
-                    <select ng-if="!curQuery.graph.type.metrics.multiple"
-                            chosen style="width: 100%"
-                            data-placeholder="Select Metrics.."
-                            ng-model="curQuery.graph.state.metrics"
-                            ng-options="metrics as metrics.column.label for metrics in curQuery.graph.meta.metrics"
-                            ng-change="refreshGraphData(curQuery)">
+                <div>
+                  <select chosen style="width: 100%;"
+                          data-placeholder="Select Metrics.."
+                          ng-model="curQuery.graph.state.metrics"
+                          ng-options="metrics as metrics.column.label for metrics in curQuery.graph.meta.metrics"
+                          ng-change="refreshGraphData(curQuery)">
                         <option value="">-- choose metrics --</option>
                     </select>
                 </div>
             </div>
         </div>
-
-        <div class="col-xs-8 col-lg-9">
-            <div ng-if="curQuery.graph.data.length > 0">
-                <div ng-if="curQuery.graph.type.value == 'bar'">
-                    <nvd3-multi-bar-chart
-                            data="curQuery.graph.data"
-                            height="{{curQuery.graph.data.length * 5 + 250}}"
-                            showXAxis="true"
-                            showYAxis="true"
-                            noData="No Graph"
-                            showLegend="true"
-                            interactive="true"
-                            tooltips="true"
-                            >
-                        <svg></svg>
-                    </nvd3-multi-bar-chart>
-                </div>
-
-                <div ng-if="curQuery.graph.type.value == 'line'">
-                    <nvd3-line-chart
-                            height="350"
-                            data="curQuery.graph.data"
-                            xAxisTickFormat="xAxisTickFormatFunction()"
-                            showXAxis="true"
-                            showYAxis="true"
-                            noData="No Graph"
-                            clipVoronoi="true"
-                            interactive="true"
-                            tooltips="true"
-                            >
-                        <svg></svg>
-                    </nvd3-line-chart>
-                </div>
-
-                <div ng-if="curQuery.graph.type.value == 'pie'">
-                    <nvd3-pie-chart
-                            data="curQuery.graph.data"
-                            height="{{ curQuery.graph.data.length | resizePieHeight }}"
-                            x="xFunction()"
-                            y="yFunction()"
-                            noData="No Graph"
-                            tooltips="true"
-                            showLabels="true"
-                            showLegend="true"
-                            >
-                        <svg></svg>
-                    </nvd3-pie-chart>
-                </div>
+    </div>
+    <div ng-if="curQuery.graph.show" class="row">
+         <div class="col-xs-12">
+            <div ng-if="chart">
+                <nvd3 options="chart.options" data="chart.data"></nvd3>
             </div>
-
-            <div ng-if="!curQuery.graph.data || curQuery.graph.data.length == 0" style="padding-top: 10%">
+             <div ng-if="!chart" style="padding-top: 10%">
                 <div no-result text="No Graph Generated."></div>
             </div>
         </div>

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/bower.json
----------------------------------------------------------------------
diff --git a/webapp/bower.json b/webapp/bower.json
index 4d5a311..eac2cb3 100755
--- a/webapp/bower.json
+++ b/webapp/bower.json
@@ -19,8 +19,7 @@
     "messenger": "1.4.1",
     "moment": "2.5.1",
     "d3": "3.4.4",
-    "nvd3": "1.1.15-beta",
-    "angularjs-nvd3-directives": "0.0.5-beta",
+    "nvd3": "1.8.4",
     "angular-sweetalert": "~1.0.3",
     "angular-underscore": "~0.5.0",
     "angular-ui-sortable": "0.13.1",
@@ -35,7 +34,8 @@
     "angular-ui-select": "0.13.2",
     "angular-sanitize": "1.2.18",
     "angular-tree-control": "0.2.8",
-    "angular-bootstrap-datetimepicker": "0.3.15"
+    "angular-bootstrap-datetimepicker": "0.3.15",
+    "angular-nvd3": "1.0.9"
   },
   "devDependencies": {
     "less.js": "~1.4.0",
@@ -43,7 +43,7 @@
   },
   "resolutions": {
     "angular": "1.2.29",
-    "nvd3": "1.1.15-beta",
+    "nvd3": "1.8.4",
     "d3": "3.4.4",
     "moment": "2.4.0",
     "angular-resource": "1.2.15",

http://git-wip-us.apache.org/repos/asf/kylin/blob/c27455fa/webapp/grunt.json
----------------------------------------------------------------------
diff --git a/webapp/grunt.json b/webapp/grunt.json
index d0ee545..06720b2 100755
--- a/webapp/grunt.json
+++ b/webapp/grunt.json
@@ -37,8 +37,7 @@
         "app/components/angular-chosen-localytics/chosen.js",
         "app/components/moment/min/moment.min.js",
         "app/components/d3/d3.min.js",
-        "app/components/nvd3/nv.d3.min.js",
-        "app/components/angularjs-nvd3-directives/dist/angularjs-nvd3-directives.js",
+        "app/components/nvd3/build/nv.d3.min.js",
         "app/components/bootstrap-sweetalert/lib/sweet-alert.js",
         "app/components/angular-sweetalert/SweetAlert.js",
         "app/components/underscore/underscore.js",
@@ -48,6 +47,7 @@
         "app/components/angular-toggle-switch/angular-toggle-switch.js",
         "app/components/angular-ui-select/dist/select.js",
         "app/components/angular-sanitize/angular-sanitize.js",
+        "app/components/angular-nvd3/dist/angular-nvd3.js",
         "tmp/js/scripts.js"
       ],
       "dest": "tmp/js/scripts.min.js"
@@ -65,7 +65,7 @@
         "app/css/messenger-theme-ice.css",
         "app/components/chosen/chosen.css",
         "app/components/angular-chosen-localytics/chosen-spinner.css",
-        "app/components/nvd3/nv.d3.min.css",
+        "app/components/nvd3/build/nv.d3.min.css",
         "app/css/AdminLTE.css",
         "app/css/skins/_all-skins.min.css",
         "app/components/bootstrap-sweetalert/lib/sweet-alert.css",