this repo has no description
1import { ContextMenu } from "./structs/ContextMenu";
2import { Node, NodeIO, NodeIOLinkColours } from "./structs/node";
3import { lerp } from "./utils/lerp";
4
5export interface PositionInfo{
6 x: number,
7 y: number,
8 scale: number
9}
10
11const GRID_SIZE = 50;
12
13export let renderBackgroundGrid = (
14 canvas: HTMLCanvasElement,
15 ctx: CanvasRenderingContext2D,
16 position: PositionInfo
17) => {
18 let offsetX = position.x % 50;
19 let offsetY = position.y % 50;
20
21 let gridAmountX = canvas.width / (GRID_SIZE * position.scale);
22 let gridAmountY = canvas.height / (GRID_SIZE * position.scale);
23
24 ctx.fillStyle = '#fff1';
25
26 for (let x = 0; x < gridAmountX / 2; x++) {
27 for (let y = 0; y < gridAmountY / 2; y++) {
28 ctx.fillRect(
29 ((x * GRID_SIZE) + offsetX) * position.scale,
30 ((y * GRID_SIZE) + offsetY) * position.scale,
31 5 * position.scale, 5 * position.scale);
32
33 ctx.fillRect(
34 (((x + 1) * GRID_SIZE) - offsetX) * -position.scale,
35 ((y * GRID_SIZE) + offsetY) * position.scale,
36 5 * position.scale, 5 * position.scale);
37
38 ctx.fillRect(
39 ((x * GRID_SIZE) + offsetX) * position.scale,
40 (((y + 1) * GRID_SIZE) - offsetY) * -position.scale,
41 5 * position.scale, 5 * position.scale);
42
43 ctx.fillRect(
44 (((x + 1) * GRID_SIZE) - offsetX) * -position.scale,
45 (((y + 1) * GRID_SIZE) - offsetY) * -position.scale,
46 5 * position.scale, 5 * position.scale);
47 }
48 }
49}
50
51export let renderNodes = (
52 canvas: HTMLCanvasElement,
53 ctx: CanvasRenderingContext2D,
54 nodes: Node[],
55 position: PositionInfo
56) => {
57 let startX = canvas.width / -2;
58 let startY = canvas.height / -2;
59
60 ctx.textBaseline = 'top';
61
62 nodes.map(node => {
63 let nodeX = Math.round(node.x / 10) * 10;
64 let nodeY = Math.round(node.y / 10) * 10;
65
66 ctx.fillStyle = '#343742ff';
67 ctx.strokeStyle = node.selected ? '#004696ff' : '#fff0';
68 ctx.lineWidth = 5 * position.scale;
69
70 // Draw Node Box
71 drawRoundedRect(ctx,
72 (nodeX + startX + position.x) * position.scale,
73 (nodeY + startY + position.y) * position.scale,
74 node.w * position.scale,
75 node.h * position.scale,
76 10 * position.scale);
77
78 ctx.shadowColor = '#0005';
79 ctx.shadowBlur = 10;
80
81 ctx.stroke();
82 ctx.fill();
83
84 ctx.shadowBlur = 0;
85
86 // Draw Node Name
87 ctx.fillStyle = '#fff';
88 ctx.font = (25 * position.scale) + 'px Rubik';
89 ctx.textAlign = 'center';
90
91 ctx.fillText(node.name,
92 (nodeX + (node.w * 0.5) + startX + position.x) * position.scale,
93 (nodeY + 10 + startY + position.y) * position.scale
94 );
95
96 // Draw Inputs
97 ctx.font = (15 * position.scale) + 'px Rubik';
98 ctx.textAlign = 'left';
99
100 node.inputs.map(( input, i ) => {
101 ctx.fillStyle = NodeIOLinkColours(input);
102
103 ctx.beginPath();
104 ctx.arc(
105 (nodeX - 10 + startX + 10 + position.x) * position.scale,
106 (nodeY + 50 + (30 * i) + startY + 10 + position.y) * position.scale,
107 7 * position.scale,
108 0,
109 Math.PI * 2,
110 );
111 ctx.fill();
112
113 ctx.fillText(input.name,
114 (nodeX + 15 + startX + position.x) * position.scale,
115 (nodeY + 53 + (30 * i) + startY + position.y) * position.scale,
116 )
117 })
118
119 // Draw Outputs
120 ctx.textAlign = 'right';
121
122 node.outputs.map(( output, i ) => {
123 ctx.fillStyle = NodeIOLinkColours(output);
124
125 ctx.beginPath();
126 ctx.arc(
127 (nodeX + (node.w - 10) + startX + 10 + position.x) * position.scale,
128 (nodeY + 50 + (30 * i) + startY + 10 + position.y) * position.scale,
129 7 * position.scale,
130 0,
131 Math.PI * 2,
132 );
133 ctx.fill();
134
135 ctx.fillText(output.name,
136 (nodeX + (node.w - 15) + startX + position.x) * position.scale,
137 (nodeY + 53 + (30 * i) + startY + position.y) * position.scale,
138 )
139 })
140 })
141
142 nodes.map(node => {
143 let nodeX = Math.round(node.x / 10) * 10;
144 let nodeY = Math.round(node.y / 10) * 10;
145
146 node.outputs.map(( output, i ) => {
147 output.connections.map(partner => {
148 let x0 = (nodeX + (node.w - 10) + 10 + startX + position.x) * position.scale;
149 let y0 = (nodeY + 50 + (30 * i) + 10 + startY + position.y) * position.scale;
150 let x1 = ((Math.round(partner.parent.x / 10) * 10) + startX + position.x) * position.scale;
151 let y1 = ((Math.round(partner.parent.y / 10) * 10) + 60 + (30 * partner.index) + startY + position.y) * position.scale;
152
153 let colours = NodeIOLinkColours(output, partner);
154 let grad = ctx.createLinearGradient(x0, y0, x1, y1);
155
156 grad.addColorStop(0, colours[0]);
157 grad.addColorStop(1, colours[1]);
158
159 ctx.strokeStyle = grad;
160 ctx.lineWidth = 3 * position.scale;
161
162 drawCurve(ctx, x0, y0, x1, y1);
163 ctx.stroke();
164 })
165 })
166 })
167}
168
169export let renderContextMenu = (
170 ctx: CanvasRenderingContext2D,
171 contextMenu: ContextMenu
172) => {
173 if(contextMenu.visible){
174 ctx.font = '20px Rubik';
175 ctx.textBaseline = 'top';
176 ctx.textAlign = 'left';
177
178 let widestItem = 0;
179 contextMenu.items.map(x => {
180 let width = ctx.measureText(x.text).width;
181 if(widestItem < width)widestItem = width;
182 });
183
184 contextMenu.size = [ widestItem + 20, 25 * contextMenu.items.length + 20 ]
185
186 drawRoundedRect(ctx, contextMenu.position[0], contextMenu.position[1], contextMenu.size[0], contextMenu.size[1], 10);
187 ctx.fillStyle = '#444';
188 ctx.fill();
189
190 let submenuToRender: any = null;
191
192 contextMenu.items.map((x, i) => {
193 ctx.fillStyle = x.hovered ? '#aaa' : '#fff';
194 ctx.fillText(x.text, contextMenu.position[0] + 10, contextMenu.position[1] + 10 + 25 * i);
195
196 if(x.hovered && x.menu){
197 submenuToRender = x.menu;
198 submenuToRender.position = [ contextMenu.position[0] + contextMenu.size[0] + 5, contextMenu.position[1] + 25 * i ];
199 }
200 });
201
202 if(submenuToRender){
203 renderContextMenu(ctx, submenuToRender);
204 }
205 }
206}
207
208export let renderTempDrawing = (
209 canvas: HTMLCanvasElement,
210 ctx: CanvasRenderingContext2D,
211 drawingTo: [ number, number ],
212 drawingFrom: NodeIO,
213 position: PositionInfo
214) => {
215 let startX = canvas.width / -2;
216 let startY = canvas.height / -2;
217
218 // DEBUG STUFF
219 // ctx.fillStyle = '#f00';
220
221 // ctx.fillRect(
222 // (drawingTo[0] + 10 + startX + position.x) * position.scale,
223 // (drawingTo[1] + 10 + startY + position.y) * position.scale,
224 // 10, 10
225 // );
226
227 // ctx.fillRect(
228 // (drawingFrom.parent.x + (drawingFrom.parent.w - 10) + 10 + startX + position.x) * position.scale,
229 // (drawingFrom.parent.y + 50 + (30 * drawingFrom.index) + 10 + startY + position.y) * position.scale,
230 // 10, 10
231 // );
232
233 ctx.strokeStyle = NodeIOLinkColours(drawingFrom);
234 ctx.lineWidth = 3 * position.scale;
235
236 let nodeX = Math.round(drawingFrom.parent.x / 10) * 10;
237 let nodeY = Math.round(drawingFrom.parent.y / 10) * 10;
238
239 drawCurve(ctx,
240 (nodeX + (drawingFrom.parent.w - 10) + 10 + startX + position.x) * position.scale,
241 (nodeY + 50 + (30 * drawingFrom.index) + 10 + startY + position.y) * position.scale,
242 (drawingTo[0] + 10 + startX + position.x) * position.scale,
243 (drawingTo[1] + 10 + startY + position.y) * position.scale,
244 );
245 ctx.stroke();
246}
247
248let drawCurve = ( ctx: CanvasRenderingContext2D, fromX: number, fromY: number, toX: number, toY: number ) => {
249 ctx.beginPath();
250
251 let bias = Math.sqrt(( fromX - toX ) * ( fromX - toX ) + ( fromY - toY ) * ( fromY - toY )) / 3;
252
253 let start = [ fromX + bias, fromY ];
254 let end = [ toX - bias, toY ];
255
256 let midpoint = [
257 lerp(start[0], end[0], 0.5),
258 lerp(start[1], end[1], 0.5)
259 ];
260
261 ctx.bezierCurveTo(fromX, fromY, start[0], start[1], midpoint[0], midpoint[1]);
262 ctx.bezierCurveTo(midpoint[0], midpoint[1], end[0], end[1], toX, toY);
263}
264
265export let renderNullTab = (
266 canvas: HTMLCanvasElement,
267 ctx: CanvasRenderingContext2D,
268) => {
269 ctx.fillStyle = '#fff';
270
271 ctx.font = '20px Rubik';
272 ctx.textBaseline = 'middle';
273 ctx.textAlign = 'center';
274
275 let textX = lerp((canvas.width / -2) + 200, canvas.width / 2, 0.5);
276 let textY = lerp((canvas.height / -2) + 40, canvas.height / 2, 0.5);
277
278 ctx.font = '40px Rubik';
279 ctx.fillText('Welcome to VRCMacros', textX, textY);
280
281 ctx.font = '20px Rubik';
282 ctx.fillText('Create a new tab to get started!', textX, textY + 40);
283}
284
285let drawRoundedRect = ( ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, radius: number ) => {
286 ctx.beginPath();
287 ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5);
288 ctx.lineTo(x + w - radius, y);
289 ctx.arc(x + w - radius, y + radius, radius, Math.PI * 1.5, 0);
290 ctx.lineTo(x + w, y + h - radius);
291 ctx.arc(x + w - radius, y + h - radius, radius, 0, Math.PI * 0.5);
292 ctx.lineTo(x + radius, y + h);
293 ctx.arc(x + radius, y + h - radius, radius, Math.PI * 0.5, Math.PI);
294 ctx.closePath();
295}