Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] add POC waffle viz #11931

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/core_plugins/waffle_chart/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function (kibana) {
return new kibana.Plugin({
uiExports: {
visTypes: [
'plugins/waffle_chart/waffle_chart'
]
}
});
}
4 changes: 4 additions & 0 deletions src/core_plugins/waffle_chart/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "waffle_chart",
"version": "kibana"
}
4 changes: 4 additions & 0 deletions src/core_plugins/waffle_chart/public/options_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="form-group">
<label>Font Size - {{ vis.params.fontSize }}pt</label>
<input type="range" ng-model="vis.visConfig.fontSize" class="form-control" min="12" max="120" />
</div>
8 changes: 8 additions & 0 deletions src/core_plugins/waffle_chart/public/vis_component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

class visComponent extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}

export { visComponent };
11 changes: 11 additions & 0 deletions src/core_plugins/waffle_chart/public/vis_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { uiModules } from 'ui/modules';
const module = uiModules.get('kibana/waffle_chart', ['kibana']);

module.controller('KbnWaffleChartController', function ($scope, $element, Private) {
$scope.$watch('esResponse', function (resp) {
if (resp) {
// call when done rendering
$scope.renderComplete();
}
});
});
3 changes: 3 additions & 0 deletions src/core_plugins/waffle_chart/public/vis_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div ng-controller="KbnWaffleChartController" class="waffle_chart">
<b>render visualization here</b>
</div>
53 changes: 53 additions & 0 deletions src/core_plugins/waffle_chart/public/waffle_chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import 'plugins/waffle_chart/waffle_chart.less';
import { CATEGORY } from 'ui/vis/vis_category';
import 'plugins/waffle_chart/vis_controller';
import { VisFactoryProvider } from 'ui/vis/vis_factory';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
import optionsTemplate from 'plugins/waffle_chart/options_template.html';
import visTemplate from 'plugins/waffle_chart/vis_template.html';

function WaffleChartProvider(Private) {
const VisFactory = Private(VisFactoryProvider);
const Schemas = Private(VisSchemasProvider);

// return the visType object, which kibana will use to display and configure new Vis object of this type.
return VisFactory.createAngularVisualization({
name: 'waffle_chart',
title: 'Waffle Chart',
icon: 'fa fa-gear',
description: 'a waffle chart',
category: CATEGORY.OTHER,
visConfig: {
defaults: {
// add default parameters
fontSize: '50'
},
template: visTemplate,
},
editor: 'default',
editorConfig: {
optionsTemplate: optionsTemplate,
schemas: new Schemas([
{
group: 'metrics',
name: 'metric',
title: 'Metric',
min: 1,
aggFilter: ['!derivative', '!geo_centroid'],
defaults: [
{ type: 'count', schema: 'metric' }
]
}
]),
},
requestHandler: 'courier',
responseHandler: 'none',
});
}

// register the provider with the visTypes registry
VisTypesRegistryProvider.register(WaffleChartProvider);

// export the provider so that the visType can be required with Private()
export default WaffleChartProvider;
5 changes: 5 additions & 0 deletions src/core_plugins/waffle_chart/public/waffle_chart.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import (reference) "~ui/styles/mixins.less";

.waffle_chart {
/* add your styles here */
}
9 changes: 9 additions & 0 deletions src/core_plugins/waffle_chart2/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function (kibana) {
return new kibana.Plugin({
uiExports: {
visTypes: [
'plugins/waffle_chart2/waffle_chart2'
]
}
});
}
4 changes: 4 additions & 0 deletions src/core_plugins/waffle_chart2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "waffle_chart2",
"version": "kibana"
}
2 changes: 2 additions & 0 deletions src/core_plugins/waffle_chart2/public/options_template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<div class="form-group">
</div>
172 changes: 172 additions & 0 deletions src/core_plugins/waffle_chart2/public/vis_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
import d3 from 'd3';

