replace cubism with a custom implementation
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"private": true,
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"babelify"
|
||||
]
|
||||
}
|
||||
}
|
||||
+5
@@ -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
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user