diff --git a/src/rendering.js b/src/rendering.js index a1d3aca..300128b 100644 --- a/src/rendering.js +++ b/src/rendering.js @@ -203,43 +203,37 @@ module.exports = (options) => { }, /** - * @param {{g:Object[]}} data - * @param {Object} nodes + * @param {Node2} node */ - renderNodes: (data, nodes) => { - Object.values(nodes).forEach(node => { - const icon = self.getIcon(node.icon); - if (icon) { - const scale = (node['scale'] || options['icons']['scale']) * DEFAULT_SCALE; - const group = { + renderNode: (node) => { + const icon = self.getIcon(node.icon); + if (!icon) + return null; + const scale = (node['scale'] || options['icons']['scale']) * DEFAULT_SCALE; + return { + '_attributes': { + 'transform': `translate(${(node.x + 0.5) * options['h-spacing']} ${node.y + 0.5})`, + }, + 'g': { + '_attributes': { + 'transform': `scale(${scale / resources.height} ${scale / resources.height}) translate(${-icon.width / 2} ${-256})`, + 'stroke': (node['color'] || options['icons']['color'] || undefined), + 'fill': (node['color'] || options['icons']['color'] || undefined) + }, + 'path': { '_attributes': { - 'transform': `translate(${(node.x + 0.5) * options['h-spacing']} ${node.y + 0.5})`, - }, - 'g': { - '_attributes': { - 'transform': `scale(${scale / resources.height} ${scale / resources.height}) translate(${-icon.width / 2} ${-256})`, - 'stroke': (node['color'] || options['icons']['color'] || undefined), - 'fill': (node['color'] || options['icons']['color'] || undefined) - }, - 'path': { - '_attributes': { - 'd': icon.path, - } - } + 'd': icon.path, } - }; - data['g'].push(group); + } } - }); + }; }, /** - * @param {{g:Object[]}} data * @param {Object} nodes - * @param {Link2[]} links + * @param {Link2} link */ - renderLinks: (data, nodes, links) => { - links.forEach(link => { + renderLink: (nodes, link) => { const src = nodes[link.from]; const dst = nodes[link.to]; @@ -265,9 +259,9 @@ module.exports = (options) => { const path = self.getLinkPath(link.type, size); if (!path) - return; + return null; - const group = { + return { '_attributes': { 'transform': `translate(${posX} ${posY}) rotate(${angle})` }, @@ -284,8 +278,6 @@ module.exports = (options) => { } } }; - data['g'].push(group); - }); }, /** @@ -322,25 +314,28 @@ module.exports = (options) => { */ compute: (nodes, links) => { + const data = {'g': []}; + Object.keys(nodes).forEach(key => { const res = utils.isValid(nodes[key], NODE_DEF); if (res) throw `Node '${key}' is invalid at key '${res}'`; + const group = self.renderNode(nodes[key]); + if (group) + data['g'].push(group); }); links.forEach((link, i) => { const res = utils.isValid(link, LINK_DEF); if (res) throw `Link ${i} (${link.from}->${link.to}) is invalid at key '${res}'`; + const group = self.renderLink(nodes, link); + if (group) + data['g'].push(group); }); const bounds = self.getBounds(nodes); - const data = {'g': []}; - - self.renderNodes(data, nodes); - self.renderLinks(data, nodes, links); - return self.toXML(data, bounds); } }; diff --git a/test/link_path_data.json b/test/link_paths.json similarity index 100% rename from test/link_path_data.json rename to test/link_paths.json diff --git a/test/rendering.test.js b/test/rendering.test.js index 20e2237..3460efe 100644 --- a/test/rendering.test.js +++ b/test/rendering.test.js @@ -5,6 +5,28 @@ const fs = require('fs'); const solidCirclePath = 'M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8z'; const regularCirclePath = 'M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200z'; +let linkPaths = {}; + +/*test('write data', () => { + const data = {}; + ['default', 'line', 'double', 'split-double', 'dashed', 'dashed-line', 'dashed-double', 'dashed-split-double'].forEach(type => { + data[type] = {}; + [1, 1.5, 2].forEach(width => { + data[type][width] = rendering().getLinkPath(type, width); + }); + }); + fs.writeFileSync('test/link_paths.json', JSON.stringify(data), {encoding: 'utf-8'}); +});*/ + +beforeAll((done) => { + + fs.readFile('test/link_paths.json', {encoding: 'utf-8'}, (err, fileData) => { + if (!err) + linkPaths = JSON.parse(fileData); + done(); + }); +}); + describe('resources fail', () => { beforeAll(() => { fs.renameSync('resources.json', 'resources.tmp.json'); @@ -99,29 +121,12 @@ describe('getIcon', () => { }); }); -/*test('write data', () => { - const data = {}; - ['default', 'line', 'double', 'split-double', 'dashed', 'dashed-line', 'dashed-double', 'dashed-split-double'].forEach(type => { - data[type] = {}; - [1, 1.5, 2].forEach(width => { - data[type][width] = rendering().getLinkPath(type, width); - }); - }); - fs.writeFileSync('test/link_path_data.json', JSON.stringify(data), {encoding: 'utf-8'}); -});*/ - describe('getLinkPath (non-regression)', () => { - let data = {}; - - beforeAll(() => { - data = JSON.parse(fs.readFileSync('test/link_path_data.json', {encoding: 'utf-8'})); - }); - ['default', 'line', 'double', 'split-double', 'dashed', 'dashed-line', 'dashed-double', 'dashed-split-double'].forEach(type => { data[type] = {}; [1, 1.5, 2].forEach(width => { test(type + ' ' + width, () => { - expect(rendering().getLinkPath(type, width)).toEqual(data[type][width]); + expect(rendering().getLinkPath(type, width)).toEqual(linkPaths[type][width]); }); }); }); @@ -150,6 +155,10 @@ describe('getBounds', () => { }); }); +describe('renderNode', () => { + +}); + describe('toXML', () => { test('no data', () => { const res = rendering({scale: 20, 'h-spacing': 1}).toXML({}, {w: 0, h: 0}); @@ -174,6 +183,19 @@ describe('compute', () => { const res = rendering({beautify: true, 'h-spacing': 1.2, scale: 20}).compute({}, []); expect(res).toEqual('\n'); }); + test('only invisible things', () => { + const res = rendering({beautify: true, 'h-spacing': 1, scale: 20}).compute({'a': {name: 'a', icon: '', x: 0, y: 0}, 'b': {name: 'b', icon: '', x: 1, y: 0}}, [{from: 'a', to: 'b', type: 'none'}]); + expect(res).toEqual('\n'); + }); + test('simple output', () => { + const res = rendering({beautify: true, 'h-spacing': 1, scale: 20}).compute({'a': {name: 'a', icon: 'circle', x: 0, y: 0}, 'b': {name: 'b', icon: 'circle', x: 1, y: 0}}, [{from: 'a', to: 'b'}]); + + expect(res.split(solidCirclePath).length).toBe(3); //2 times circle path + expect(res.includes(linkPaths['default'][1])).toBe(true); // contains simple arrow of width 1 + expect(res.split('').length).toBe(7); //6 groups definitions + + expect(res.indexOf('')).toBe(0); + }); test('invalid node', () => { try { rendering().compute({ @@ -186,7 +208,7 @@ describe('compute', () => { }); test('invalid link', () => { try { - rendering().compute({}, [{from: 'a', to: 'b'}, {from: 'a', to: 'b', type: 5}]); + rendering().compute({'a': {name: 'a', icon: '', x: 0, y: 0}, 'b': {name: 'b', icon: '', x: 0, y: 0}}, [{from: 'a', to: 'b'}, {from: 'a', to: 'b', type: 5}]); fail('no error thrown'); } catch (err) { expect(err).toBe('Link 1 (a->b) is invalid at key \'type\'');