added d3pie and d3dpie charts; updated d3 to latest v4.12.2
Costa Tsaousis (ktsaou) committed
Jan 25, 2018 at 02:04 UTC
e38f00a9891ef173a214692f461a7653bff2e0a8
5 files changed
+784
-3
web/Makefile.am
+1
@@ -47,6 +47,7 @@ dist_weblib_DATA = \
47
lib/clipboard-polyfill-be05dad.js \
48
lib/c3-0.4.11.min.js \
49
lib/d3-3.5.17.min.js \
50
+ lib/d3pie-0.2.1.min.js \
51
lib/dygraph-combined-dd74404.js \
52
lib/dygraph-smooth-plotter-dd74404.js \
53
lib/fontawesome-all-5.0.1.min.js \
web/dashboard.css
+31
@@ -432,6 +432,37 @@ body {
432
height: auto !important;
433
}
434
435
+.d3dpieChart {
436
+ border-radius: 5px 5px 0 0;
437
+ padding-top: 0px;
438
+ margin: 0px auto 0;
439
+ height: 100%;
440
+ background-color: #fff;
441
+}
442
+.d3dpieChart svg {
443
+ width: 100% !important;
444
+ height: 100%;
445
+}
446
+.d3dpieChart path.slice {
447
+ stroke-width: 2px;
448
+}
449
+.d3dpieChart .slice {
450
+ stroke: white;
451
+ stroke-width: 2px;
452
+}
453
+.d3dpieChart .slice:hover{
454
+ opacity: .5;
455
+}
456
+.d3dpieChart .labels text{
457
+ background-color: #333;
458
+ width: 200px;
459
+}
460
+.d3dpieChart polyline{
461
+ stroke: #333;
462
+ stroke-width: 1px;
463
+ fill: none;
464
+}
465
+
466
.easyPieChart {
467
position: relative;
468
text-align: center;
web/dashboard.html
+58
@@ -643,6 +643,64 @@ So, to avoid flashing the charts, we destroy and re-create the charts on each up
643
<small>rendered in <span id="time803">X</span> ms</small>
644
</div>
645
646
+
647
+ <hr>
648
+ <h1>d3pie Charts</h1>
649
+
650
+ <div style="width: 33%; display: inline-block;">
651
+ <div data-netdata="acquiring.responses_by_errorcode"
652
+ data-dimensions="!*.0000|*"
653
+ data-append-options="match-ids|unaligned"
654
+ data-method="sum"
655
+ data-units="trns / hour"
656
+ data-update-every="30"
657
+ data-host="https://jira.viva.gr/netdata/"
658
+ data-chart-library="d3pie"
659
+ data-d3pie-pieinnerradius="70%"
660
+ data-d3pie-pieouterradius="90%"
661
+ data-d3pie-smallsegmentgrouping-value="0.5"
662
+ data-d3pie-smallsegmentgrouping-enabled="true"
663
+ data-d3pie-labels-inner-hidewhenlessthanpercentage="3"
664
+ data-title="Rejected Transactions Reasons"
665
+ data-width="100%"
666
+ data-height="300px"
667
+ data-after="-3600"
668
+ data-points="1"
669
+ data-decimal-digits="0"
670
+ data-dt-element-name="time901"
671
+ ></div>
672
+ <br/>
673
+ <small>rendered in <span id="time901">X</span> ms</small>
674
+ </div>
675
+
676
+ <div style="width: 33%; display: inline-block;">
677
+ <div data-netdata="apps.cpu"
678
+ data-chart-library="d3dpie"
679
+ data-width="100%"
680
+ data-height="250px"
681
+ data-after="-60"
682
+ data-points="60"
683
+ data-debug="false"
684
+ data-decimal-digits="0"
685
+ data-dt-element-name="time902"
686
+ ></div>
687
+ <br/>
688
+ <small>rendered in <span id="time902">X</span> ms</small>
689
+ </div>
690
+
691
+ <div style="width: 33%; display: inline-block;">
692
+ <div data-netdata="apps.cpu"
693
+ data-width="100%"
694
+ data-height="300px"
695
+ data-after="-60"
696
+ data-points="60"
697
+ data-debug="false"
698
+ data-decimal-digits="0"
699
+ data-dt-element-name="time902"
700
+ ></div>
701
+ <br/>
702
+ <small>rendered in <span id="time902">X</span> ms</small>
703
+ </div>
704
</div> <!-- 1st container -->
705
</body>
706
</html>
web/dashboard.js
+663
-3
@@ -19,6 +19,10 @@
19
* (default: false) */
20
/*global netdataNoC3 *//* boolean, disable c3 charts
21
* (default: false) */
22
+/*global netdataNoD3pie *//* boolean, disable d3pie charts
23
+ * (default: false) */
24
+/*global netdataNoD3dpie *//* boolean, disable d3dpie charts
25
+ * (default: false) */
26
/*global netdataNoBootstrap *//* boolean, disable bootstrap - disables help too
27
* (default: false) */
28
/*global netdataDontStart *//* boolean, do not start the thread to process the charts
@@ -160,7 +164,8 @@ var NETDATA = window.NETDATA || {};
164
NETDATA.raphael_js = NETDATA.serverStatic + 'lib/raphael-2.2.4-min.js';
165
NETDATA.c3_js = NETDATA.serverStatic + 'lib/c3-0.4.11.min.js';
166
NETDATA.c3_css = NETDATA.serverStatic + 'css/c3-0.4.11.min.css';
163
- NETDATA.d3_js = NETDATA.serverStatic + 'lib/d3-3.5.17.min.js';
167
+ NETDATA.d3pie_js = NETDATA.serverStatic + 'lib/d3pie-0.2.1.min.js';
168
+ NETDATA.d3_js = NETDATA.serverStatic + 'lib/d3-4.12.2.min.js';
169
NETDATA.morris_js = NETDATA.serverStatic + 'lib/morris-0.5.1.min.js';
170
NETDATA.morris_css = NETDATA.serverStatic + 'css/morris-0.5.1.css';
171
NETDATA.google_js = 'https://www.google.com/jsapi';
@@ -168,7 +173,7 @@ var NETDATA = window.NETDATA || {};
173
NETDATA.themes = {
174
white: {
175
bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-3.3.7.css',
171
- dashboard_css: NETDATA.serverStatic + 'dashboard.css?v20180120-1',
176
+ dashboard_css: NETDATA.serverStatic + 'dashboard.css?v20180124-3',
177
background: '#FFFFFF',
178
foreground: '#000000',
179
grid: '#F0F0F0',
@@ -186,7 +191,7 @@ var NETDATA = window.NETDATA || {};
191
},
192
slate: {
193
bootstrap_css: NETDATA.serverStatic + 'css/bootstrap-slate-flat-3.3.7.css?v20161229-1',
189
- dashboard_css: NETDATA.serverStatic + 'dashboard.slate.css?v20180120-1',
194
+ dashboard_css: NETDATA.serverStatic + 'dashboard.slate.css?v20180124-3',
195
background: '#272b30',
196
foreground: '#C8C8C8',
197
grid: '#283236',
@@ -7101,6 +7106,623 @@ var NETDATA = window.NETDATA || {};
7106
return true;
7107
};
7108
7109
+ // ----------------------------------------------------------------------------------------------------------------
7110
+ // d3pie
7111
+
7112
+ NETDATA.d3pieInitialize = function(callback) {
7113
+ if(typeof netdataNoD3pie === 'undefined' || !netdataNoD3pie) {
7114
+
7115
+ // d3pie requires D3
7116
+ if(!NETDATA.chartLibraries.d3.initialized) {
7117
+ if(NETDATA.chartLibraries.d3.enabled) {
7118
+ NETDATA.d3Initialize(function() {
7119
+ NETDATA.d3pieInitialize(callback);
7120
+ });
7121
+ }
7122
+ else {
7123
+ NETDATA.chartLibraries.d3pie.enabled = false;
7124
+ if(typeof callback === "function")
7125
+ return callback();
7126
+ }
7127
+ }
7128
+ else {
7129
+ $.ajax({
7130
+ url: NETDATA.d3pie_js,
7131
+ cache: true,
7132
+ dataType: "script",
7133
+ xhrFields: { withCredentials: true } // required for the cookie
7134
+ })
7135
+ .done(function() {
7136
+ NETDATA.registerChartLibrary('d3pie', NETDATA.d3pie_js);
7137
+ })
7138
+ .fail(function() {
7139
+ NETDATA.chartLibraries.d3pie.enabled = false;
7140
+ NETDATA.error(100, NETDATA.d3pie_js);
7141
+ })
7142
+ .always(function() {
7143
+ if(typeof callback === "function")
7144
+ return callback();
7145
+ });
7146
+ }
7147
+ }
7148
+ else {
7149
+ NETDATA.chartLibraries.d3pie.enabled = false;
7150
+ if(typeof callback === "function")
7151
+ return callback();
7152
+ }
7153
+ };
7154
+
7155
+ NETDATA.d3pieSetContent = function(state, data, index) {
7156
+ state.legendFormatValueDecimalsFromMinMax(
7157
+ data.min,
7158
+ data.max
7159
+ );
7160
+
7161
+ var content = [];
7162
+ var colors = state.chartColors();
7163
+ var len = data.result.labels.length;
7164
+ for(var i = 1; i < len ; i++) {
7165
+ var label = data.result.labels[i];
7166
+ var value = data.result.data[index][label];
7167
+ var color = colors[i - 1];
7168
+
7169
+ content.push({
7170
+ label: label,
7171
+ value: value,
7172
+ color: color
7173
+ });
7174
+ }
7175
+
7176
+ return content;
7177
+ };
7178
+
7179
+ NETDATA.d3pieChartUpdate = function(state, data) {
7180
+ var content = NETDATA.d3pieSetContent(state, data, 0);
7181
+
7182
+ var subtitle = NETDATA.dataAttribute(state.element, 'd3pie-subtitle', state.units_current);
7183
+ if(subtitle !== state.d3pie_subtitle) {
7184
+ state.d3pie_subtitle = subtitle;
7185
+ state.d3pie_instance.updateProp("header.subtitle.text", state.d3pie_subtitle);
7186
+ }
7187
+
7188
+ state.d3pie_instance.updateProp("data.content", content);
7189
+ return true;
7190
+ };
7191
+
7192
+ NETDATA.d3pieChartCreate = function(state, data) {
7193
+
7194
+ state.element_chart.id = 'd3pie-' + state.uuid;
7195
+ // console.log('id = ' + state.element_chart.id);
7196
+
7197
+ var content = NETDATA.d3pieSetContent(state, data, 0);
7198
+ state.d3pie_subtitle = NETDATA.dataAttribute(state.element, 'd3pie-subtitle', state.units_current);
7199
+
7200
+ state.d3pie_options = {
7201
+ header: {
7202
+ title: {
7203
+ text: NETDATA.dataAttribute(state.element, 'd3pie-title', state.title),
7204
+ color: NETDATA.dataAttribute(state.element, 'd3pie-title-color', "#333333"),
7205
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-title-fontsize', 14),
7206
+ font: NETDATA.dataAttribute(state.element, 'd3pie-title-font', "arial")
7207
+ },
7208
+ subtitle: {
7209
+ text: state.d3pie_subtitle,
7210
+ color: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-color', "#666666"),
7211
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-fontsize', 11),
7212
+ font: NETDATA.dataAttribute(state.element, 'd3pie-subtitle-font', "arial")
7213
+ },
7214
+ titleSubtitlePadding: 1
7215
+ },
7216
+ footer: {
7217
+ text: NETDATA.dataAttribute(state.element, 'd3pie-footer', ''),
7218
+ color: NETDATA.dataAttribute(state.element, 'd3pie-footer-color', "#999999"),
7219
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-footer-fontsize', 10),
7220
+ font: NETDATA.dataAttribute(state.element, 'd3pie-footer-font', "arial"),
7221
+ location: NETDATA.dataAttribute(state.element, 'd3pie-footer-location', "bottom-left")
7222
+ },
7223
+ size: {
7224
+ canvasHeight: state.chartHeight(),
7225
+ canvasWidth: state.chartWidth(),
7226
+ pieInnerRadius: NETDATA.dataAttribute(state.element, 'd3pie-pieinnerradius', "0%"),
7227
+ pieOuterRadius: NETDATA.dataAttribute(state.element, 'd3pie-pieouterradius', "80%")
7228
+ },
7229
+ data: {
7230
+ // none, random, value-asc, value-desc, label-asc, label-desc
7231
+ sortOrder: NETDATA.dataAttribute(state.element, 'd3pie-sortorder', "value-desc"),
7232
+ smallSegmentGrouping: {
7233
+ enabled: NETDATA.dataAttributeBoolean(state.element, "d3pie-smallsegmentgrouping-enabled", true),
7234
+ value: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-value', 1),
7235
+ // percentage, value
7236
+ valueType: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-valuetype', "percentage"),
7237
+ label: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-label', "other"),
7238
+ color: NETDATA.dataAttribute(state.element, 'd3pie-smallsegmentgrouping-color', "#cccccc")
7239
+ },
7240
+
7241
+ // REQUIRED! This is where you enter your pie data; it needs to be an array of objects
7242
+ // of this form: { label: "label", value: 1.5, color: "#000000" } - color is optional
7243
+ content: content
7244
+ },
7245
+ labels: {
7246
+ outer: {
7247
+ // label, value, percentage, label-value1, label-value2, label-percentage1, label-percentage2
7248
+ format: NETDATA.dataAttribute(state.element, 'd3pie-labels-outer-format', "label-value1"),
7249
+ hideWhenLessThanPercentage: NETDATA.dataAttribute(state.element, 'd3pie-labels-outer-hidewhenlessthanpercentage', null),
7250
+ pieDistance: 20
7251
+ },
7252
+ inner: {
7253
+ // label, value, percentage, label-value1, label-value2, label-percentage1, label-percentage2
7254
+ format: NETDATA.dataAttribute(state.element, 'd3pie-labels-inner-format', "percentage"),
7255
+ hideWhenLessThanPercentage: NETDATA.dataAttribute(state.element, 'd3pie-labels-inner-hidewhenlessthanpercentage', null)
7256
+ },
7257
+ mainLabel: {
7258
+ color: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-color', "#333333"),
7259
+ font: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-font', "arial"),
7260
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-mainLabel-fontsize', 10)
7261
+ },
7262
+ percentage: {
7263
+ color: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-color', "#dddddd"),
7264
+ font: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-font', "arial"),
7265
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-percentage-fontsize', 10),
7266
+ decimalPlaces: 0
7267
+ },
7268
+ value: {
7269
+ color: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-color', "#cccc44"),
7270
+ font: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-font', "arial"),
7271
+ fontSize: NETDATA.dataAttribute(state.element, 'd3pie-labels-value-fontsize', 10)
7272
+ },
7273
+ lines: {
7274
+ enabled: NETDATA.dataAttributeBoolean(state.element, 'd3pie-labels-lines-enabled', true),
7275
+ style: NETDATA.dataAttribute(state.element, 'd3pie-labels-lines-style', "curved"),
7276
+ color: NETDATA.dataAttribute(state.element, 'd3pie-labels-lines-color', "segment") // "segment" or a hex color
7277
+ },
7278
+ formatter: function(context) {
7279
+ // console.log(context);
7280
+ if(context.part === 'value')
7281
+ return state.legendFormatValue(context.value);
7282
+ if(context.part === 'percentage')
7283
+ return context.label + '%';
7284
+
7285
+ return context.label;
7286
+ }
7287
+ },
7288
+ effects: {
7289
+ load: {
7290
+ effect: "none", // none / default
7291
+ speed: 0
7292
+ },
7293
+ pullOutSegmentOnClick: {
7294
+ effect: "none", // none / linear / bounce / elastic / back
7295
+ speed: 300,
7296
+ size: 10
7297
+ },
7298
+ highlightSegmentOnMouseover: false,
7299
+ highlightLuminosity: 1
7300
+ },
7301
+ tooltips: {
7302
+ enabled: false,
7303
+ type: "placeholder", // caption|placeholder
7304
+ string: "",
7305
+ placeholderParser: null,
7306
+ styles: {
7307
+ fadeInSpeed: 250,
7308
+ backgroundColor: "#000000",
7309
+ backgroundOpacity: 0.5,
7310
+ color: "#efefef",
7311
+ borderRadius: 2,
7312
+ font: "arial",
7313
+ fontSize: 10,
7314
+ padding: 4
7315
+ }
7316
+ },
7317
+ misc: {
7318
+ colors: {
7319
+ background: null, // transparent
7320
+ // segments: state.chartColors(),
7321
+ segmentStroke: NETDATA.dataAttribute(state.element, 'd3pie-misc-colors-segmentstroke', "#ffffff")
7322
+ },
7323
+ gradient: {
7324
+ enabled: NETDATA.dataAttributeBoolean(state.element, 'd3pie-misc-gradient-enabled', false),
7325
+ percentage: NETDATA.dataAttribute(state.element, 'd3pie-misc-colors-percentage', 95),
7326
+ color: NETDATA.dataAttribute(state.element, 'd3pie-misc-colors-segmentstroke', "#000000")
7327
+ },
7328
+ canvasPadding: {
7329
+ top: 5,
7330
+ right: 5,
7331
+ bottom: 5,
7332
+ left: 5
7333
+ },
7334
+ pieCenterOffset: {
7335
+ x: 0,
7336
+ y: 0
7337
+ },
7338
+ cssPrefix: null
7339
+ },
7340
+ callbacks: {
7341
+ onload: null,
7342
+ onMouseoverSegment: null,
7343
+ onMouseoutSegment: null,
7344
+ onClickSegment: null
7345
+ }
7346
+ };
7347
+
7348
+ state.d3pie_instance = new d3pie(state.element_chart, state.d3pie_options);
7349
+
7350
+ // console.log(state.d3pie_instance);
7351
+
7352
+ return true;
7353
+ };
7354
+
7355
+ // ----------------------------------------------------------------------------------------------------------------
7356
+ // d3dpie
7357
+
7358
+ NETDATA.d3dpieInitialize = function(callback) {
7359
+ if(typeof netdataNod3dpie === 'undefined' || !netdataNod3dpie) {
7360
+
7361
+ // d3dpie requires D3
7362
+ if(!NETDATA.chartLibraries.d3.initialized) {
7363
+ if(NETDATA.chartLibraries.d3.enabled) {
7364
+ NETDATA.d3Initialize(function() {
7365
+ NETDATA.d3dpieInitialize(callback);
7366
+ });
7367
+ }
7368
+ else {
7369
+ NETDATA.chartLibraries.d3dpie.enabled = false;
7370
+ if(typeof callback === "function")
7371
+ return callback();
7372
+ }
7373
+ }
7374
+ else {
7375
+ NETDATA.registerChartLibrary('d3dpie', "lib/d3dpie.js");
7376
+ if(typeof callback === "function")
7377
+ return callback();
7378
+ }
7379
+ }
7380
+ else {
7381
+ NETDATA.chartLibraries.d3dpie.enabled = false;
7382
+ if(typeof callback === "function")
7383
+ return callback();
7384
+ }
7385
+ };
7386
+
7387
+ NETDATA.d3dpieSetContent = function(state, data, index) {
7388
+ state.legendFormatValueDecimalsFromMinMax(
7389
+ data.min,
7390
+ data.max
7391
+ );
7392
+
7393
+ var content = [];
7394
+ var colors = state.chartColors();
7395
+ var len = data.result.labels.length;
7396
+ var sum = 0;
7397
+ for(var i = 1; i < len ; i++) {
7398
+ var label = data.result.labels[i];
7399
+ var value = data.result.data[index][label];
7400
+ var color = colors[i - 1];
7401
+
7402
+ sum += value;
7403
+
7404
+ content.push({
7405
+ label: label,
7406
+ value: value,
7407
+ color: color
7408
+ });
7409
+ }
7410
+
7411
+ len = content.length;
7412
+ for(i = 0; i < len ; i++) {
7413
+ content[i].percent = content[i].value * 100 / sum;
7414
+ }
7415
+
7416
+ return content;
7417
+ };
7418
+
7419
+ NETDATA.d3dpieChange = function(d3dpie, data, duration) {
7420
+ var svg = d3dpie.svg;
7421
+ var width = d3dpie.width;
7422
+ var height = d3dpie.height;
7423
+ var radius = d3dpie.radius;
7424
+ var pie = d3dpie.pie;
7425
+ var arc = d3dpie.arc;
7426
+ var outerArc = d3dpie.outerArc;
7427
+ var key = d3dpie.key;
7428
+
7429
+ function mergeWithFirstEqualZero(first, second) {
7430
+ var secondSet = d3.set();
7431
+ second.forEach(function (d) {
7432
+ secondSet.add(d.label);
7433
+ });
7434
+
7435
+ var onlyFirst = first
7436
+ .filter(function (d) {
7437
+ return !secondSet.has(d.label)
7438
+ })
7439
+ .map(function (d) {
7440
+ return {label: d.label, value: 0};
7441
+ });
7442
+ return d3.merge([second, onlyFirst])
7443
+ .sort(function (a, b) {
7444
+ return d3.ascending(a.label, b.label);
7445
+ });
7446
+ }
7447
+
7448
+ var data0 = svg.select(".slices").selectAll("path.slice")
7449
+ .data().map(function (d) {
7450
+ return d.data
7451
+ });
7452
+ if (data0.length === 0) data0 = data;
7453
+ var was = mergeWithFirstEqualZero(data, data0);
7454
+ var is = mergeWithFirstEqualZero(data0, data);
7455
+
7456
+ /* ------- SLICE ARCS -------*/
7457
+
7458
+ var slice = svg.select(".slices").selectAll("path.slice")
7459
+ .data(pie(was), key);
7460
+
7461
+ slice.enter()
7462
+ .insert("path")
7463
+ .attr("class", "slice")
7464
+ .style("fill", function (d) {
7465
+ return d.data.color;
7466
+ })
7467
+ .each(function (d) {
7468
+ this._current = d;
7469
+ });
7470
+
7471
+ slice = svg.select(".slices").selectAll("path.slice")
7472
+ .data(pie(is), key);
7473
+
7474
+ slice
7475
+ .transition().duration(duration)
7476
+ .attrTween("d", function (d) {
7477
+ var interpolate = d3.interpolate(this._current, d);
7478
+ var _this = this;
7479
+ return function (t) {
7480
+ _this._current = interpolate(t);
7481
+ return arc(_this._current);
7482
+ };
7483
+ });
7484
+
7485
+ slice = svg.select(".slices").selectAll("path.slice")
7486
+ .data(pie(data), key);
7487
+
7488
+ slice
7489
+ .exit().transition().delay(duration).duration(0)
7490
+ .remove();
7491
+
7492
+ /* ------- TEXT LABELS -------*/
7493
+
7494
+ var text = svg.select(".labels").selectAll("text")
7495
+ .data(pie(was), key);
7496
+
7497
+ text.enter()
7498
+ .append("text")
7499
+ .attr("dy", ".35em")
7500
+ .style("opacity", 0)
7501
+ .text(function (d) {
7502
+ return d.data.label;
7503
+ })
7504
+ .each(function (d) {
7505
+ this._current = d;
7506
+ });
7507
+
7508
+ function midAngle(d) {
7509
+ return d.startAngle + (d.endAngle - d.startAngle) / 2;
7510
+ }
7511
+
7512
+ var slotsLeft = {}, slotsRight = {};
7513
+ var setLeft = {}, setRight = {};
7514
+ var fontSize = 14;
7515
+
7516
+ function verticalAlign(d, pos) {
7517
+ if(d.data.value === 0)
7518
+ return;
7519
+
7520
+ var slots = (pos[0] < 0)?slotsLeft:slotsRight;
7521
+ var set = (pos[0] < 0)?setLeft:setRight;
7522
+
7523
+ if(typeof(set[d.data.label]) !== 'undefined') {
7524
+ pos[1] = set[d.data.label];
7525
+ return;
7526
+ }
7527
+
7528
+ var y = Math.round(pos[1]);
7529
+ y -= y % fontSize;
7530
+ var idx = Math.round(y / fontSize);
7531
+
7532
+ for(var i = 0; i < 10 ;i++) {
7533
+ if (typeof(slots[idx + i]) === 'undefined') {
7534
+ //console.log(d.data.label + ': x = ' + pos[0].toString() + ', y = ' + y.toString() + ', idx = ' + idx.toString() + ', found i = ', i.toString() + ', new y = ' + ((idx + i) * fontSize).toString());
7535
+ slots[idx + i] = 1;
7536
+ y = (idx + i) * fontSize;
7537
+ break;
7538
+ }
7539
+ else if (typeof(slots[idx - i]) === 'undefined') {
7540
+ //console.log(d.data.label + ': x = ' + pos[0].toString() + ', y = ' + y.toString() + ', idx = ' + idx.toString() + ', found i = ', (-i).toString() + ', new y = ' + ((idx - i) * fontSize).toString());
7541
+ slots[idx - i] = 1;
7542
+ y = (idx - i) * fontSize;
7543
+ break;
7544
+ }
7545
+ }
7546
+
7547
+ pos[1] = y;
7548
+ set[d.data.label] = y;
7549
+ }
7550
+
7551
+ text = svg.select(".labels").selectAll("text")
7552
+ .data(pie(is), key);
7553
+
7554
+ text.transition().duration(duration)
7555
+ .style("opacity", function (d) {
7556
+ return (d.data.value === 0) ? 0 : 1;
7557
+ })
7558
+ .attrTween("transform", function (d) {
7559
+ var interpolate = d3.interpolate(this._current, d);
7560
+ var _this = this;
7561
+ return function (t) {
7562
+ var d2 = interpolate(t);
7563
+ _this._current = d2;
7564
+ var pos = outerArc.centroid(d2);
7565
+ pos[0] = radius * (midAngle(d2) < Math.PI ? 1 : -1);
7566
+ verticalAlign(d2, pos);
7567
+ return "translate(" + pos + ")";
7568
+ };
7569
+ })
7570
+ .styleTween("text-anchor", function (d) {
7571
+ var interpolate = d3.interpolate(this._current, d);
7572
+ return function (t) {
7573
+ var d2 = interpolate(t);
7574
+ return midAngle(d2) < Math.PI ? "start" : "end";
7575
+ };
7576
+ });
7577
+
7578
+ text = svg.select(".labels").selectAll("text")
7579
+ .data(pie(data), key);
7580
+
7581
+ text
7582
+ .exit().transition().delay(duration)
7583
+ .remove();
7584
+
7585
+ /* ------- SLICE TO TEXT POLYLINES -------*/
7586
+
7587
+ var polyline = svg.select(".lines").selectAll("polyline")
7588
+ .data(pie(was), key);
7589
+
7590
+ polyline.enter()
7591
+ .append("polyline")
7592
+ .style("opacity", 0)
7593
+ .each(function (d) {
7594
+ this._current = d;
7595
+ });
7596
+
7597
+ polyline = svg.select(".lines").selectAll("polyline")
7598
+ .data(pie(is), key);
7599
+
7600
+ polyline.transition().duration(duration)
7601
+ .style("opacity", function (d) {
7602
+ return (d.data.value === 0) ? 0 : 1;
7603
+ })
7604
+ .attrTween("points", function (d) {
7605
+ // this._current = this._current;
7606
+ var interpolate = d3.interpolate(this._current, d);
7607
+ var _this = this;
7608
+ return function (t) {
7609
+ var d2 = interpolate(t);
7610
+ _this._current = d2;
7611
+ var pos = outerArc.centroid(d2);
7612
+ pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1);
7613
+ verticalAlign(d2, pos);
7614
+
7615
+ var pos2 = outerArc.centroid(d2);
7616
+ verticalAlign(d2, pos2);
7617
+ return [arc.centroid(d2), pos2, pos];
7618
+ };
7619
+ });
7620
+
7621
+ polyline = svg.select(".lines").selectAll("polyline")
7622
+ .data(pie(data), key);
7623
+
7624
+ polyline
7625
+ .exit().transition().delay(duration)
7626
+ .remove();
7627
+ };
7628
+
7629
+ NETDATA.d3dpieSetSelection = function(state, t) {
7630
+ if(state.timeIsVisible(t) !== true)
7631
+ return NETDATA.d3dpieClearSelection(state, true);
7632
+
7633
+ var slot = state.calculateRowForTime(t);
7634
+ slot = state.data.result.data.length - slot - 1;
7635
+
7636
+ if(slot < 0 || slot >= state.data.result.length)
7637
+ return NETDATA.d3dpieClearSelection(state, true);
7638
+
7639
+ if(state.tmp.d3pie_timer === undefined) {
7640
+ state.tmp.d3pie_timer = NETDATA.timeout.set(function() {
7641
+ state.tmp.d3pie_timer = undefined;
7642
+ NETDATA.d3dpieChange(state.d3dpie_instance, NETDATA.d3dpieSetContent(state, state.data, slot), 0);
7643
+ }, 0);
7644
+ }
7645
+
7646
+ return true;
7647
+ };
7648
+
7649
+ NETDATA.d3dpieClearSelection = function(state, force) {
7650
+ if(typeof state.tmp.d3dpie_timer !== 'undefined') {
7651
+ NETDATA.timeout.clear(state.tmp.d3dpie_timer);
7652
+ state.tmp.d3dpie_timer = undefined;
7653
+ }
7654
+
7655
+ if(state.isAutoRefreshable() === true && state.data !== null && force !== true) {
7656
+ NETDATA.d3dpieChartUpdate(state, state.data);
7657
+ }
7658
+ else {
7659
+ // FIXME: we should show empty chart here
7660
+ NETDATA.d3dpieChange(state.d3dpie_instance, NETDATA.d3dpieSetContent(state, state.data, 0), 0);
7661
+ }
7662
+
7663
+ return true;
7664
+ };
7665
+
7666
+ NETDATA.d3dpieChartUpdate = function(state, data) {
7667
+ NETDATA.d3dpieChange(state.d3dpie_instance, NETDATA.d3dpieSetContent(state, data, 0), 500);
7668
+ return true;
7669
+ };
7670
+
7671
+ NETDATA.d3dpieChartCreate = function(state, data) {
7672
+ state.element_chart.className = 'd3dpieChart';
7673
+
7674
+ var svg = d3.select(state.element_chart)
7675
+ .append("svg")
7676
+ .append("g");
7677
+
7678
+ svg.append("g")
7679
+ .attr("class", "slices");
7680
+
7681
+ svg.append("g")
7682
+ .attr("class", "labels");
7683
+
7684
+ svg
7685
+ .append("g")
7686
+ .attr("class", "lines");
7687
+
7688
+ var width = state.chartWidth(),
7689
+ height = state.chartHeight(),
7690
+ radius = Math.min(width,height) / 2;
7691
+
7692
+ var pie = d3.pie()
7693
+ .sort(null)
7694
+ .value(function(d) {
7695
+ return d.value;
7696
+ });
7697
+
7698
+ var arc = d3.arc()
7699
+ .outerRadius(radius * 0.9)
7700
+ .innerRadius(radius * 0.6);
7701
+
7702
+ var outerArc = d3.arc()
7703
+ .innerRadius(radius * 0.7)
7704
+ .outerRadius(radius * 0.9);
7705
+
7706
+ svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
7707
+
7708
+ var key = function(d) { return d.data.label; };
7709
+
7710
+ state.d3dpie_instance = {
7711
+ svg: svg,
7712
+ width: width,
7713
+ height: height,
7714
+ radius: radius,
7715
+ pie: pie,
7716
+ arc: arc,
7717
+ outerArc: outerArc,
7718
+ key: key
7719
+ };
7720
+
7721
+ NETDATA.d3dpieChange(state.d3dpie_instance, NETDATA.d3dpieSetContent(state, data, 0), 500);
7722
+
7723
+ return true;
7724
+ };
7725
+
7726
// ----------------------------------------------------------------------------------------------------------------
7727
// D3
7728
@@ -8064,6 +8686,44 @@ var NETDATA = window.NETDATA || {};
8686
pixels_per_point: function(state) { void(state); return 15; },
8687
container_class: function(state) { void(state); return 'netdata-container'; }
8688
},
8689
+ "d3pie": {
8690
+ initialize: NETDATA.d3pieInitialize,
8691
+ create: NETDATA.d3pieChartCreate,
8692
+ update: NETDATA.d3pieChartUpdate,
8693
+ resize: null,
8694
+ setSelection: undefined, // function(state, t) { void(state); return true; },
8695
+ clearSelection: undefined, // function(state) { void(state); return true; },
8696
+ toolboxPanAndZoom: null,
8697
+ initialized: false,
8698
+ enabled: true,
8699
+ format: function(state) { void(state); return 'json'; },
8700
+ options: function(state) { void(state); return 'objectrows|ms'; },
8701
+ legend: function(state) { void(state); return null; },
8702
+ autoresize: function(state) { void(state); return false; },
8703
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
8704
+ track_colors: function(state) { void(state); return false; },
8705
+ pixels_per_point: function(state) { void(state); return 15; },
8706
+ container_class: function(state) { void(state); return 'netdata-container'; }
8707
+ },
8708
+ "d3dpie": {
8709
+ initialize: NETDATA.d3dpieInitialize,
8710
+ create: NETDATA.d3dpieChartCreate,
8711
+ update: NETDATA.d3dpieChartUpdate,
8712
+ resize: null,
8713
+ setSelection: NETDATA.d3dpieSetSelection,
8714
+ clearSelection: NETDATA.d3dpieClearSelection,
8715
+ toolboxPanAndZoom: null,
8716
+ initialized: false,
8717
+ enabled: true,
8718
+ format: function(state) { void(state); return 'json'; },
8719
+ options: function(state) { void(state); return 'objectrows|ms'; },
8720
+ legend: function(state) { void(state); return null; },
8721
+ autoresize: function(state) { void(state); return false; },
8722
+ max_updates_to_recreate: function(state) { void(state); return 5000; },
8723
+ track_colors: function(state) { void(state); return false; },
8724
+ pixels_per_point: function(state) { void(state); return 15; },
8725
+ container_class: function(state) { void(state); return 'netdata-container'; }
8726
+ },
8727
"d3": {
8728
initialize: NETDATA.d3Initialize,
8729
create: NETDATA.d3ChartCreate,
web/dashboard.slate.css
+31
@@ -450,6 +450,37 @@ code {
450
height: auto !important;
451
}
452
453
+.d3dpieChart {
454
+ border-radius: 5px 5px 0 0;
455
+ padding-top: 0px;
456
+ margin: 0px auto 0;
457
+ height: 100%;
458
+ background-color: #fff;
459
+}
460
+.d3dpieChart svg {
461
+ width: 100% !important;
462
+ height: 100%;
463
+}
464
+.d3dpieChart path.slice {
465
+ stroke-width: 2px;
466
+}
467
+.d3dpieChart .slice {
468
+ stroke: white;
469
+ stroke-width: 2px;
470
+}
471
+.d3dpieChart .slice:hover{
472
+ opacity: .5;
473
+}
474
+.d3dpieChart .labels text{
475
+ background-color: #333;
476
+ width: 200px;
477
+}
478
+.d3dpieChart polyline{
479
+ stroke: #333;
480
+ stroke-width: 1px;
481
+ fill: none;
482
+}
483
+
484
.easyPieChart {
485
position: relative;
486
text-align: center;