A simple gradient creator for minecraft
1class Color {
2 constructor(r, g, b, a)
3 {
4 this.r = r
5 this.g = g
6 this.b = b
7 this.a = a
8 }
9
10 fromHexString(hex) {
11 var c;
12 if(/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)){
13 c= hex.substring(1).split('');
14 if(c.length== 3){
15 c= [c[0], c[0], c[1], c[1], c[2], c[2]];
16 }
17 c= '0x'+c.join('');
18 return new Color((c>>16)&255, (c>>8)&255, c&255, 255)
19 }
20 throw new Error('Bad Hex');
21 }
22
23 toHexString() {
24 const red = this.r.toString(16).padStart(2, '0');
25 const green = this.g.toString(16).padStart(2, '0');
26 const blue = this.b.toString(16).padStart(2, '0');
27 const alpha = this.a.toString(16).padStart(2, '0');
28
29 return `#${red}${green}${blue}${alpha}`;
30 }
31}
32
33class ControlPoint {
34 constructor(x, color)
35 {
36 this.x = x
37 this.color = color
38 }
39}
40
41let controlPoints = [
42 new ControlPoint(0.0, new Color(255, 0, 0, 255)),
43 new ControlPoint(1.0, new Color(0, 0, 255, 255))
44]
45
46var numItems = 10
47var widthItems = 1
48var offsetItems = 0
49var onlySolids = true
50
51function dragMouseDown(e) {
52 // e = e || window.event;
53 // e.preventDefault();
54
55 // console.log(`pressed ${e.target.id}`)
56
57 // console.log(controlPoints[e.target.id].x / 600)
58
59 document.onmousemove = elementDrag
60 document.onmouseup = closeDragElement
61}
62
63function elementDrag(e) {
64 // console.log(e)
65 if(e.target.id != "") {
66 gradient = document.getElementById('gradient')
67
68 controlPoints[e.target.id].x = (e.clientX - gradient.getBoundingClientRect().left) / (gradient.getBoundingClientRect().right - gradient.getBoundingClientRect().left)
69
70 if(controlPoints[e.target.id].x < 0)
71 {
72 controlPoints[e.target.id].x = 0
73 }
74
75 if(controlPoints[e.target.id].x > 1)
76 {
77 controlPoints[e.target.id].x = 1
78 }
79 }
80
81 generatePointsHTML()
82 generateCSSGradient()
83 generateMinecraftBlocks()
84}
85
86function generatePointsHTML() {
87 // doc = document.getElementById('control-points')
88 // doc.innerHTML = ""
89 // gradient = document.getElementById('gradient')
90
91
92 // controlPoints.forEach((point, i) => {
93 // html = `<div class="point" id="${i}" style="margin-left: ${point.x * (gradient.getBoundingClientRect().right - gradient.getBoundingClientRect().left) - 15}px; top: ${gradient.getBoundingClientRect().bottom}px"></div>`
94 // doc.innerHTML += html
95 // })
96
97 // // Assign event handler to all control points
98 // document.querySelectorAll('.point').forEach(point => {
99 // point.onmousedown = dragMouseDown
100 // point.addEventListener('contextmenu', e => {
101 // e.preventDefault()
102 // })
103 // })
104
105 document.getElementById('color-list').innerHTML = ""
106 controlPoints.forEach((point, i) => {
107 html = `
108 <li class="list-group-item">
109 <div class="d-flex align-items-center">
110 <div class="list-color me-2" style="background-color: ${point.color.toHexString()}">
111
112 </div>
113 Point ${i}
114 <button class="btn btn-danger ms-auto" onclick="
115 controlPoints.splice(${i}, 1);
116 generatePointsHTML()
117 generateCSSGradient()
118 generateMinecraftBlocks()
119
120 ">Remove</button>
121 </div>
122
123 <div class="d-flex align-items-center">
124 <div class="me-2">R</div>
125 <input type="range" class="form-control-range" id="formControlRange" min=0 max=255 step=1 value=${point.color.r}
126 onchange="
127 controlPoints[${i}].color.r = parseInt(event.target.value)
128 generatePointsHTML()
129 generateCSSGradient()
130 generateMinecraftBlocks()
131 ">
132 <br/>
133 </div>
134 <div class="d-flex align-items-center">
135 <div class="me-2">G</div>
136 <input type="range" class="form-control-range" id="formControlRange" min=0 max=255 step=1 value=${point.color.g}
137 onchange="
138 controlPoints[${i}].color.g = parseInt(event.target.value)
139 generatePointsHTML()
140 generateCSSGradient()
141 generateMinecraftBlocks()
142 ">
143 <br/>
144 </div>
145 <div class="d-flex align-items-center">
146 <div class="me-2">B</div>
147 <input type="range" class="form-control-range" id="formControlRange" min=0 max=255 step=1 value=${point.color.b}
148 onchange="
149 controlPoints[${i}].color.b = parseInt(event.target.value)
150 generatePointsHTML()
151 generateCSSGradient()
152 generateMinecraftBlocks()
153 ">
154 <br/>
155 </div>
156 <div class="d-flex align-items-center">
157 <div class="me-2">X</div>
158 <input type="range" class="form-control-range" id="formControlRange" min=0 max=100 value=${point.x * 100}
159 onchange="
160 controlPoints[${i}].x = parseInt(event.target.value) / 100
161 generatePointsHTML()
162 generateCSSGradient()
163 generateMinecraftBlocks()
164 ">
165 <br/>
166 </div>
167 </li>
168 `
169
170 document.getElementById('color-list').innerHTML += html
171 })
172}
173
174function closeDragElement() {
175 // stop moving when mouse button is released:
176 document.onmouseup = null;
177 document.onmousemove = null;
178}
179
180// linear-gradient(to right, #3494E6 0.5%, #333333 53.31%, #986a44 55.02%, #333333 77.88%, #EC6EAD 99%)
181
182function generateCSSGradient() {
183 var gradient = "background: linear-gradient(to right, "
184
185 var sortedPoints = controlPoints.sort((a, b) => a.x - b.x)
186
187 sortedPoints.forEach(point => {
188 gradient += `${point.color.toHexString()} ${point.x * 100}%, `
189 })
190
191 gradient = gradient.substring(0, gradient.length - 2);
192 gradient += ");"
193
194 document.getElementById("gradient").setAttribute("style", gradient);
195}
196
197doc = document.getElementById('gradient')
198doc.onmousedown = (e) => {
199
200 gradient = document.getElementById('gradient')
201
202 var index = undefined
203 controlPoints.forEach((point, i) => {
204 if(point.x > e.clientX / (gradient.getBoundingClientRect().right - gradient.getBoundingClientRect().left) && index == undefined)
205 {
206 index = i
207 }
208 })
209
210 controlPoints.splice(index, 0, new ControlPoint(
211 e.clientX / (gradient.getBoundingClientRect().right - gradient.getBoundingClientRect().left),
212 new Color(255, 255, 255, 255)
213 ))
214
215 // controlPoints.forEach((point, i) => {
216 // html = `<div class="point" id="${i}" style="margin-left: ${point.x * (gradient.getBoundingClientRect().right - gradient.getBoundingClientRect().left) - 15}px; top: ${gradient.getBoundingClientRect().bottom}px"></div>`
217 // doc.innerHTML += html
218
219 // document.getElementById(`${i}`).onmousedown = dragMouseDown
220 // })
221
222 generatePointsHTML()
223 generateCSSGradient()
224 generateMinecraftBlocks()
225}
226
227function getBlockByColor(color)
228{
229 smallestDiffNum = 99999999;
230 smallestDiffBlock = "";
231
232 Object.keys(blocks).forEach(key => {
233 e = blocks[key]
234
235 if(onlySolids && e.a != 255)
236 {
237 } else {
238 diffR = Math.abs(e.r - color.r)
239 diffG = Math.abs(e.g - color.g)
240 diffB = Math.abs(e.b - color.b)
241 diff = diffR + diffG + diffB
242
243 if(diff < smallestDiffNum)
244 {
245 smallestDiffNum = diff
246 smallestDiffBlock = key
247 }
248 }
249 })
250
251 return smallestDiffBlock
252}
253
254function lerp(v0, v1, t) {
255 return v0 + t * (v1 - v0);
256}
257
258Number.prototype.clamp = function(min, max) {
259 return Math.min(Math.max(this, min), max);
260};
261
262function colString(color)
263{
264 return `r${color.r}g${color.g}b${color.b}`
265}
266
267function generateMinecraftBlocks()
268{
269 let group = document.getElementById('minecraft-group')
270 group.innerHTML = "";
271
272 for(var w = 0; w < widthItems; w++)
273 {
274 let points = []
275
276 var sortedPoints = controlPoints.sort((a, b) => a.x - b.x)
277
278 let startNumBlocks = Math.round(sortedPoints[0].x * numItems)
279
280 if(startNumBlocks > 1)
281 {
282 var block = getBlockByColor(sortedPoints[0].color)
283 for(var i = 0; i < startNumBlocks; i++)
284 {
285 points.push(block)
286 }
287 }
288
289 for(var i = 0; i < sortedPoints.length - 1; i++)
290 {
291 // if(i == sortedPoints.length - 1)
292 // {
293 // continue
294 // }
295
296 // console.log(i)
297
298 var numBlocks = (sortedPoints[i + 1].x - sortedPoints[i].x) * numItems
299 var lowBound = sortedPoints[i].x
300 var highBound = sortedPoints[i + 1].x
301
302 // console.log(`blocks ${(sortedPoints[i + 1].x - sortedPoints[i].x) * numItems} ${numItems}`)
303
304 if(numBlocks < 1)
305 {
306 continue
307 }
308
309 for(var j = 0; j < numBlocks; j++)
310 {
311 let lerpValue = j / numBlocks;
312
313 var color = new Color(0, 0, 0, 255);
314
315 color.r = lerp(sortedPoints[i].color.r, sortedPoints[i + 1].color.r, lerpValue + ((Math.random() - 0.5) * (offsetItems / 10)))
316 color.g = lerp(sortedPoints[i].color.g, sortedPoints[i + 1].color.g, lerpValue + ((Math.random() - 0.5) * (offsetItems / 10)))
317 color.b = lerp(sortedPoints[i].color.b, sortedPoints[i + 1].color.b, lerpValue + ((Math.random() - 0.5) * (offsetItems / 10)))
318
319 // console.log(lerpValue)
320
321 var block = getBlockByColor(color)
322
323 points.push(block)
324 }
325 }
326
327 let endNumBlocks = Math.round((1 - sortedPoints[sortedPoints.length - 1].x).clamp(0, 1) * numItems)
328
329 if(endNumBlocks > 1)
330 {
331 var block = getBlockByColor(sortedPoints[sortedPoints.length - 1].color)
332 for(var i = 0; i < endNumBlocks; i++)
333 {
334 points.push(block)
335 }
336 }
337
338 group.innerHTML += `<div id="minecraft${w}" class="d-flex flex-column mt-3">`
339
340 document.getElementById(`minecraft${w}`).innerHTML = ""
341
342 points.forEach(e => {
343 document.getElementById(`minecraft${w}`).innerHTML += `<img class="minecraft-block" src="/minecraft-gradient/block/${e}"></img>`
344 })
345
346 // console.log(points)
347
348 group.innerHTML += "</div>"
349 }
350}
351
352window.addEventListener('resize', (e) => {
353 generatePointsHTML()
354 generateCSSGradient()
355}, true);
356
357generateMinecraftBlocks()
358generatePointsHTML()
359generateCSSGradient()