replace cubism with a custom implementation

This commit is contained in:
Florent BEAUCHAMP
2015-09-24 21:09:46 +02:00
parent cf3e9704e8
commit 5ac84a6a02
6 changed files with 275 additions and 16 deletions
+2
View File
@@ -9,6 +9,7 @@ import foreach from 'lodash.foreach'
import xoApi from 'xo-api'
import xoCubism from'xo-cubism'
import xoHorizon from'xo-horizon'
import xoParallelD3 from 'xo-parallel-d3'
import xoSunburstD3 from 'xo-sunburst-d3'
import xoWeekHeatmap from'xo-week-heatmap'
@@ -20,6 +21,7 @@ export default angular.module('dashboard.dataviz', [
uiSelect,
xoApi,
xoCubism,
xoHorizon,
xoParallelD3,
xoSunburstD3,
xoWeekHeatmap
+4 -5
View File
@@ -266,7 +266,7 @@ export default angular.module('dashboard.health', [
}
ctrl.objects = xoApi.all
ctrl.choosen = []
ctrl.chosen = []
this.prepareTypeFilter = function (selection) {
const object = selection[0]
ctrl.typeFilter = object && object.type || undefined
@@ -278,10 +278,10 @@ export default angular.module('dashboard.health', [
}
this.prepareMetrics = function (objects) {
ctrl.choosen = objects
ctrl.chosen = objects
ctrl.loadingMetrics = true
xoAggregate
.refreshStats(ctrl.choosen)
.refreshStats(ctrl.chosen, 2)
.then(function (result) {
stats = result
ctrl.metrics = stats.keys
@@ -298,8 +298,7 @@ export default angular.module('dashboard.health', [
console.log('preparestat')
ctrl.stats = {}
forEach(stats.details, function (stat, object_id) {
const label = find(ctrl.choosen, {id: object_id})
console.log(label)
const label = find(ctrl.chosen, {id: object_id})
ctrl.stats[ctrl.selectedMetric + ' ' + label.name_label] = stat[ctrl.selectedMetric]
})
}
+30 -11
View File
@@ -86,10 +86,10 @@
.btn-group(role = 'group')
button.btn.btn-default(ng-click = 'cubism.selected = []', tooltip = 'Clear selection')
i.fa.fa-times
// button.btn.btn-default(ng-click = 'cubism.selectAll("VM")', tooltip = 'Choose all VMs')
// i.xo-icon-vm
// button.btn.btn-default(ng-click = 'cubism.selectAll("host")', tooltip = 'Choose all hosts')
// i.xo-icon-host
button.btn.btn-default(ng-click = 'cubism.selectAll("VM")', tooltip = 'Choose all VMs')
i.xo-icon-vm
button.btn.btn-default(ng-click = 'cubism.selectAll("host")', tooltip = 'Choose all hosts')
i.xo-icon-host
button.btn.btn-success(ng-click = 'cubism.prepareMetrics(cubism.selected)', tooltip = 'Load metrics')
i.fa.fa-check
|  Select
@@ -110,11 +110,30 @@
span(ng-if = '!object._ignored') {{ object.name_label }}
del(ng-if = 'object._ignored') {{ object.name_label }}
|   
cubism(
ng-if='!cubism.loadingMetrics && cubism.selectedMetric'
chart-data='cubism.stats'
extents='extents'
step='1000*5'
size='168'
//cubism(
// ng-if='!cubism.loadingMetrics && cubism.selectedMetric'
// chart-data='cubism.stats'
// extents='extents'
// step='1000*5'
// size='168'
// )
div(ng-repeat="stat in cubism.stats")
horizon(
ng-if='$first'
chart-data='stat'
show-axis='true'
axis-orientation='top'
selected='cubism.selected'
)
horizon(
ng-if='$middle'
chart-data='stat'
selected='cubism.selected'
)
horizon(
ng-if='$last && !$first'
chart-data='stat'
show-axis='true'
axis-orientation='bottom'
selected='cubism.selected'
)
+226
View File
@@ -0,0 +1,226 @@
'use strict'
import angular from 'angular'
import d3 from 'd3'
import find from 'lodash.find'
import forEach from 'lodash.forEach'
console.log('loaded')
export default angular.module('xoHorizon', [])
.directive('horizon', function ($parse) {
return {
restrict: 'E',
replace: false,
scope: {
chartData: '=',
selected: '='
},
link: link
}
function link (scope, element, attrs) {
console.log('link')
let nbSteps, margin, width, height, color, data
nbSteps = attrs.steps || 4
margin = {
top: attrs.showAxis && attrs.axisOrientation !== 'bottom' ? 20 : 0,
right: 20,
bottom: attrs.showAxis && attrs.axisOrientation === 'bottom' ? 20 : 0,
left: 20
}
width = attrs.width || 960 - margin.left - margin.right
height = attrs.height || 70 - margin.top - margin.bottom + (attrs.showAxis ? 20 : 0)
color = attrs.color || 'darkgreen'
const x = d3
.time
.scale()
.range([0, width])
const y = d3
.scale.linear()
.range([height, 0])
const xAxis = d3
.svg
.axis()
.scale(x)
.orient(attrs.axisOrientation || 'top')
const line = d3
.svg
.line()
.x(function (d) {
return x(d.date)
})
.y(function (d) {
return y(d.value)
})
const bisectDate = d3
.bisector(function (d) {
return d.date
}).left
const svg = d3
.select(element[0])
.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
// Tooltip
const focus = svg
.append('g')
.attr('class', 'focus')
.style('display', 'none')
focus
.append('text')
.attr('x', 9)
.attr('dy', '.35em')
svg
.append('rect')
.attr('class', 'overlay')
.attr('width', width)
.attr('height', height)
.style({fill: 'none', 'pointer-events': 'all'})
.on('mousemove', mousemove)
const hover = svg
.append('g')
.attr('class', 'hover-container')
.style('pointer-events', 'none')
hover
.append('line')
.attr('y1', 0)
.attr('y2', height)
.style('stroke-width', 2)
.style('stroke-dasharray', '5 5')
.style('stroke', 'red')
.style('fill', 'none')
hover
.append('text')
.style({stroke: 'black'})
function mousemove () {
const x0 = x.invert(d3.mouse(this)[0])
const index = bisectDate(data, x0, 1)
const d0 = data[index - 1]
const d1 = data[index]
const d = x0 - d0.date > d1.date - x0 ? d1 : d0
scope.$apply(function () {
scope.selected = d.date
})
}
function hoverDate (date) {
const val = find(data, {date: date})
if (val) {
hover
.select('line')
.attr('x1', x(date))
.attr('x2', x(date))
hover
.select('text')
.attr('dx', x(date) + 5)
.attr('dy', height / 2)
.text(val.value)
}
}
d3.selection.prototype.moveToFront = function () {
return this.each(function () {
this.parentNode.appendChild(this)
})
}
scope.$watch('selected', function (newVal) {
if (newVal) {
hoverDate(newVal)
}
})
scope.$watch(function () {
return scope.chartData
}, function (newVal) {
let splittedData, counter, extent
if (!newVal || !newVal.length) {
return
}
data = newVal
extent = scope.extent || d3
.extent(newVal, function (d) {
return d.value
})
extent = [Math.min(0, extent[0]), Math.max(0, extent[1])]
const intervalSize = (extent[1] - extent[0]) / nbSteps
splittedData = []
for (counter = 0; counter < nbSteps; counter++) {
splittedData[counter] = []
var d = new Date(newVal[0].date)
splittedData[counter].push({
date: d,
value: 0
})
}
forEach(newVal, function (datum) {
for (counter = 0; counter < nbSteps; counter++) {
var d = new Date(datum.date)
splittedData[counter].push({
date: d,
value: Math.min(Math.max(0, datum.value - intervalSize * counter), intervalSize),
close: new Date(+d + 60 * 60 * 1000)
})
}
})
for (counter = 0; counter < nbSteps; counter++) {
const d = new Date(newVal[newVal.length - 1].date)
splittedData[counter].push({
date: d,
value: 0
})
}
x.domain(d3.extent(splittedData[0], function (d) {
return d.date
}))
y.domain([extent[0], extent[1] / nbSteps])
if (attrs.showAxis) {
var bottomaxis = svg
.append('g')
.attr('class', 'x axis')
.style({
fill: 'none',
stroke: '#000',
'shape-rendering': 'crispEdges'
})
.call(xAxis)
if (attrs.axisOrientation === 'bottom') {
bottomaxis.attr('transform', 'translate(0,' + height + ')')
}
bottomaxis.selectAll('text').style({fill: 'black', stroke: 'transparent'})
}
forEach(splittedData, function (oneSplitted) {
svg
.append('path')
.attr('class', 'horizon-area')
.datum(oneSplitted)
.style({
fill: color,
stroke: 'transparent',
'fill-opacity': 0.25,
'stroke-opacity': 0.3
})
.attr('d', line)
})
svg.select('.overlay').moveToFront()
svg.select('.hover-container').moveToFront()
})
}
}).name
+8
View File
@@ -0,0 +1,8 @@
{
"private": true,
"browserify": {
"transform": [
"babelify"
]
}
}
+5
View File
@@ -34,6 +34,11 @@ export default angular.module('xoWebApp.services', [
statPromises.push(
xo[apiType].refreshStats(object.id, level) // 2: week granularity (7 * 24 hours)
.then(rawStats => ({object, rawStats}))
.catch(error => {
error.object = object
object._ignored = true
throw error
})
)
}
})