A simple gradient creator for minecraft
at master 11 kB view raw
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()