UNPKG

parallelowow

Version:

A parallelogram-ish paint worklet that'll make you go "woooow".

152 lines (124 loc) 4.98 kB
/* global registerPaint */ if (typeof registerPaint !== "undefined") { registerPaint("parallelowow", class { static get inputProperties() { return [ "--parallelowow-tile-width", "--parallelowow-base-color", "--parallelowow-color-step", "--parallelowow-probability", "--parallelowow-stroke-weight", ]; } paint(ctx, geom, properties) { let tileWidth = Number(properties.get("--parallelowow-tile-width")) || 56; let baseColor = properties.get("--parallelowow-base-color").toString().trim() || "#c9f"; let colorStep = Number(properties.get("--parallelowow-color-step")) || -3; let probability = Number(properties.get("--parallelowow-probability")) || 0.33; let strokeWeight = Number(properties.get("--parallelowow-stroke-weight")) || 0.5; const radians = (Math.PI / 180) * 39.375; const tileHeight = tileWidth * 0.25; const yTiles = geom.height / tileHeight; const xTiles = geom.width / tileWidth; const outerRadius = geom.width > geom.height ? geom.width * 2 : geom.height * 2; let colors = [ baseColor, this.adjustBrightness(baseColor, -10), this.adjustBrightness(baseColor, -30) ]; if (strokeWeight > 0) { ctx.lineWidth = strokeWeight; ctx.strokeStyle = this.adjustBrightness(colors[0], 25); ctx.lineCap = "butt"; } for (let y = -1; y < yTiles; y++) { const yOffset = y * tileHeight; for (let x = -1; x < (xTiles + y); x++) { if (Math.random() > probability) { const xOffset = (x * tileWidth) - (y * tileHeight); // Helpers! const upperLeftX = xOffset; const upperLeftY = yOffset; const upperRightX = xOffset + tileWidth; const upperRightY = yOffset; const lowerRightX = xOffset + (tileWidth - tileHeight); const lowerRightY = yOffset + tileHeight; const lowerLeftX = xOffset - tileHeight; const lowerLeftY = lowerRightY; // 1. Draw shape on the right side of the parallelogram ctx.fillStyle = colors[1]; ctx.beginPath(); ctx.moveTo(upperRightX, upperRightY); ctx.lineTo((Math.cos(radians) * outerRadius), (Math.sin(radians) * outerRadius)); ctx.lineTo(lowerRightX, lowerRightY); ctx.lineTo(upperRightX, upperRightY); ctx.fill(); if (strokeWeight > 0) { ctx.stroke(); } // 2. Draw shape on the lower left side of the parallelogram ctx.fillStyle = colors[2]; ctx.beginPath(); ctx.moveTo(lowerRightX, lowerRightY); ctx.lineTo((Math.cos(radians) * outerRadius), (Math.sin(radians) * outerRadius)); ctx.lineTo(lowerLeftX, lowerLeftY); ctx.moveTo(lowerLeftX, lowerLeftY); ctx.fill(); if (strokeWeight > 0) { ctx.stroke(); } // 3. Draw parallelogram cap ctx.fillStyle = colors[0]; ctx.beginPath(); ctx.moveTo(upperLeftX, upperLeftY); ctx.lineTo(upperRightX, upperRightY); ctx.lineTo(lowerRightX, lowerRightY); ctx.lineTo(lowerLeftX, lowerLeftY); ctx.lineTo(upperLeftX, upperLeftY); ctx.fill(); if (strokeWeight > 0) { ctx.stroke(); } } } // 4. Slightly darken colors for next run. colors = colors.map(colorKey => this.adjustBrightness(colorKey, colorStep)); } } isValidHexColor(hex) { return /^#?(?:[0-9a-f]{3}){1,2}$/i.test(hex); } hexToRgb(hex) { if (/^#/i.test(hex)) { hex = hex.replace("#", ""); } if (hex.length === 3) { const rHex = hex.substring(0, 1); const gHex = hex.substring(1, 2); const bHex = hex.substring(2, 3); hex = `${rHex}${rHex}${gHex}${gHex}${bHex}${bHex}`; } const rDec = parseInt(hex.substring(0, 2), 16); const gDec = parseInt(hex.substring(2, 4), 16); const bDec = parseInt(hex.substring(4, 6), 16); return `rgb(${rDec},${gDec},${bDec})`; } adjustBrightness(colorString, amt) { let rgbString = this.isValidHexColor(colorString) ? this.hexToRgb(colorString) : colorString; rgbString = rgbString.replace(/rgba?\(/g, "").replace(/\)/g, "").replace(/\s/g, ""); const rgbParts = rgbString.split(",").map((rgbPart, index) => { if (index > 2) { return; } rgbPart = parseInt(rgbPart) + amt; if (rgbPart < 0) { rgbPart = 0; } else if (rgbPart > 255) { rgbPart = 255; } return rgbPart; }); return rgbString.indexOf("rgba") !== -1 ? `rgba(${rgbParts.join(",")})` : `rgb(${rgbParts.join(",")})`; } }); }