class VisController {
constructor(el) {
this._container = el;
this._waffleContainer = document.createElement('div');
this._waffleContainer.setAttribute('class', 'waffle-waffle');
this._legendContainer = document.createElement('div');
this._legendContainer.setAttribute('class', 'waffle-legend');
this._container.appendChild(this._waffleContainer);
this._container.appendChild(this._legendContainer);
}

render(vis, visData) {

window._vis = vis;

return new Promise((resolve) => {

this._clear();


try {
const label = vis.aggs[0].makeLabel() + ': '+ vis.aggs[1].makeLabel();
const data = convertResponse(visData);
this._createWaffleVis(data, label);
} catch (e) {
//handle error
}
resolve(true);
});
}

_clear() {
d3.select(this._waffleContainer).selectAll('*').remove();
d3.select(this._legendContainer).selectAll('*').remove();
}


_createWaffleVis(data, label) {
//copy pasted from http://bl.ocks.org/XavierGimenez/8070956
const widthSquares = 20;
const heightSquares = 5;
const squareSize = 25;
let squareValue = 0;
const gap = 1;
let theData = [];

const color = d3.scale.category10();

//total
let total = d3.sum(data, function (d) {
return d.value;
});

//value of a square
squareValue = total / (widthSquares * heightSquares);

//remap data
data.forEach(function (d, i) {
d.value = +d.value;
d.units = Math.floor(d.value / squareValue);
theData = theData.concat(
new Array(d.units + 1).join(1).split('').map(function () {
return {
squareValue: squareValue,
units: d.units,
value: d.value,
groupIndex: i
};
})
);
});

const width = (squareSize * widthSquares) + widthSquares * gap + 25;
const height = (squareSize * heightSquares) + heightSquares * gap + 25;

let col;
let row;
d3.select(this._waffleContainer)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.selectAll('div')
.data(theData)
.enter()
.append('rect')
.attr('width', squareSize)
.attr('height', squareSize)
.attr('fill', function (d) {
return color(d.groupIndex);
})
.attr('x', function (d, i) {
//group n squares for column
col = Math.floor(i / heightSquares);
return (col * squareSize) + (col * gap);
})
.attr('y', function (d, i) {
row = i % heightSquares;
return (heightSquares * squareSize) - ((row * squareSize) + (row * gap));
})
.append('title')
.text(function (d) {
return label + ' ' + data[d.groupIndex].key + ' | ' + d.value + ' , ' + d.units + '%';
});

//add legend with categorical data
const legend = d3.select(this._legendContainer)
.append('svg')
.attr('width', 300)
.attr('height', 200)
.append('g')
.selectAll('div')
.data(data)
.enter()
.append('g')
.attr('transform', function (d, i) {
return 'translate(0,' + i * 20 + ')';
});
legend.append('rect')
.attr('width', 18)
.attr('height', 18)
.style('fill', function (d, i) {
return color(i);
});
legend.append('text')
.attr('x', 25)
.attr('y', 13)
.text(function (d) {
return d.key;
});

//add value of a unit square
const legend2 = d3.select('#legend')
.select('svg')
.append('g')
.attr('transform', 'translate(100,0)');

legend2.append('text')
.attr('y', '14')
.attr('font-size', '18px')
.text('Total: ' + total)
.attr('fill', '#444444');

}

resize() {
console.log('resizing visualization');
}

destroy() {
this._clear();
this._container.innerHTML = '';
}
}

function convertResponse(esResponse) {
const data = [];
for (let i = 0; i < esResponse.rows.length; i += 1) {
if (esResponse.rows[i].rows[0] && esResponse.rows[i].rows[0][0]) {
data.push({
key: esResponse.rows[i].rows[0][0].$parent.value,
value: esResponse.rows[i].rows[0][0].value
});
}
}
return data;
}


export {VisController};
56 changes: 56 additions & 0 deletions src/core_plugins/waffle_chart2/public/waffle_chart2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'plugins/waffle_chart2/waffle_chart2.less';
import { CATEGORY } from 'ui/vis/vis_category';
import { VisFactoryProvider } from 'ui/vis/vis_factory';
import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
import { VisSchemasProvider } from 'ui/vis/editors/default/schemas';
import optionsTemplate from 'plugins/waffle_chart2/options_template.html';
import { VisController } from 'plugins/waffle_chart2/vis_controller';

function WaffleChart2Provider(Private) {
const VisFactory = Private(VisFactoryProvider);
const Schemas = Private(VisSchemasProvider);

// return the visType object, which kibana will use to display and configure new Vis object of this type.
return VisFactory.createBaseVisualization({
name: 'waffle_chart2',
title: 'Waffle Chart2',
icon: 'fa fa-gear',
description: 'A waffle chart',
category: CATEGORY.BASIC,
visualization: VisController,
visConfig: {
},
editor: 'default',
editorConfig: {
optionsTemplate: optionsTemplate,
schemas: new Schemas([
{
group: 'metrics',
name: 'metric',
title: 'Metric',
min: 1,
aggFilter: ['!derivative', '!geo_centroid'],
defaults: [
{ type: 'count', schema: 'metric' }
]
},
{
group: 'buckets',
name: 'split',
title: 'Waffle colors',
min: 0,
max: 1,
aggFilter: '!geohash_grid'
}
]),
},
requestHandler: 'courier',
responseHandler: 'basic',
});
}

// register the provider with the visTypes registry
VisTypesRegistryProvider.register(WaffleChart2Provider);

// export the provider so that the visType can be required with Private()
export default WaffleChart2Provider;
18 changes: 18 additions & 0 deletions src/core_plugins/waffle_chart2/public/waffle_chart2.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
@import (reference) "~ui/styles/mixins.less";

.waffle_chart2 {
/* add your styles here */
}

.waffle-waffle {
position: absolute;
width: 100%;
height: 100%;
}

.waffle-legend {
position: absolute;
width: 20%;
top: 0;
right: 0;
}
8 changes: 8 additions & 0 deletions src/core_plugins/waffle_vis/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function (kibana) {

return new kibana.Plugin({
uiExports: {
visTypes: ['plugins/waffle_vis/waffle_vis']
}
});
}
4 changes: 4 additions & 0 deletions src/core_plugins/waffle_vis/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "waffle_vis",
"version": "kibana"
}
Loading