3 const kEntrypoint
= "breadsticks";
5 const kDrawDelay
= 100;
6 const kDarkDrawingColor
= '#fff';
7 const kLightDrawingColor
= '#000';
8 const kMaxVectorMagnitude
= 150; // max size of a vector
9 const kMagnitudeColorMultiplier
= 2.5; // how large should the magnitude be before it's completely transparent
11 /***********************************************
12 * Breadstick generates a matrix of points
13 * and assigns a vector to each entry
15 ***********************************************/
18 * Generate field of points in which to draw
21 // Updates the field object using a canvas
23 const updateFieldFromCanvas
= (field
, canvas
) => {
24 updateFieldFromRect(field
, canvas
.getBoundingClientRect());
26 canvas
.width
= window
.innerWidth
;
27 canvas
.height
= window
.innerHeight
;
29 window
.addEventListener('resize', () => {
30 canvas
.width
= window
.innerWidth
;
31 canvas
.height
= window
.innerHeight
;
32 updateFieldFromRect(field
, canvas
.getBoundingClientRect());
36 // Updates a field object using a rect
38 const updateFieldFromRect
= (field
, rect
) => {
39 field
.width
= rect
.width
;
40 field
.height
= rect
.height
;
44 * Generate the matrix of vectors
47 // Updates a matrix for a given field using the mouse
50 const updateFieldMatrixFromMouse
= (field
, matrix
, gap
= 50) => {
51 const mousePosition
= {
56 fillMatrix(matrix
, mousePosition
.x
, mousePosition
.y
, field
.width
, field
.height
, gap
);
58 const updateMousePosition
= document
.addEventListener('mousemove', (event
) => {
59 mousePosition
.x
= event
.clientX
;
60 mousePosition
.y
= event
.clientY
;
61 fillMatrix(matrix
, mousePosition
.x
, mousePosition
.y
, field
.width
, field
.height
, gap
);
65 // Gets a matrix by calculating the offset between position and field.
67 const fillMatrix
= (matrix
, x
, y
, w
, h
, gap
= 50) => {
68 for (let i
= 0; i
< w
/ gap
; ++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
);
78 // Calculates the offset vector of a point
79 const calculateOffsetVector
= (sourceX
, sourceY
, targetX
, targetY
, w
, h
) => {
80 const xOffset
= targetX
- sourceX
;
81 const yOffset
= targetY
- sourceY
;
83 const calculatedMagnitude
= Math
.sqrt(Math
.pow(xOffset
, 2) + Math
.pow(yOffset
, 2));
90 color: getColor(calculatedMagnitude
),
91 angle: Math
.atan2(xOffset
, yOffset
),
92 magnitude: Math
.min(calculatedMagnitude
, kMaxVectorMagnitude
)
102 const drawVector
= (context
, i
, j
, vector
) => {
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
;
107 context
.moveTo(vector
.position
.x
, vector
.position
.y
);
108 context
.lineTo(Math
.round(x
), Math
.round(y
));
112 // Gets the color depending on the calculated magnitude
113 // as well as the color scheme
115 const getColor
= (calculatedMagnitude
) => {
117 let colorValue
= Math
.round(calculatedMagnitude
* 255 / (kMaxVectorMagnitude
* kMagnitudeColorMultiplier
)) % 255;
119 if (window
.matchMedia('(prefers-color-scheme: dark)').matches
) {
120 colorValue
= 255 - colorValue
% 255;
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('')}`;
128 // Draws field on canvas
130 const drawFieldMatrixOnCanvas
= (matrix
, context
) => {
132 context
.setLineDash([25, 10])
133 context
.clearRect(0, 0, context
.canvas
.width
, context
.canvas
.height
);
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
]
141 drawVector(context
, i
, j
, vector
);
157 const canvas
= document
.getElementById(kEntrypoint
);
159 updateFieldFromCanvas(field
, canvas
);
162 updateFieldMatrixFromMouse(field
, matrix
, kGap
);
164 const context
= canvas
.getContext('2d');
165 const drawFunction
= () => {
166 drawFieldMatrixOnCanvas(matrix
, context
);
167 setTimeout(drawFunction
, kDrawDelay
);
170 setTimeout(drawFunction
, 0);
173 window
.addEventListener('load', run
);