]> git.r.bdr.sh - rbdr/r.bdr.sh/blame - jekyll/js/breadsticks.js
Add new projects
[rbdr/r.bdr.sh] / jekyll / js / breadsticks.js
CommitLineData
beaf2913
BB
1// App Config
2
3const kEntrypoint = "breadsticks";
4const kGap = 50;
5const kDrawDelay = 100;
6const kDarkDrawingColor = '#fff';
7const kLightDrawingColor = '#000';
97d30c50
BB
8const kMaxVectorMagnitude = 150; // max size of a vector
9const kMagnitudeColorMultiplier = 2.5; // how large should the magnitude be before it's completely transparent
beaf2913
BB
10
11/***********************************************
12 * Breadstick generates a matrix of points
13 * and assigns a vector to each entry
14 * and then draws them
15 ***********************************************/
16
17/*
18 * Generate field of points in which to draw
19 */
20
21// Updates the field object using a canvas
22
23const updateFieldFromCanvas = (field, canvas) => {
24 updateFieldFromRect(field, canvas.getBoundingClientRect());
25
26 canvas.width = window.innerWidth;
27 canvas.height = window.innerHeight;
28
29 window.addEventListener('resize', () => {
30 canvas.width = window.innerWidth;
31 canvas.height = window.innerHeight;
32 updateFieldFromRect(field, canvas.getBoundingClientRect());
33 });
34};
35
36// Updates a field object using a rect
37
38const updateFieldFromRect = (field, rect) => {
39 field.width = rect.width;
40 field.height = rect.height;
41}
42
43/*
44 * Generate the matrix of vectors
45 */
46
47// Updates a matrix for a given field using the mouse
48
49
50const updateFieldMatrixFromMouse = (field, matrix, gap = 50) => {
51 const mousePosition = {
52 x: 0,
53 y: 0
54 };
55
56 fillMatrix(matrix, mousePosition.x, mousePosition.y, field.width, field.height, gap);
57
58 const updateMousePosition = document.addEventListener('mousemove', (event) => {
97d30c50
BB
59 mousePosition.x = event.clientX;
60 mousePosition.y = event.clientY;
beaf2913
BB
61 fillMatrix(matrix, mousePosition.x, mousePosition.y, field.width, field.height, gap);
62 });
63};
64
65// Gets a matrix by calculating the offset between position and field.
66
67const fillMatrix = (matrix, x, y, w, h, gap = 50) => {
68 for (let i = 0; i < w / gap; ++i) {
69 matrix[i] = [];
70 for (let j = 0; j < h / gap; ++j) {
71 let targetX = i * gap;
72 let targetY = j * gap;
73 matrix[i][j] = calculateOffsetVector(x, y, targetX, targetY, w, h);
74 }
75 }
76};
77
78// Calculates the offset vector of a point
79const calculateOffsetVector = (sourceX, sourceY, targetX, targetY, w, h) => {
80 const xOffset = targetX - sourceX;
81 const yOffset = targetY - sourceY;
82
97d30c50
BB
83 const calculatedMagnitude = Math.sqrt(Math.pow(xOffset, 2) + Math.pow(yOffset, 2));
84
beaf2913
BB
85 return {
86 position: {
87 x: targetX,
88 y: targetY
89 },
97d30c50 90 color: getColor(calculatedMagnitude),
beaf2913 91 angle: Math.atan2(xOffset, yOffset),
97d30c50 92 magnitude: Math.min(calculatedMagnitude, kMaxVectorMagnitude)
beaf2913
BB
93 };
94};
95
96
97/*
98 * Drawing
99 */
100
97d30c50 101// draw a vector
beaf2913 102const drawVector = (context, i, j, vector) => {
97d30c50
BB
103 const x = vector.position.x - vector.magnitude * Math.sin(vector.angle);
104 const y = vector.position.y - vector.magnitude * Math.cos(vector.angle);
105 context.strokeStyle = vector.color;
beaf2913
BB
106 context.beginPath();
107 context.moveTo(vector.position.x, vector.position.y);
108 context.lineTo(Math.round(x), Math.round(y));
109 context.stroke();
110};
111
97d30c50
BB
112// Gets the color depending on the calculated magnitude
113// as well as the color scheme
114
115const getColor = (calculatedMagnitude) => {
116
117 let colorValue = Math.round(calculatedMagnitude * 255 / (kMaxVectorMagnitude * kMagnitudeColorMultiplier)) % 255;
beaf2913 118
beaf2913 119 if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
97d30c50 120 colorValue = 255 - colorValue % 255;
beaf2913
BB
121 }
122
97d30c50
BB
123 // Initialize an array with the value, converts it to a hex string and joins it.
124 return `#${Array(3).fill(colorValue.toString(16)).join('')}`;
beaf2913
BB
125};
126
127
128// Draws field on canvas
129
130const drawFieldMatrixOnCanvas = (matrix, context) => {
131
97d30c50 132 context.setLineDash([25, 10])
beaf2913
BB
133 context.clearRect(0, 0, context.canvas.width, context.canvas.height);
134
135 for (let i = 0; i < matrix.length; ++i) {
136 const row = matrix[i];
137 for (let j = 0; j < row.length; ++j) {
138 const vector = row[j]
139
140 if (vector) {
141 drawVector(context, i, j, vector);
142 }
143 }
144 }
145};
146
147/*
148 * Entrypoint
149 */
150
151const run = () => {
152
153 const field = {
154 width: 0,
155 height: 0
156 };
157 const canvas = document.getElementById(kEntrypoint);
158
159 updateFieldFromCanvas(field, canvas);
160
161 const matrix = [[]];
162 updateFieldMatrixFromMouse(field, matrix, kGap);
163
164 const context = canvas.getContext('2d');
165 const drawFunction = () => {
166 drawFieldMatrixOnCanvas(matrix, context);
167 setTimeout(drawFunction, kDrawDelay);
168 }
169
170 setTimeout(drawFunction, 0);
171};
172
173window.addEventListener('load', run);