ONOS-1904 : Initial patchset for defining the Sprite Service.
- reverting topo-theme.css so that the original sprite layer still works (if anyone out there is using it).
- adding hard-coded sprite and layout for testing purposes (they'll be removed later).
Change-Id: I5f78c5cbc66cfe9ad0ac0292d5ffb1e19b611fa5
diff --git a/web/gui/src/main/webapp/app/fw/svg/sprite-theme.css b/web/gui/src/main/webapp/app/fw/svg/sprite-theme.css
new file mode 100644
index 0000000..a65562f
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/svg/sprite-theme.css
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+/* ------------------------------------------------- */
+/* Sprite Layer */
+
+/* TODO: revisit these styles */
+
+
+#ov-topo svg #topo-sprites .gold1 use {
+ stroke: #fda;
+ fill: none;
+}
+#ov-topo svg #topo-sprites .gold1 text {
+ fill: #eda;
+}
+
+#ov-topo svg #topo-sprites .blue1 use {
+ stroke: #bbd;
+ fill: none;
+}
+#ov-topo svg #topo-sprites .blue1 text {
+ fill: #cce;
+}
+
+#ov-topo svg #topo-sprites .gray1 use {
+ stroke: #ccc;
+ fill: none;
+}
+#ov-topo svg #topo-sprites .gray1 text {
+ fill: #ddd;
+}
+
+/* fills */
+#ov-topo svg #topo-sprites use.fill-gray2 {
+ fill: #eee;
+}
+
+#ov-topo svg #topo-sprites use.fill-blue2 {
+ fill: #bce;
+}
\ No newline at end of file
diff --git a/web/gui/src/main/webapp/app/fw/svg/sprite.js b/web/gui/src/main/webapp/app/fw/svg/sprite.js
new file mode 100644
index 0000000..2f24f9b
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/svg/sprite.js
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * ONOS GUI -- SVG -- Sprite Service
+ * For defining sprites and layouts (of sprites).
+ */
+(function () {
+ 'use strict';
+
+ // injected references
+ var $log, fs, sds;
+
+ // configuration of default options
+ var optDefaults = {
+ sprite: {
+ builder: {
+ // none for now
+ },
+ addRect: {
+ // none for now
+ },
+ addPath: {
+ // none for now
+ }
+ },
+ layout: {
+ builder: {
+ grid: 10 // grid square size (in layout coord-space
+ },
+ addSprite: {
+ anchor: 'topleft' // topleft, center
+ },
+ addLabel: {
+ anchor: 'center', // center, left, right
+ fontStyle: 'normal' // normal, italic, bold
+ }
+ }
+ };
+
+ // internal state
+ var sprites, // sprite cache
+ layouts, // layout cache
+ api;
+
+ // ----------------------------------------------------------------------
+ // === Sprite Builder ===
+
+ // Sample usage:
+ //
+ // ss.createSprite('foo', 100, 100)
+ // .addPath('M40,40h20v20h-20z')
+ // .addRect(50, 50, 10, 20)
+ // .register();
+
+ function spriteBuilder(id, w, h, opts) {
+ var o = angular.extend({}, optDefaults.sprite.builder, opts),
+ builder,
+ paths = [],
+ rects = [];
+
+ // TODO: verify id has not already been registered
+
+ // x,y is top left corner; w,h is width and height of rectangle
+ function addRect(x, y, w, h, opts) {
+ var o = angular.extend({}, optDefaults.sprite.addRect, opts);
+
+ rects.push({
+ x: x, y: y, w: w, h: h
+ });
+ return builder;
+ }
+
+ function addPath(d, opts) {
+ var o = angular.extend({}, optDefaults.sprite.addPath, opts);
+
+ if (fs.isS(d)) {
+ paths.push(d);
+ } else if (fs.isA(d)) {
+ paths.push(d.join(''));
+ } else {
+ $log.warn('addPath: path not a string or array', d);
+ }
+ return builder;
+ }
+
+ function register() {
+ sprites.set(id, builder);
+ }
+
+ // define the builder object...
+ builder = {
+ type: 'sprite',
+ data: {
+ id: id,
+ w: w,
+ h: h,
+ opts: o
+ },
+ paths: paths,
+ rects: rects,
+
+ // builder API
+ addRect: addRect,
+ addPath: addPath,
+ register: register
+ };
+
+ return builder;
+ }
+
+ // ----------------------------------------------------------------------
+ // === Layout Builder ===
+
+ // Sample usage:
+ //
+ // ss.createLayout('fooLayout', 400, 300)
+ // .addSprite('foo', 10, 10, 40)
+ // .addSprite('foo', 60, 10, 40)
+ // .addSprite('foo', 110, 10, 40)
+ // .register();
+
+ function layoutBuilder(id, w, h, opts) {
+ var o = angular.extend({}, optDefaults.layout.builder, opts),
+ builder,
+ sprs = [],
+ labs = [];
+
+ // TODO: verify id has not already been registered
+
+ function addSprite(id, x, y, w, opts) {
+ var o = angular.extend({}, optDefaults.layout.addSprite, opts),
+ s = sprites.get(id);
+
+ if (!s) {
+ $log.warn('no such sprite:', id);
+ return builder;
+ }
+
+ sprs.push({
+ sprite: s, x: x, y: y, w: w, anchor: o.anchor
+ });
+ return builder;
+ }
+
+ function addLabel(text, x, y, opts) {
+ var o = angular.extend({}, optDefaults.layout.addLabel, opts);
+
+ labs.push({
+ text: text, x: x, y: y, anchor: o.anchor, style: o.fontStyle
+ });
+ return builder;
+ }
+
+ function register() {
+ layouts.set(id, builder);
+ }
+
+ // define the builder object...
+ builder = {
+ type: 'layout',
+ data: {
+ id: id,
+ w: w,
+ h: h,
+ opts: o
+ },
+ sprites: sprs,
+ labels: labs,
+
+ // builder API
+ addSprite: addSprite,
+ addLabel: addLabel,
+ register: register
+ };
+
+ return builder;
+ }
+
+ // ----------------------------------------------------------------------
+ // === API functions ===
+
+ // Clears the sprite / layout caches.
+ function clear() {
+ sprites = d3.map();
+ layouts = d3.map();
+ }
+
+ // Initializes the sprite / layout caches with core elements.
+ function init() {
+ sds.registerCoreSprites(api);
+ }
+
+ // Returns a sprite "builder", which can be used to programmatically
+ // define a sprite.
+ function createSprite(id, w, h) {
+ $log.debug('createSprite:', id, w, 'x', h);
+ return spriteBuilder(id, w, h);
+ }
+
+ // Returns a layout "builder", which can be used to programmatically
+ // define a layout.
+ function createLayout(id, w, h, grid) {
+ $log.debug('createLayout:', id, w, 'x', h, '(grid=' + grid + ')');
+ return layoutBuilder(id, w, h, grid);
+ }
+
+ // Registers a sprite defined by the given object (JSON structure).
+ function registerSprite(json) {
+ $log.debug('registerSprite:', json);
+ // TODO: create and register a sprite based on JSON data
+ }
+
+ // Registers a layout defined by the given object (JSON structure).
+ function registerLayout(json) {
+ $log.debug('registerLayout:', json);
+ // TODO: create and register a layout based on JSON data
+ }
+
+ // Returns the sprite with the given ID, or undefined otherwise.
+ function sprite(id) {
+ return sprites.get(id);
+ }
+
+ // Returns the layout with the given ID, or undefined otherwise.
+ function layout(id) {
+ layouts.get(id);
+ }
+
+ // Returns a count of registered sprites and layouts.
+ function count() {
+ return {
+ sprites: sprites.size(),
+ layouts: layouts.size()
+ };
+ }
+
+ // Dumps the cache contents to console
+ function dump() {
+ $log.debug('Dumping Caches...');
+ $log.debug('sprites:', sprites);
+ $log.debug('layouts:', layouts);
+ }
+
+ // ----------------------------------------------------------------------
+
+ angular.module('onosSvg')
+ .factory('SpriteService',
+ ['$log', 'FnService', 'SpriteDataService',
+
+ function (_$log_, _fs_, _sds_) {
+ $log = _$log_;
+ fs = _fs_;
+ sds = _sds_;
+
+ api = {
+ clear: clear,
+ init: init,
+ createSprite: createSprite,
+ createLayout: createLayout,
+ registerSprite: registerSprite,
+ registerLayout: registerLayout,
+ sprite: sprite,
+ layout: layout,
+ count: count,
+ dump: dump
+ };
+ return api;
+ }]
+ )
+ .run(['$log', function ($log) {
+ $log.debug('Clearing sprite and layout caches');
+ clear();
+ }]);
+
+}());
diff --git a/web/gui/src/main/webapp/app/fw/svg/spriteData.js b/web/gui/src/main/webapp/app/fw/svg/spriteData.js
new file mode 100644
index 0000000..756d4b1
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/svg/spriteData.js
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * ONOS GUI -- SVG -- Sprite Data Service
+ * Bundled sprite and layout definitions.
+ */
+(function () {
+ 'use strict';
+
+ // ----------------------------------------------------------------------
+ // === Sprite Data ===
+
+ var cloud = {
+ // TODO: define cloud sprite...
+ vbox: '0 0 305 186',
+ d: [
+ "M91.2,48.4C121.2,6.3,187.9-13.4,219,45.6",
+ "M43.1,139.6C21.8,142.9-15.6,108.4,26.1,79",
+ "M103.7,150C89,205.2-11.2,167.4,30.5,138",
+ "M192.3,147.3c-33.5,48-82.1,32.3-94.5-8.2",
+ "M267.1,115c27.9,67.8-77.6,74.3-83.1,41",
+ "M34.3,89.9C10.8,79,59.5,10.7,97.2,39.6",
+ "M211.9,34.2c51.9-38.8,118,57.4,59,94.5"
+ ],
+ style: {
+ fill: 'none',
+ 'stroke-miterlimit': 10
+ }
+ };
+
+ // TODO: define other core sprites here...
+
+ // ----------------------------------------------------------------------
+ // === API functions ===
+
+ function registerCoreSprites(ssApi) {
+ ssApi.registerSprite(cloud);
+
+ // TODO: add base set of sprites here ...
+
+ // ----------------------------------------------------------$$$
+ // This following code is for initial development of Topo2 sprite layer
+ ssApi.createSprite('rack', 40, 50)
+ .addRect(0, 0, 40, 50)
+ .addPath([
+ 'M5,20h30v5h-30z',
+ 'M5,30h30v5h-30z',
+ 'M5,40h30v5h-30z'
+ ])
+ .register();
+
+ ssApi.createLayout('segmentRouting', 130, 75)
+ .addSprite('rack', 10, 40, 20)
+ .addSprite('rack', 40, 40, 20)
+ .addSprite('rack', 70, 40, 20)
+ .addSprite('rack', 100, 40, 20)
+ .addLabel('Segment Routing', 120, 10, {anchor: 'right'})
+ .register();
+
+ ssApi.dump();
+ // ----------------------------------------------------------$$$
+ }
+
+ // ----------------------------------------------------------------------
+
+ angular.module('onosSvg')
+ .factory('SpriteDataService', [
+ function () {
+ return {
+ registerCoreSprites: registerCoreSprites
+ };
+ }
+ ]);
+
+}());
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 40edebe..9f85a21 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -69,6 +69,8 @@
<script src="app/fw/svg/map.js"></script>
<script src="app/fw/svg/zoom.js"></script>
<script src="app/fw/svg/svgUtil.js"></script>
+ <script src="app/fw/svg/sprite.js"></script>
+ <script src="app/fw/svg/spriteData.js"></script>
<script src="app/fw/remote/remote.js"></script>
<script src="app/fw/remote/urlfn.js"></script>
@@ -104,6 +106,7 @@
<link rel="stylesheet" href="app/fw/mast/mast-theme.css">
<link rel="stylesheet" href="app/fw/svg/glyph.css">
<link rel="stylesheet" href="app/fw/svg/glyph-theme.css">
+ <link rel="stylesheet" href="app/fw/svg/sprite-theme.css">
<link rel="stylesheet" href="app/fw/svg/icon.css">
<link rel="stylesheet" href="app/fw/svg/icon-theme.css">
<link rel="stylesheet" href="app/fw/layer/panel.css">
@@ -264,7 +267,7 @@
<script>
<!-- Inject user agent info into html element to allow CSS sensitivity. -->
(function () {
- var t = !!('ontouchstart' in window) || !!('onmsgesturechange' in window);
+ var t = ('ontouchstart' in window) || ('onmsgesturechange' in window);
d3.select(document.documentElement)
.attr('data-useragent', navigator.userAgent)
.attr('data-platform', navigator.platform)
diff --git a/web/gui/src/main/webapp/onos.js b/web/gui/src/main/webapp/onos.js
index 2e0d651..631ef84 100644
--- a/web/gui/src/main/webapp/onos.js
+++ b/web/gui/src/main/webapp/onos.js
@@ -91,10 +91,10 @@
'$log', '$scope', '$route', '$routeParams', '$location',
'KeyService', 'ThemeService', 'GlyphService', 'VeilService',
'PanelService', 'FlashService', 'QuickHelpService', 'EeService',
- 'WebSocketService',
+ 'WebSocketService', 'SpriteService',
function (_$log_, $scope, $route, $routeParams, $location,
- ks, ts, gs, vs, ps, flash, qhs, ee, wss) {
+ ks, ts, gs, vs, ps, flash, qhs, ee, wss, ss) {
var self = this;
$log = _$log_;
@@ -112,6 +112,7 @@
ks.installOn(d3.select('body'));
ks.bindQhs(qhs);
gs.init();
+ ss.init();
vs.init();
ps.init();
saucy(ee, ks);
diff --git a/web/gui/src/main/webapp/tests/app/fw/svg/sprite-spec.js b/web/gui/src/main/webapp/tests/app/fw/svg/sprite-spec.js
new file mode 100644
index 0000000..ed7c315
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/fw/svg/sprite-spec.js
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ ONOS GUI -- SVG -- Sprite Service - Unit Tests
+ */
+
+describe('factory: fw/svg/sprite.js', function () {
+ var $log, fs, ss, d3Elem, svg;
+
+ // config...
+ var numBaseSprites = 1,
+ sampleData = 'M91.2,48.4C121.2,6.3,187.9-13.4,219,45.6';
+
+ // load modules we need
+ beforeEach(module('onosUtil', 'onosSvg'));
+
+ // inject the services we need
+ beforeEach(inject(function (_$log_, FnService, SpriteService) {
+ var body = d3.select('body');
+ $log = _$log_;
+ fs = FnService;
+ ss = SpriteService;
+
+ // NOTE: once we get to loading sprites into the DOM, we'll need these:
+ // d3Elem = body.append('defs').attr('id', 'myDefs');
+ // svg = body.append('svg').attr('id', 'mySvg');
+ }));
+
+ // clean up after each test
+ afterEach(function () {
+ // d3.select('#mySvg').remove();
+ // d3.select('#myDefs').remove();
+ ss.clear();
+ });
+
+ // === UNIT TESTS ===
+
+ it('should define SpriteService', function () {
+ expect(ss).toBeDefined();
+ });
+
+ it('should define api functions', function () {
+ expect(fs.areFunctions(ss, [
+ 'clear', 'init',
+ 'createSprite', 'createLayout',
+ 'registerSprite', 'registerLayout',
+ 'sprite', 'layout',
+ 'count', 'dump'
+ ])).toBe(true);
+ });
+
+ it('should start no sprites or layouts', function () {
+ var c = ss.count();
+ expect(c.sprites).toBe(0);
+ expect(c.layouts).toBe(0);
+ });
+
+ // Programmatic build of a sprite
+ it('should register a simple sprite', function () {
+ ss.createSprite('foo', 303, 185)
+ .addPath(sampleData)
+ .register();
+
+ expect(ss.count().sprites).toBe(1);
+
+ var s = ss.sprite('foo');
+ expect(s).toBeDefined();
+ // TODO: verify internal structure of sprite
+
+ });
+});
\ No newline at end of file