Skip to content

Commit ffd626d

Browse files
committed
Raytracing node.
1 parent 15173f9 commit ffd626d

8 files changed

Lines changed: 821 additions & 32 deletions

File tree

app/scripts/app.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {RandomMode} from './elements/random/RandomFlowNodeViewModel';
99
import {Class, LayoutExecutor} from 'yfiles';
1010
import {ISurface} from './core/ISurface';
1111
import {SpyFlowNodeController} from './elements/spy/SpyFlowNodeController';
12+
import {RaytraceFlowNodeController} from './elements/raytrace/RaytraceFlowNodeController';
1213

1314

1415
Class.ensure(LayoutExecutor);
@@ -43,6 +44,7 @@ class App {
4344
this.surface.connect(random.ports['Output'], barchart.ports['Input']);
4445
const spy = new SpyFlowNodeController(this.surface);
4546
this.surface.connect(random.ports['Output'], spy.ports['Input']);
47+
const ray = new RaytraceFlowNodeController(this.surface);
4648
this.surface.layout();
4749
}
4850

app/scripts/core/Surface.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ISurface} from './ISurface';
2-
import {BridgeCrossingStyle, BridgeManager, DefaultEdgePathCropper, Fill, GraphComponent, GraphEditorInputMode, GraphItemTypes, GraphObstacleProvider, HierarchicLayout, HierarchicNestingPolicy, ICanvasObjectDescriptor, IEdge, IGraph, INode, IPort, LayoutExecutor, License, ShapeNodeStyle, Size, TemplateNodeStyle} from 'yfiles';
2+
import {BridgeCrossingStyle, BridgeManager, DefaultEdgePathCropper, Fill, GraphComponent, GraphEditorInputMode, GraphItemTypes, GraphObstacleProvider, GraphViewerInputMode, HierarchicLayout, HierarchicNestingPolicy, ICanvasObjectDescriptor, IEdge, IGraph, INode, IPort, LayoutExecutor, License, ShapeNodeStyle, Size, TemplateNodeStyle} from 'yfiles';
33
import {IFlowModel} from './IFlowModel';
44
import {IFlowPortViewModel} from './IFlowPortViewModel';
55
import {IFlowNodeModel} from './IFlowNodeModel';
@@ -20,11 +20,14 @@ export class Surface implements ISurface {
2020

2121
private createInteractions() {
2222
const mode = new GraphEditorInputMode();
23-
mode.showHandleItems = GraphItemTypes.ALL & ~GraphItemTypes.NODE;
23+
mode.showHandleItems = GraphItemTypes.NONE;
2424
mode.createEdgeInputMode.useHitItemsCandidatesOnly = true;
2525
mode.allowCreateNode = false;
2626
mode.allowCreateEdge = true;
2727
mode.allowCreateBend = false;
28+
mode.allowEditLabel = false;
29+
mode.allowDuplicate = false;
30+
2831
this.graphComponent.inputMode = mode;
2932

3033
mode.addItemClickedListener((s, e) => {
@@ -212,7 +215,7 @@ export class Surface implements ISurface {
212215

213216
executor.start().then( () => {
214217
this.graphComponent.fitContent();
215-
this.graphComponent.zoom = 3;
218+
this.graphComponent.zoom = 1;
216219
});
217220
}
218221

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {FlowNodeController} from '../../core/FlowNodeController';
2+
import {ISurface} from '../../core/ISurface';
3+
import {FreeNodePortLocationModel, Rect} from 'yfiles';
4+
import RaytraceNodeStyle from '../../style/RaytraceNodeStyle';
5+
import {RaytraceFlowNodeViewModel} from './RaytraceFlowNodeViewModel';
6+
7+
export class RaytraceFlowNodeController extends FlowNodeController {
8+
9+
constructor( surface: ISurface) {
10+
super( surface);
11+
this.viewModel = new RaytraceFlowNodeViewModel(this.model);
12+
13+
this.node= this.surface.graph.createNode({
14+
style: new RaytraceNodeStyle(),
15+
layout: new Rect(0, 0, 105, 150),
16+
tag: this.viewModel
17+
});
18+
19+
const vmInput = this.viewModel.portViewModels['Input'];
20+
this.ports['Input'] = this.surface.graph.addPort({owner: this.node, locationParameter: FreeNodePortLocationModel.INSTANCE.createParameter( this.node, vmInput.position), style: this.inputStyle, tag: vmInput});
21+
22+
}
23+
24+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import {FlowNodeViewModel} from '../../core/FlowNodeViewModel';
2+
import {FlowPortViewModel} from '../../core/FlowPortViewModel';
3+
import {PortType} from '../../core/PortType';
4+
import {Point} from 'yfiles';
5+
import {FlowNodeModel} from '../../core/FlowNodeModel';
6+
import * as _ from 'lodash';
7+
8+
export class RaytraceFlowNodeViewModel extends FlowNodeViewModel {
9+
10+
/**
11+
* Property used by the stream to set the raw data given as string.
12+
* @param arrayAsString {string} Presumably an array of numbers in a string.
13+
*/
14+
public set rawValues(arrayAsString: string) {
15+
const parsed = this.parse(arrayAsString);
16+
if (!_.isNil(parsed)) {
17+
this._values = parsed;
18+
this.update();
19+
this.firePropertyChanged('values');
20+
this.setPropertyValue('values', parsed);
21+
}
22+
}
23+
24+
public get values(): number[] {
25+
return this._values;
26+
27+
}
28+
29+
30+
private _values: number[];
31+
32+
constructor(model) {
33+
super('Sum', model);
34+
35+
this.portViewModels['Input'] = new FlowPortViewModel('rawValues', PortType.INPUT, this, new Point(0.0, 30 - 2));
36+
this.model.nodes[this.id] = new FlowNodeModel(this.id, this.model);
37+
38+
}
39+
40+
41+
update() {
42+
43+
}
44+
45+
parse(x) {
46+
if (_.isString(x)) {
47+
const found = JSON.parse(x);
48+
if (_.isArray(found)) {
49+
return found;
50+
}
51+
}
52+
return null;
53+
}
54+
55+
56+
}

app/scripts/style/D3NodeStyle.ts

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as d3 from 'd3';
22
import {NodeStyleBase, SvgVisual} from 'yfiles'
3-
import {IFlowNodeViewModel} from '../core/IFlowNodeViewModel';
43
import {BarChartFlowNodeViewModel} from '../elements/barchart/BarChartFlowNodeViewModel';
54
import * as _ from 'lodash';
65

@@ -20,10 +19,6 @@ const color = d3
2019
.range(['#1dccc2', '#2f5b88'])
2120
.interpolate(d3.interpolateHcl);
2221

23-
/**
24-
* A node style that triggers the sparkline rendering and includes the result in
25-
* the node visualization.
26-
*/
2722
export default class D3ChartNodeStyle extends NodeStyleBase {
2823
constructor() {
2924
super();
@@ -35,7 +30,6 @@ export default class D3ChartNodeStyle extends NodeStyleBase {
3530
* @return {SvgVisual}
3631
*/
3732
createVisual(renderContext, node) {
38-
// create a g element and use it as a container for the sparkline visualization
3933
const g = window.document.createElementNS('http://www.w3.org/2000/svg', 'g');
4034
const svgVisual = new SvgVisual(g);
4135

@@ -58,22 +52,6 @@ export default class D3ChartNodeStyle extends NodeStyleBase {
5852

5953
const group = d3.select(g);
6054

61-
// const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
62-
// // temporarily add the svg to the body so the elements can be measured
63-
// window.document.body.appendChild(svg);
64-
//
65-
// const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
66-
//
67-
// const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
68-
// clipPath.setAttribute('id', 'round-corner');
69-
// const clipRec = document.createElementNS('http://www.w3.org/2000/svg', 'rec');
70-
// clipRec.setAttribute('width', '70');
71-
// clipRec.setAttribute('height', '30');
72-
// clipRec.setAttribute('rx', '6');
73-
// clipRec.setAttribute('ry', '6');
74-
// clipPath.appendChild(clipRec);
75-
// defs.appendChild(clipPath);
76-
// svg.appendChild(defs);
7755
const defs = group.append('defs');
7856

7957

@@ -181,12 +159,7 @@ export default class D3ChartNodeStyle extends NodeStyleBase {
181159
color.domain([0, d3.max(data)]);
182160

183161
const group = d3.select(g);
184-
// group.append('rect')
185-
// .attr('width', 70)
186-
// .attr('height', 70)
187-
// .attr('rx', 6)
188-
// .attr('ry', 6)
189-
// .attr('fill', '#323232');
162+
190163
group
191164
.attr('transform', `translate(${x} ${y})`)
192165
.select('rect')
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
import {HtmlCanvasVisual, IRenderContext, NodeStyleBase, Point, Rect, SvgVisual} from 'yfiles'
2+
import {} from '../elements/raytrace/RaytraceFlowNodeViewModel';
3+
import * as _ from 'lodash';
4+
import {Material, RayTracer, roundRect, Scene, Sphere, Vector3} from './raytracer.js'
5+
6+
const margin = {
7+
top: 30,
8+
right: 3,
9+
bottom: -20,
10+
left: 3
11+
};
12+
13+
export class RaytraceVisual extends HtmlCanvasVisual {
14+
private rayTracer: RayTracer;
15+
16+
private getRendering(scaling) {
17+
const buffer = this.rayTracer.render(Math.round(scaling*(105 - 2)), Math.round(scaling * (150 - 12)));
18+
return new Uint8ClampedArray(buffer);
19+
}
20+
21+
public layout: Rect;
22+
23+
constructor() {
24+
super();
25+
const scene = new Scene();
26+
27+
// add background sphere
28+
scene.add(
29+
new Sphere(new Vector3(10.0, -10004, -20), 10000,
30+
new Material(new Vector3(0.2, 0.2, 0.2), 0.5, 0, new Vector3()))
31+
);
32+
33+
// add sphere
34+
scene.add(
35+
new Sphere(new Vector3(0, -1, -20), 3,
36+
new Material(new Vector3(0.100, 0.32, 0.936), 0.1, 0.05, new Vector3(0.8, 0, 0)))
37+
);
38+
39+
// add lights
40+
scene.add(
41+
new Sphere(new Vector3(0, 20, -30), 3,
42+
new Material(new Vector3(0, -20, 0), 0, 0, new Vector3(1.2, 1.2, 1.2)))
43+
);
44+
scene.add(
45+
new Sphere(new Vector3(10, 20, 10), 3,
46+
new Material(new Vector3(), 0, 0, new Vector3(1, 1, 1)))
47+
);
48+
49+
const backgroundColor = new Vector3(0.7, 0.8, 0.9);
50+
51+
// create ray tracer
52+
this.rayTracer = new RayTracer(backgroundColor, scene);
53+
}
54+
55+
paint(renderContext: IRenderContext, ctx: CanvasRenderingContext2D): void {
56+
if (_.isNil(this.layout)) {
57+
return;
58+
}
59+
const l = this.layout;
60+
const canvas = renderContext.canvasComponent;
61+
const viewPoint = canvas.viewPoint;
62+
const viewPort = canvas.viewport;
63+
const scaling = 1 / canvas.zoom;
64+
65+
66+
ctx.save();
67+
roundRect(ctx, l.x, l.y, l.width, l.height, 6, false);
68+
ctx.clip();
69+
70+
// background
71+
ctx.fillStyle = '#6A5656';
72+
ctx.fillRect(l.x, l.y, l.width, l.height);
73+
74+
ctx.restore();
75+
const factor = canvas.zoom;
76+
const imageData = ctx.getImageData(l.x, l.y, Math.round(factor*(105 - 2)), Math.round(factor * (150 - 12)));
77+
imageData.data.set(this.getRendering(factor));
78+
// const p = canvas.toViewCoordinates(l)
79+
ctx.putImageData(imageData, canvas.zoom * (-viewPoint.x + l.x), canvas.zoom * (-viewPoint.y + l.y));
80+
// ctx.putImageData(imageData, p.x, p.y);
81+
82+
ctx.save();
83+
roundRect(ctx, l.x, l.y, l.width, l.height, 6, false);
84+
ctx.clip();
85+
86+
// header
87+
ctx.fillStyle = 'green';
88+
ctx.fillRect(l.x, l.y, l.width, 20);
89+
ctx.font = '10px sans-serif';
90+
ctx.fillStyle = 'white';
91+
ctx.fillText('Raytrace', l.x + 7, l.y + 13);
92+
ctx.restore();
93+
94+
95+
// border
96+
roundRect(ctx, l.x, l.y, l.width, l.height, 6, false);
97+
ctx.strokeStyle = '#636363';
98+
ctx.lineWidth = 2;
99+
ctx.stroke();
100+
return;
101+
102+
103+
// ctx.translate(this.position.x, this.position.y);
104+
105+
ctx.save()
106+
107+
ctx.translate(viewPoint.x, viewPoint.y);
108+
ctx.scale(scaling, scaling);
109+
// create scene
110+
111+
112+
// get canvas
113+
const canvasWidth = 105;
114+
const canvasHeight = 150;
115+
116+
// save start time
117+
const startTime = Date.now();
118+
// ctx.save();
119+
// ctx.rect(1, 1, 104, 147);
120+
// ctx.clip();
121+
// ctx.fillStyle = '#6A5656';
122+
// ctx.fillRect(0, 0, 105, 150);
123+
124+
125+
ctx.fillStyle = 'green';
126+
ctx.fillRect(0, 0, 110, 20);
127+
128+
ctx.font = '10px sans-serif';
129+
ctx.fillStyle = 'white';
130+
ctx.fillText('Raytrace', 7, 13);
131+
132+
// ctx.restore();
133+
roundRect(ctx, 0, 0, 105, 150, 6, false);
134+
ctx.strokeStyle = '#636363';
135+
ctx.lineWidth = 2;
136+
ctx.stroke();
137+
ctx.restore()
138+
const totalDuration = (Date.now() - startTime) / 1000;
139+
// console.log(`Raytraced in ${totalDuration}s.`)
140+
}
141+
142+
}
143+
144+
export default class RaytraceNodeStyle extends NodeStyleBase {
145+
constructor() {
146+
super();
147+
}
148+
149+
/**
150+
* Creates the visual for a node.
151+
* @see Overrides {@link NodeStyleBase#createVisual}
152+
* @return {SvgVisual}
153+
*/
154+
createVisual(renderContext, node) {
155+
const visual = new RaytraceVisual();
156+
157+
return visual
158+
}
159+
160+
/**
161+
* Re-renders the node using the old visual for performance reasons.
162+
* @see Overrides {@link NodeStyleBase#updateVisual}
163+
* @return {SvgVisual}
164+
*/
165+
updateVisual(renderContext, oldVisual, node) {
166+
const visual = oldVisual as RaytraceVisual;
167+
visual.layout = node.layout;
168+
169+
return visual;
170+
}
171+
172+
}

0 commit comments

Comments
 (0)