/********************************************************************************
* Copyright (c) 2017-2018 TypeFox and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
/** @jsx svg */
import { svg } from '../lib/jsx';
import 'reflect-metadata';
import { expect, describe, it } from 'vitest';
import { Container } from 'inversify';
import { VNode } from 'snabbdom';
import { TYPES } from '../base/types';
import { IVNodePostprocessor } from '../base/views/vnode-postprocessor';
import { CircularNodeView, RectangularNodeView } from '../lib/svg-views';
import { CircularNode, RectangularNode, RectangularPort } from '../lib/model';
import { RenderingContext, ViewRegistry, configureModelElement } from '../base/views/view';
import { ModelRendererFactory } from '../base/views/viewer';
import { PolylineEdgeView, SGraphView } from './views';
import { SModelElementImpl, SParentElementImpl } from '../base/model/smodel';
import { IModelFactory } from '../base/model/smodel-factory';
import defaultModule from '../base/di.config';
import selectModule from '../features/select/di.config';
import moveModule from '../features/move/di.config';
import { SEdgeImpl, SGraphImpl, SNodeImpl, SPortImpl } from './sgraph';
import routingModule from '../features/routing/di.config';
import toHTML from 'snabbdom-to-html';
import { SEdge, SNode, SPort } from 'sprotty-protocol';
describe('graph views', () => {
class CircleNodeView extends CircularNodeView {
override render(node: SNodeImpl, renderContext: RenderingContext): VNode {
const radius = this.getRadius(node);
return
;
}
protected override getRadius(node: SNodeImpl) {
return 40;
}
}
const container = new Container();
container.load(defaultModule, selectModule, moveModule, routingModule);
configureModelElement(container, 'graph', SGraphImpl, SGraphView);
configureModelElement(container, 'node:circle', CircularNode, CircleNodeView);
configureModelElement(container, 'edge:straight', SEdgeImpl, PolylineEdgeView);
configureModelElement(container, 'port', SPortImpl, RectangularNodeView);
const postprocessors = container.getAll(TYPES.IVNodePostprocessor);
const context = container.get(TYPES.ModelRendererFactory)('hidden', postprocessors);
const graphFactory = container.get(TYPES.IModelFactory);
const viewRegistry = container.get(TYPES.ViewRegistry);
it('render an empty graph', () => {
const schema = {
type: 'graph',
id: 'mygraph',
children: []
};
const graph = graphFactory.createRoot(schema) as SGraphImpl;
const view = viewRegistry.get(graph.type);
const vnode = view.render(graph, context);
expect(toHTML(vnode)).to.be.equal('');
});
function createModel() {
const node0 = { id: 'node0', type: 'node:circle', position: { x: 100, y: 100 }, size: { width: 80, height: 80 } };
const node1 = { id: 'node1', type: 'node:circle', position: { x: 200, y: 150 }, size: { width: 80, height: 80 }, selected: true };
const edge0 = { id: 'edge0', type: 'edge:straight', sourceId: 'node0', targetId: 'node1' };
const graph = graphFactory.createRoot({ id: 'graph', type: 'graph', children: [node0, node1, edge0] }) as SGraphImpl;
return graph;
}
it('render a straight edge', () => {
const graph = createModel();
const view = viewRegistry.get('edge:straight');
const vnode = view.render(graph.index.getById('edge0') as SEdgeImpl, context);
expect(toHTML(vnode)).to.be.equal(
'');
});
it('render a circle node', () => {
const graph = createModel();
const view = viewRegistry.get('node:circle');
const vnode = view.render(graph.index.getById('node0') as SNodeImpl, context);
expect(toHTML(vnode)).to.be.equal('');
});
it('render a whole graph', () => {
const graph = createModel();
const vnode = context.renderElement(graph);
const expectation = '';
expect(toHTML(vnode)).to.be.equal(expectation);
});
});
describe('PolylineEdgeView', () => {
const container = new Container();
container.load(defaultModule, routingModule);
configureModelElement(container, 'graph', SGraphImpl, SGraphView);
configureModelElement(container, 'node', RectangularNode, RectangularNodeView);
configureModelElement(container, 'edge', SEdgeImpl, PolylineEdgeView);
configureModelElement(container, 'edge:straight', SEdgeImpl, PolylineEdgeView);
configureModelElement(container, 'port', RectangularPort, RectangularNodeView);
const factory = container.get(TYPES.IModelFactory);
const model = factory.createRoot({
type: 'graph',
id: 'graph',
children: [
{
type: 'node',
id: 'node1',
position: { x: 10, y: 10 },
size: { width: 10, height: 10 },
children: [
{
type: 'port',
id: 'port1',
position: { x: 10, y: 4 }
} as SPort,
{
type: 'edge',
id: 'edge1',
sourceId: 'port1',
targetId: 'port2'
} as SEdge
]
} as SNode,
{
type: 'node',
id: 'node2',
position: { x: 30, y: 20 },
size: { width: 10, height: 10 },
children: [
{
type: 'port',
id: 'port2',
position: { x: -2, y: 4 }
} as SPort,
{
type: 'edge',
id: 'edge2',
sourceId: 'port1',
targetId: 'port2'
} as SEdge
]
} as SNode,
]
});
const viewRegistry = container.get(TYPES.ViewRegistry);
const edgeView = viewRegistry.get('edge:straight');
const context = {
targetKind: 'hidden',
viewRegistry,
decorate: function(vnode: VNode, element: SModelElementImpl): VNode { return vnode; },
renderElement: function(element: SModelElementImpl): VNode { return ; },
renderChildren: function(element: SParentElementImpl): VNode[] { return []; }
} as RenderingContext;
it('correctly translates edge source and target position', () => {
const edge = model.index.getById('edge1') as SEdgeImpl;
const vnode = edgeView.render(edge, context);
expect(toHTML(vnode)).to.equal('');
});
it('correctly translates edge target and source position', () => {
const edge = model.index.getById('edge2') as SEdgeImpl;
const vnode = edgeView.render(edge, context);
expect(toHTML(vnode)).to.equal('');
});
});