blob: 8b1c4992ab2ddaf24c9fd749d6d9b3750a73352d [file] [log] [blame]
Simon Hunt737c89f2015-01-28 12:23:19 -08001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Simon Hunt737c89f2015-01-28 12:23:19 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- SVG -- Util Service
19 */
20
21/*
22 The SVG Util Service provides a miscellany of utility functions.
23 */
24
25(function () {
26 'use strict';
27
28 // injected references
29 var $log, fs;
30
Simon Huntf4ef6dd2016-02-03 17:05:14 -080031 // TODO: change 'force' ref to be 'force.alpha' ref.
32 function createDragBehavior(force, selectCb, atDragEnd,
33 dragEnabled, clickEnabled) {
34 var draggedThreshold = d3.scale.linear()
35 .domain([0, 0.1])
36 .range([5, 20])
37 .clamp(true),
38 drag,
39 fSel = fs.isF(selectCb),
40 fEnd = fs.isF(atDragEnd),
41 fDEn = fs.isF(dragEnabled),
42 fCEn = fs.isF(clickEnabled),
43 bad = [];
44
45 function naf(what) {
46 return 'SvgUtilService: createDragBehavior(): ' + what +
47 ' is not a function';
48 }
49
50 if (!force) {
51 bad.push('SvgUtilService: createDragBehavior(): ' +
52 'Bad force reference');
53 }
54 if (!fSel) {
55 bad.push(naf('selectCb'));
56 }
57 if (!fEnd) {
58 bad.push(naf('atDragEnd'));
59 }
60 if (!fDEn) {
61 bad.push(naf('dragEnabled'));
62 }
63 if (!fCEn) {
64 bad.push(naf('clickEnabled'));
65 }
66
67 if (bad.length) {
68 $log.error(bad.join('\n'));
69 return null;
70 }
71
72 function dragged(d) {
73 var threshold = draggedThreshold(force.alpha()),
74 dx = d.oldX - d.px,
75 dy = d.oldY - d.py;
76 if (Math.abs(dx) >= threshold || Math.abs(dy) >= threshold) {
77 d.dragged = true;
78 }
79 return d.dragged;
80 }
81
82 drag = d3.behavior.drag()
83 .origin(function(d) { return d; })
84 .on('dragstart', function(d) {
85 if (clickEnabled() || dragEnabled()) {
86 d3.event.sourceEvent.stopPropagation();
87
88 d.oldX = d.x;
89 d.oldY = d.y;
90 d.dragged = false;
91 d.fixed |= 2;
92 d.dragStarted = true;
93 }
94 })
95 .on('drag', function(d) {
96 if (dragEnabled()) {
97 d.px = d3.event.x;
98 d.py = d3.event.y;
99 if (dragged(d)) {
100 if (!force.alpha()) {
101 force.alpha(.025);
102 }
103 }
104 }
105 })
106 .on('dragend', function(d) {
Steven Burrowse3a18842016-09-22 15:33:33 +0100107 d3.event.sourceEvent.preventDefault();
108
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800109 if (d.dragStarted) {
110 d.dragStarted = false;
111 if (!dragged(d)) {
112 // consider this the same as a 'click'
113 // (selection of a node)
114 if (clickEnabled()) {
115 selectCb.call(this, d);
116 }
117 }
118 d.fixed &= ~6;
119
120 // hook at the end of a drag gesture
121 if (dragEnabled()) {
122 atDragEnd.call(this, d);
123 }
124 }
125 });
126
127 return drag;
128 }
129
130
131 function loadGlow(defs, r, g, b, id) {
132 var glow = defs.append('filter')
133 .attr('x', '-50%')
134 .attr('y', '-50%')
135 .attr('width', '200%')
136 .attr('height', '200%')
137 .attr('id', id);
138
139 glow.append('feColorMatrix')
140 .attr('type', 'matrix')
141 .attr('values',
142 '0 0 0 0 ' + r + ' ' +
143 '0 0 0 0 ' + g + ' ' +
144 '0 0 0 0 ' + b + ' ' +
145 '0 0 0 1 0 ');
146
147 glow.append('feGaussianBlur')
148 .attr('stdDeviation', 3)
149 .attr('result', 'coloredBlur');
150
151 glow.append('feMerge').selectAll('feMergeNode')
152 .data(['coloredBlur', 'SourceGraphic'])
153 .enter().append('feMergeNode')
154 .attr('in', String);
155 }
156
Simon Hunt95f4b422017-03-03 13:49:05 -0800157 // deprecated -- we'll use something else to highlight instances for affinity
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800158 function loadGlowDefs(defs) {
159 loadGlow(defs, 0.0, 0.0, 0.7, 'blue-glow');
160 loadGlow(defs, 1.0, 1.0, 0.3, 'yellow-glow');
161 }
162
163 // --- Ordinal scales for 7 values.
164
Simon Hunta9761342016-06-10 18:02:53 -0700165 // Colors per Mojo-Design's color palette..
Simon Huntdf2a4e62016-08-11 14:21:56 -0700166 // blue red dk grey steel lt blue lt red lt grey
167 var lightNorm = ['#5b99d2', '#d05a55', '#716b6b', '#7e9aa8', '#66cef6', '#db7773', '#aeada8' ],
168 lightMute = ['#a8cceb', '#f1a7a7', '#b9b5b5', '#bdcdd5', '#a8e9fd', '#f8c9c9', '#d7d6d4' ],
Simon Hunta9761342016-06-10 18:02:53 -0700169 // TODO: dark theme
Simon Huntdf2a4e62016-08-11 14:21:56 -0700170 darkNorm = ['#5b99d2', '#d05a55', '#716b6b', '#7e9aa8', '#66cef6', '#db7773', '#aeada8' ],
171 darkMute = ['#a8cceb', '#f1a7a7', '#b9b5b5', '#bdcdd5', '#a8e9fd', '#f8c9c9', '#d7d6d4' ];
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800172
173 var colors= {
174 light: {
175 norm: d3.scale.ordinal().range(lightNorm),
176 mute: d3.scale.ordinal().range(lightMute)
177 },
178 dark: {
179 norm: d3.scale.ordinal().range(darkNorm),
180 mute: d3.scale.ordinal().range(darkMute)
181 }
182 };
183
184 function cat7() {
185 var tcid = 'd3utilTestCard';
186
187 function getColor(id, muted, theme) {
188 // NOTE: since we are lazily assigning domain ids, we need to
189 // get the color from all 4 scales, to keep the domains
190 // in sync.
191 var ln = colors.light.norm(id),
192 lm = colors.light.mute(id),
193 dn = colors.dark.norm(id),
194 dm = colors.dark.mute(id);
195 if (theme === 'dark') {
196 return muted ? dm : dn;
197 } else {
198 return muted ? lm : ln;
199 }
200 }
201
202 function testCard(svg) {
203 var g = svg.select('g#' + tcid),
204 dom = d3.range(7),
205 k, muted, theme, what;
206
207 if (!g.empty()) {
208 g.remove();
209
210 } else {
211 g = svg.append('g')
212 .attr('id', tcid)
213 .attr('transform', 'scale(4)translate(20,20)');
214
215 for (k=0; k<4; k++) {
216 muted = k%2;
217 what = muted ? ' muted' : ' normal';
218 theme = k < 2 ? 'light' : 'dark';
219 dom.forEach(function (id, i) {
220 var x = i * 20,
221 y = k * 20,
Simon Hunta9761342016-06-10 18:02:53 -0700222 f = getColor(id, muted, theme);
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800223 g.append('circle').attr({
224 cx: x,
225 cy: y,
226 r: 5,
227 fill: f
228 });
229 });
230 g.append('rect').attr({
231 x: 140,
232 y: k * 20 - 5,
233 width: 32,
234 height: 10,
235 rx: 2,
236 fill: '#888'
237 });
238 g.append('text').text(theme + what)
239 .attr({
240 x: 142,
241 y: k * 20 + 2,
242 fill: 'white'
243 })
244 .style('font-size', '4pt');
245 }
246 }
247 }
248
249 return {
250 testCard: testCard,
251 getColor: getColor
252 };
253 }
254
255 function translate(x, y) {
256 if (fs.isA(x) && x.length === 2 && !y) {
257 return 'translate(' + x[0] + ',' + x[1] + ')';
258 }
259 return 'translate(' + x + ',' + y + ')';
260 }
261
262 function scale(x, y) {
263 return 'scale(' + x + ',' + y + ')';
264 }
265
266 function skewX(x) {
267 return 'skewX(' + x + ')';
268 }
269
270 function rotate(deg) {
271 return 'rotate(' + deg + ')';
272 }
273
274 function stripPx(s) {
275 return s.replace(/px$/,'');
276 }
277
278 function safeId(s) {
279 return s.replace(/[^a-z0-9]/gi, '-');
280 }
281
282 function makeVisible(el, b) {
283 el.style('visibility', (b ? 'visible' : 'hidden'));
284 }
285
286 function isVisible(el) {
287 return el.style('visibility') === 'visible';
288 }
289
290 function visible(el, x) {
291 if (x === undefined) {
292 return isVisible(el);
293 } else {
294 makeVisible(el, x);
295 }
296 }
297
Simon Hunt737c89f2015-01-28 12:23:19 -0800298 angular.module('onosSvg')
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800299 .factory('SvgUtilService', ['$log', 'FnService',
Simon Hunt737c89f2015-01-28 12:23:19 -0800300 function (_$log_, _fs_) {
301 $log = _$log_;
302 fs = _fs_;
303
Simon Hunt737c89f2015-01-28 12:23:19 -0800304 return {
305 createDragBehavior: createDragBehavior,
Simon Hunt0ee28682015-02-12 20:48:11 -0800306 loadGlowDefs: loadGlowDefs,
Simon Huntc9b73162015-01-29 14:02:15 -0800307 cat7: cat7,
Simon Hunt4b668592015-01-29 17:33:53 -0800308 translate: translate,
Simon Hunt56004a82015-02-19 13:53:20 -0800309 scale: scale,
310 skewX: skewX,
311 rotate: rotate,
Simon Hunt7c8ab8d2015-02-03 15:05:15 -0800312 stripPx: stripPx,
Simon Hunt18bf9822015-02-12 17:35:45 -0800313 safeId: safeId,
Simon Huntf4ef6dd2016-02-03 17:05:14 -0800314 visible: visible
Simon Hunt737c89f2015-01-28 12:23:19 -0800315 };
316 }]);
317}());