diff --git a/src/components/Graph/NodeColorSettings.vue b/src/components/Graph/NodeColorSettings.vue index 7517532..804d6e5 100644 --- a/src/components/Graph/NodeColorSettings.vue +++ b/src/components/Graph/NodeColorSettings.vue @@ -35,7 +35,12 @@ /> - + { if (node[nodeId]) { graph.addNode(node[nodeId], { - data: node, - labelColor: options.style.nodes.label.color + data: node }) } }) @@ -56,7 +55,7 @@ export function buildNodes(graph, dataSources, options) { } export function buildEdges(graph, dataSources, options) { - const docColumn = Object.keys(dataSources)[0] || 'doc' + const docColumn = Object.keys(dataSources)[0] const { objectType, edgeSource, edgeTarget } = options.structure if (objectType && edgeSource && edgeTarget) { @@ -69,8 +68,7 @@ export function buildEdges(graph, dataSources, options) { const target = edge[edgeTarget] if (graph.hasNode(source) && graph.hasNode(target)) { graph.addEdge(source, target, { - data: edge, - labelColor: options.style.edges.label.color + data: edge }) } }) @@ -261,7 +259,6 @@ function getColorMethod( colorscale[index % colorscale.length] ]) ) - return (attributes, nodeId) => { const category = sourceGetter(nodeId, attributes) attributes.color = colorMap[category] @@ -277,6 +274,7 @@ function getColorMethod( const value = sourceGetter(nodeId, attributes) const normalizedValue = (value - min) / (max - min) if (isNaN(normalizedValue)) { + attributes.color = '#000000' return } const exactMatch = normalizedColorscale.find( @@ -288,9 +286,9 @@ function getColorMethod( } const rightColorIndex = normalizedColorscale.findIndex( - ([value]) => value >= normalizedValue + ([value]) => value > normalizedValue ) - const leftColorIndex = (rightColorIndex || 1) - 1 + const leftColorIndex = rightColorIndex - 1 const right = normalizedColorscale[rightColorIndex] const left = normalizedColorscale[leftColorIndex] const interpolationFactor = @@ -327,18 +325,3 @@ function getEdgeValueScale(graph, sourceGetter) { }, new Set()) return Array.from(scaleSet).sort((a, b) => a - b) } - -export function getOptionsFromDataSources(dataSources) { - if (!dataSources) { - return [] - } - - return Object.keys(dataSources).map(name => ({ - value: name, - label: name - })) -} - -export default { - getOptionsFromDataSources -} diff --git a/src/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/index.vue b/src/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/index.vue index fd3dbbb..8d091d6 100644 --- a/src/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/index.vue +++ b/src/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/index.vue @@ -31,7 +31,7 @@ import fIo from '@/lib/utils/fileIo' import $ from 'jquery' import 'pivottable' import 'pivottable/dist/pivot.css' -import PivotUi from './PivotUi' +import PivotUi from './PivotUi/index.vue' import pivotHelper from './pivotHelper' import Chart from '@/views/MainView/Workspace/Tabs/Tab/DataView/Chart' import chartHelper from '@/lib/chartHelper' diff --git a/tests/lib/graphHelper.spec.js b/tests/lib/graphHelper.spec.js new file mode 100644 index 0000000..7bb7953 --- /dev/null +++ b/tests/lib/graphHelper.spec.js @@ -0,0 +1,1206 @@ +import { expect } from 'chai' +import sinon from 'sinon' +import * as graphHelper from '@/lib/graphHelper' +import Graph from 'graphology' + +describe('graphHelper.js', () => { + afterEach(() => { + sinon.restore() + }) + + it('dataSourceIsValid returns false if data source is not valid for graph', () => { + // no columns + let dataSources = {} + + expect(graphHelper.dataSourceIsValid(dataSources)).to.eql(false) + + // the records are not JSONs + dataSources = { + id: [1, 2] + } + + expect(graphHelper.dataSourceIsValid(dataSources)).to.eql(false) + + // too few keys in JSON + dataSources = { + doc: ['{"id": 1}', '{"id": 2}'] + } + + expect(graphHelper.dataSourceIsValid(dataSources)).to.eql(false) + + // no key that could be an object type + dataSources = { + doc: ['{"foo": "hello", "type": 1}', '{"object_type": 0, "bar": true}'] + } + + expect(graphHelper.dataSourceIsValid(dataSources)).to.eql(false) + + // valid + dataSources = { + doc: ['{"foo": "hello", "type": 1}', '{"type": 0, "bar": true}'] + } + + expect(graphHelper.dataSourceIsValid(dataSources)).to.eql(true) + }) + + it('buildNodes', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "dog"}', + '{"type": 0, "node_id": null, "label": "bird"}', + '{"object_type": 0, "node_id": 4, "label": "insect"}', + '{"type": 1, "source": 1, "target": ""}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: null, + objectType: null, + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + expect(graph.export().nodes).to.eql([]) + + graph.clear() + + options.structure.nodeId = 'node_id' + options.structure.objectType = 'type' + graphHelper.buildNodes(graph, dataSources, options) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { data: { type: 0, node_id: 1, label: 'cat' } } + }, + { + key: '2', + attributes: { data: { type: 0, node_id: 2, label: 'dog' } } + } + ]) + }) + + it('buildEdges', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "dog"}', + '{"type": 0, "node_id": 3, "label": "bird"}', + '{"type": 1, "source": 1, "target": 2}', + '{"type": 1, "source": 1, "target": 8}', + '{"type": 1, "from": 1, "to": 3}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: null, + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + expect(graph.export().edges).to.eql([]) + + graph.clear() + + options.structure.objectType = 'type' + options.structure.edgeSource = 'source' + options.structure.edgeTarget = 'target' + + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + + const edges = graph.export().edges + expect(edges.length).to.eql(1) + expect(edges[0].source).to.equal('1') + expect(edges[0].target).to.equal('2') + expect(edges[0].attributes).to.eql({ + data: { type: 1, source: 1, target: 2 } + }) + }) + + it('udpateNodes - lables', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "dog"}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + label: { + source: 'label', + color: 'green' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, label: 'cat' }, + label: 'cat', + labelColor: 'green' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, label: 'dog' }, + label: 'dog', + labelColor: 'green' + } + } + ]) + + graphHelper.updateNodes(graph, { + label: { + source: null, + color: 'green' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, label: 'cat' }, + label: '', + labelColor: 'green' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, label: 'dog' }, + label: '', + labelColor: 'green' + } + } + ]) + }) + + it('udpateEdges - lables', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "mouse"}', + '{"type": 1, "source": 1, "target": 2, "label": "eats"}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + label: { + source: 'label', + color: 'green' + } + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, label: 'eats' }, + label: 'eats', + labelColor: 'green' + } + ]) + + graphHelper.updateEdges(graph, { + label: { + source: null, + color: 'green' + } + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, label: 'eats' }, + label: '', + labelColor: 'green' + } + ]) + }) + + it('udpateNodes - size - constant', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "dog"}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + size: { + type: 'constant', + value: 25 + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, label: 'cat' }, + size: 25 + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, label: 'dog' }, + size: 25 + } + } + ]) + }) + + it('udpateEdges - size - constant', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "mouse"}', + '{"type": 1, "source": 1, "target": 2}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + size: { + type: 'constant', + value: 20 + } + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2 }, + size: 20 + } + ]) + }) + + it('udpateNodes - size - variable', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "points": 0}', + '{"type": 0, "node_id": 2, "points": 8}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + size: { + type: 'variable', + source: 'points', + scale: 4, + mode: 'diameter', + min: 1 + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, points: 0 }, + size: 0.5 + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, points: 8 }, + size: 16 + } + } + ]) + + graphHelper.updateNodes(graph, { + size: { + type: 'variable', + source: 'points', + scale: 4, + mode: 'area', + min: 1 + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, points: 0 }, + size: 0.5 + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, points: 8 }, + size: 4 + } + } + ]) + }) + + it('udpateEdges - size - variable', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "mouse"}', + '{"type": 0, "node_id": 3, "label": "cheese"}', + '{"type": 1, "source": 1, "target": 2, "weight": 5}', + '{"type": 1, "source": 2, "target": 3, "weight": 2}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + size: { + type: 'variable', + source: 'weight', + scale: 2, + min: 6 + } + }) + + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, weight: 5 }, + size: 10 + }, + { + data: { type: 1, source: 2, target: 3, weight: 2 }, + size: 6 + } + ]) + }) + + it('udpateNodes - size - computed', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1}', // 0 + '{"type": 0, "node_id": 2}', // 2 + '{"type": 0, "node_id": 3}', // 0 + '{"type": 1, "source": 2, "target": 1}', + '{"type": 1, "source": 2, "target": 3}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateNodes(graph, { + size: { + type: 'calculated', + method: 'outDegree', + scale: 4, + mode: 'diameter', + min: 1 + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + size: 0.5 + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + size: 4 + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + size: 0.5 + } + } + ]) + + graphHelper.updateNodes(graph, { + size: { + type: 'calculated', + method: 'outDegree', + scale: 4, + mode: 'area', + min: 1 + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + size: 0.5 + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + size: 2 + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + size: 0.5 + } + } + ]) + }) + + it('udpateNodes - color - constant', () => { + const dataSources = { + doc: ['{"type": 0, "node_id": 1}', '{"type": 0, "node_id": 2}'] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + color: { + type: 'constant', + value: '#a1b8c3' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + color: '#a1b8c3' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + color: '#a1b8c3' + } + } + ]) + }) + + it('udpateEdges - color - constant', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "mouse"}', + '{"type": 1, "source": 1, "target": 2}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + color: { + type: 'constant', + value: '#df78af' + } + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2 }, + color: '#df78af' + } + ]) + }) + + it('udpateNodes - color - variable', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "color": "red", "points": 5}', + '{"type": 0, "node_id": 2, "color": "#abcdff", "points": 15}', + '{"type": 0, "node_id": 3, "color": "#123456", "points": 10}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'color', + sourceUsage: 'direct' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#ff0000' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#abcdff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#123456' + } + } + ]) + + const colorscale = ['#aaaaff', '#8888ff', '#6666ff', '#4444ff', '#0000ff'] + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'points', + sourceUsage: 'map_to', + colorscale, + mode: 'categorical', + colorscaleDirection: 'normal' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#aaaaff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#6666ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#8888ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'points', + sourceUsage: 'map_to', + colorscale, + mode: 'categorical', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#0000ff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#6666ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#4444ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'points', + sourceUsage: 'map_to', + colorscale, + mode: 'continious', + colorscaleDirection: 'normal' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#aaaaff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#0000ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#6666ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'points', + sourceUsage: 'map_to', + colorscale, + mode: 'continious', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#0000ff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#aaaaff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#6666ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'points', + sourceUsage: 'map_to', + colorscale: ['#aaaaff', '#0000ff'], + mode: 'continious', + colorscaleDirection: 'normal' + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, color: 'red', points: 5 }, + color: '#aaaaff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, color: '#abcdff', points: 15 }, + color: '#0000ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3, color: '#123456', points: 10 }, + color: '#5555ff' + } + } + ]) + }) + + it('udpateNodes makes nodes black when apply continious color for categories', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "country": "NL"}', + '{"type": 0, "node_id": 2, "country": "GB"}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: null, + edgeTarget: null + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.updateNodes(graph, { + color: { + type: 'variable', + source: 'country', + sourceUsage: 'map_to', + mode: 'continious', + colorscaleDirection: 'normal' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1, country: 'NL' }, + color: '#000000' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2, country: 'GB' }, + color: '#000000' + } + } + ]) + }) + + it('udpateEdges - color - variable', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1, "label": "cat"}', + '{"type": 0, "node_id": 2, "label": "mouse"}', + '{"type": 0, "node_id": 3, "label": "cheese"}', + '{"type": 1, "source": 1, "target": 2, "color": "red", "weight": 5}', + '{"type": 1, "source": 1, "target": 3, "color": "red", "weight": 15}', + '{"type": 1, "source": 2, "target": 3, "color": "red", "weight": 10}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + color: { + type: 'variable', + source: 'color', + sourceUsage: 'direct' + } + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, color: 'red', weight: 5 }, + color: '#ff0000' + }, + { + data: { type: 1, source: 1, target: 3, color: 'red', weight: 15 }, + color: '#ff0000' + }, + { + data: { type: 1, source: 2, target: 3, color: 'red', weight: 10 }, + color: '#ff0000' + } + ]) + + const colorscale = ['#aaaaff', '#8888ff', '#6666ff', '#4444ff', '#0000ff'] + graphHelper.updateEdges(graph, { + color: { + type: 'variable', + source: 'weight', + sourceUsage: 'map_to', + colorscale, + mode: 'categorical', + colorscaleDirection: 'normal' + } + }) + + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, color: 'red', weight: 5 }, + color: '#aaaaff' + }, + { + data: { type: 1, source: 1, target: 3, color: 'red', weight: 15 }, + color: '#6666ff' + }, + { + data: { type: 1, source: 2, target: 3, color: 'red', weight: 10 }, + color: '#8888ff' + } + ]) + + graphHelper.updateEdges(graph, { + color: { + type: 'variable', + source: 'weight', + sourceUsage: 'map_to', + colorscale, + mode: 'categorical', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, color: 'red', weight: 5 }, + color: '#0000ff' + }, + { + data: { type: 1, source: 1, target: 3, color: 'red', weight: 15 }, + color: '#6666ff' + }, + { + data: { type: 1, source: 2, target: 3, color: 'red', weight: 10 }, + color: '#4444ff' + } + ]) + + graphHelper.updateEdges(graph, { + color: { + type: 'variable', + source: 'weight', + sourceUsage: 'map_to', + colorscale, + mode: 'continious', + colorscaleDirection: 'normal' + } + }) + + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, color: 'red', weight: 5 }, + color: '#aaaaff' + }, + { + data: { type: 1, source: 1, target: 3, color: 'red', weight: 15 }, + color: '#0000ff' + }, + { + data: { type: 1, source: 2, target: 3, color: 'red', weight: 10 }, + color: '#6666ff' + } + ]) + + graphHelper.updateEdges(graph, { + color: { + type: 'variable', + source: 'weight', + sourceUsage: 'map_to', + colorscale, + mode: 'continious', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2, color: 'red', weight: 5 }, + color: '#0000ff' + }, + { + data: { type: 1, source: 1, target: 3, color: 'red', weight: 15 }, + color: '#aaaaff' + }, + { + data: { type: 1, source: 2, target: 3, color: 'red', weight: 10 }, + color: '#6666ff' + } + ]) + }) + + it('udpateNodes - color - calculated', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1}', + '{"type": 0, "node_id": 2}', + '{"type": 0, "node_id": 3}', + '{"type": 1, "source": 2, "target": 3}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + + const colorscale = ['#aaaaff', '#8888ff', '#6666ff', '#4444ff', '#0000ff'] + + graphHelper.updateNodes(graph, { + color: { + type: 'calculated', + method: 'degree', + colorscale, + mode: 'categorical', + colorscaleDirection: 'normal' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + color: '#aaaaff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + color: '#8888ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + color: '#8888ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'calculated', + method: 'outDegree', + colorscale, + mode: 'categorical', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + color: '#0000ff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + color: '#4444ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + color: '#0000ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'calculated', + method: 'degree', + colorscale, + mode: 'continious', + colorscaleDirection: 'normal' + } + }) + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + color: '#aaaaff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + color: '#0000ff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + color: '#0000ff' + } + } + ]) + + graphHelper.updateNodes(graph, { + color: { + type: 'calculated', + method: 'degree', + colorscale, + mode: 'continious', + colorscaleDirection: 'reversed' + } + }) + + expect(graph.export().nodes).to.eql([ + { + key: '1', + attributes: { + data: { type: 0, node_id: 1 }, + color: '#0000ff' + } + }, + { + key: '2', + attributes: { + data: { type: 0, node_id: 2 }, + color: '#aaaaff' + } + }, + { + key: '3', + attributes: { + data: { type: 0, node_id: 3 }, + color: '#aaaaff' + } + } + ]) + }) + + it('udpateEdges - direction', () => { + const dataSources = { + doc: [ + '{"type": 0, "node_id": 1}', + '{"type": 0, "node_id": 2}', + '{"type": 1, "source": 1, "target": 2}' + ] + } + const graph = new Graph() + const options = { + structure: { + nodeId: 'node_id', + objectType: 'type', + edgeSource: 'source', + edgeTarget: 'target' + } + } + graphHelper.buildNodes(graph, dataSources, options) + graphHelper.buildEdges(graph, dataSources, options) + graphHelper.updateEdges(graph, { + showDirection: true + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2 }, + type: 'arrow' + } + ]) + + graphHelper.updateEdges(graph, { + showDirection: false + }) + expect(graph.export().edges.map(edge => edge.attributes)).to.eql([ + { + data: { type: 1, source: 1, target: 2 }, + type: 'line' + } + ]) + }) +}) diff --git a/tests/views/MainView/Workspace/Tabs/Tab/DataView/Chart/Chart.spec.js b/tests/views/MainView/Workspace/Tabs/Tab/DataView/Chart/Chart.spec.js index 74b6ad8..8d0234f 100644 --- a/tests/views/MainView/Workspace/Tabs/Tab/DataView/Chart/Chart.spec.js +++ b/tests/views/MainView/Workspace/Tabs/Tab/DataView/Chart/Chart.spec.js @@ -15,7 +15,6 @@ describe('Chart.vue', () => { }) it('getOptionsForSave called with proper arguments', () => { - // mount the component const wrapper = mount(Chart, { global: { mocks: { $store } @@ -30,7 +29,6 @@ describe('Chart.vue', () => { }) it('emits update when plotly updates', async () => { - // mount the component const wrapper = mount(Chart, { global: { mocks: { $store } @@ -48,7 +46,6 @@ describe('Chart.vue', () => { points: [80] } - // mount the component const wrapper = mount(Chart, { props: { dataSources, @@ -208,4 +205,40 @@ describe('Chart.vue', () => { expect(wrapper.find('.Select__menu').text()).to.contain('name' + 'points') wrapper.unmount() }) + + it('hides and shows controls depending on showViewSettings and resizes the plot', async () => { + const wrapper = mount(Chart, { + attachTo: document.body, + props: { + dataSources: null + }, + global: { + mocks: { $store } + } + }) + + // don't call flushPromises here, otherwize resize observer will be call to often + // which causes ResizeObserver loop completed with undelivered notifications. + await nextTick() + + const plot = wrapper.find('.svg-container').wrapperElement + + const initialPlotWidth = plot.scrollWidth + const initialPlotHeight = plot.scrollHeight + + expect(wrapper.find('.plotly_editor .editor_controls').exists()).to.equal( + false + ) + + await wrapper.setProps({ showViewSettings: true }) + + await flushPromises() + + expect(plot.scrollWidth).not.to.equal(initialPlotWidth) + expect(plot.scrollHeight).not.to.equal(initialPlotHeight) + expect(wrapper.find('.plotly_editor .editor_controls').exists()).to.equal( + true + ) + wrapper.unmount() + }) }) diff --git a/tests/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/Pivot.spec.js b/tests/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/Pivot.spec.js index af220d8..1f5ffcb 100644 --- a/tests/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/Pivot.spec.js +++ b/tests/views/MainView/Workspace/Tabs/Tab/DataView/Pivot/Pivot.spec.js @@ -586,4 +586,48 @@ describe('Pivot.vue', () => { wrapper.unmount() }) + + it('hides or shows controlls depending on showViewSettings and resizes standart chart', async () => { + const wrapper = mount(Pivot, { + global: { + mocks: { $store: { state: { isWorkspaceVisible: true } } } + }, + props: { + dataSources: { + item: ['foo', 'bar', 'bar', 'bar'], + year: [2021, 2021, 2020, 2020] + }, + initOptions: { + rows: ['item'], + cols: ['year'], + colOrder: 'key_a_to_z', + rowOrder: 'key_a_to_z', + aggregatorName: 'Count', + vals: [], + renderer: $.pivotUtilities.renderers['Bar Chart'], + rendererName: 'Bar Chart' + } + }, + attachTo: container + }) + + expect(wrapper.find('.pivot-ui').isVisible()).to.equal(false) + + await flushPromises() + + const plot = wrapper.find('.svg-container').wrapperElement + const initialPlotHeight = plot.scrollHeight + + await wrapper.setProps({ showViewSettings: true }) + expect(wrapper.find('.pivot-ui').isVisible()).to.equal(true) + + await flushPromises() + const plotAfterResize = wrapper.find('.svg-container').wrapperElement + + expect(plotAfterResize.scrollWidth.scrollHeight).not.to.equal( + initialPlotHeight + ) + + wrapper.unmount() + }) })