this repo has no description
at main 8.9 kB view raw
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}