Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: rewrite color picker and add alpha picker #337

Merged
merged 1 commit into from
May 28, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
178 changes: 167 additions & 11 deletions wasm/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,23 @@
<link rel="preload" as="fetch" type="application/wasm" href="./index_bg.wasm" crossorigin>
<script src="./index.min.js"></script>
<style>
:root {
--slider-thumb-size: 26px;
--slider-track-height: 14px;
--slider-thumb-bg-color: #FF8253;
--input-border-color: #666;
}

html {
box-sizing: border-box;
font-family: system-ui, Arial, Helvetica, sans-serif;
}

html:before {
content: '';
color: color-mix( in srgb, var(--picker-color), transparent var(--picker-alpha, 0%) );
/* Or use Relative color */
/* color: rgb(from var(--picker-color) r g b / var(--picker-alpha, 1)); */
}

*, *:before, *:after {
Expand Down Expand Up @@ -49,12 +64,12 @@
margin-right: auto;
}

input[type="color"] {
input[type="color" i] {
border: none;
background: none;
}

input[type="color"]::-webkit-color-swatch-wrapper {
input[type="color" i]::-webkit-color-swatch-wrapper {
padding: 0;
}

Expand All @@ -63,7 +78,26 @@
user-select: none;
}

input:not([type="color"]), select {
.color-picker-box {
position: relative;
display: flex;
align-items: center;
height: var(--slider-track-height);
}

#color-picker {
visibility: hidden;
width: 40px;
height: var(--slider-track-height);
position: absolute;
bottom: -10px;
visibility: hidden;
position-anchor: --picker-target;
left: anchor(left);
margin-left: -106px;
}

input:not([type="color" i]), select {
height: 30px;
padding: 0 .5em;
font-size: 16px;
Expand All @@ -73,6 +107,7 @@
display: flex;
flex: 1;
margin-top: 20px;
margin-bottom: 30px;
}

#input-svg {
Expand Down Expand Up @@ -169,6 +204,71 @@
.github:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out;
}
/* 自定义 Alpha 选择器样式 */
input[type="range" i] {
appearance: none;
max-width: 150px;
}

input[type="range" i]::-webkit-slider-thumb {
anchor-name: --picker-target;
appearance: none;
height: var(--slider-thumb-size);
width: var(--slider-thumb-size);
max-width: 80px;
position: relative;
z-index: 2048;
top: 50%;
transform: translateY(-50%);
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 1px 2px 8px rgba(0, 0, 0, 0.6), inset 0px 1px 3px rgba(0, 0, 0, 0.3);
background: var(--picker-color, var(--slider-thumb-bg-color));
}
input[type="range" i]::-moz-range-thumb {
anchor-name: --picker-target;
appearance: none;
height: var(--slider-thumb-size);
width: var(--slider-thumb-size);
max-width: 80px;
position: relative;
z-index: 2048;
border-radius: 50%;
border: 2px solid #fff;
box-shadow: 1px 2px 8px rgba(0, 0, 0, 0.6), inset 0px 1px 3px rgba(0, 0, 0, 0.3);
background: var(--picker-color, var(--slider-thumb-bg-color));
}
input[type="range" i]:focus::-webkit-slider-thumb {
outline: solid 2px #000;
}
input[type="range" i]:focus::-moz-range-thumb {
outline: solid 2px #000;
}

input[type="range" i]::-webkit-slider-runnable-track {
appearance: none;
height: var(--slider-track-height);
border-radius: 999px;
border: 1px solid var(--input-border-color, #666);
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3);
--chessboard-size: var(--slider-track-height);
background:
linear-gradient(to right, transparent, var(--picker-color, var(--slider-thumb-bg-color))),
repeating-conic-gradient(#808080 0% 25%, transparent 0% 50%)
50% / var(--chessboard-size) var(--chessboard-size);
}
input[type="range" i]::-moz-range-track {
appearance: none;
height: var(--slider-track-height);
border-radius: 999px;
border: 1px solid var(--input-border-color, #666);
box-shadow: inset 0px 1px 3px rgba(0, 0, 0, 0.3);
--chessboard-size: var(--slider-track-height);
background:
linear-gradient(to right, transparent, var(--picker-color, var(--slider-thumb-bg-color))),
repeating-conic-gradient(#808080 0% 25%, transparent 0% 50%)
50% / var(--chessboard-size) var(--chessboard-size);
}
</style>
<script>
const fontList = [
Expand Down Expand Up @@ -350,6 +450,7 @@
}

const colorPickerElement = document.querySelector('#color-picker')
const colorPickerAlphaElement = document.querySelector('#color-picker-alpha')
const svgSizeElement = document.querySelector('#svg-size')
const cropElement = document.querySelector('#crop-by-bbox')
const svgSelectElement = document.querySelector('#slt-svg')
Expand Down Expand Up @@ -396,12 +497,40 @@
}
})

colorPickerElement.addEventListener('change', function (event) {
const value = event.target.value
function onChangeColor() {
const hasCrop = cropElement.checked
if (!value) return
resvgOpts.background = value
const style = window.getComputedStyle(document.querySelector('html'), ':before')
const color = style.getPropertyValue('color')
const rgb_color = convertColorToRGBA(color)

console.info('getComputedStyle color\n', color)
console.info('convert to rgba()\n', rgb_color)

resvgOpts.background = rgb_color
svg2png(null, resvgOpts, hasCrop)
}

colorPickerElement.addEventListener('input', function (event) {
const value = event.target.value
if (!value) return
document.documentElement.style.setProperty('--picker-color', value)
onChangeColor()
})
colorPickerAlphaElement.addEventListener('click', function (event) {
colorPickerElement.showPicker()
})

colorPickerAlphaElement.addEventListener('input', function (event) {
const value = event.target.value
if (!value) return

const color_picker_value = getComputedStyle(document.documentElement).getPropertyValue('--picker-color')
if (!color_picker_value) {
document.documentElement.style.setProperty('--picker-color', '#FF8253')
}
// 如果使用 Relative color,这里直接使用 value + %
document.documentElement.style.setProperty('--picker-alpha', 100 - value + '%')
onChangeColor()
})

svgSizeElement.addEventListener('change', function (event) {
Expand Down Expand Up @@ -487,6 +616,30 @@
}
return { checkResult: false, index: currentFontIndex }
}

// 将 color() 转换为 rgba()
function convertColorToRGBA(color) {
if (!color || typeof color !== 'string') return color

const match = color.match(/color\(srgb\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+%?))?\)/)
if (match) {
const r = Math.round(match[1] * 255)
const g = Math.round(match[2] * 255)
const b = Math.round(match[3] * 255)
let alpha = match[4]
// 如果 alpha 是百分比形式,转换为 0 到 1 之间的小数
if (!alpha) {
alpha = 1
} else if (alpha.includes('%')) {
alpha = parseFloat(alpha) / 100
} else {
alpha = parseFloat(alpha)
}

return `rgba(${r}, ${g}, ${b}, ${alpha})`
}
return color
}
</script>
</head>

Expand Down Expand Up @@ -518,12 +671,15 @@ <h1 class="site-title">resvg-js playground</h1>
</select>
</div>
<div class="opts-cell">
<label for="color-picker">Change background:</label>
<input type="color" name="color-picker" id="color-picker">
<label for="color-picker">Background:</label>
<div class="color-picker-box">
<input type="color" name="color-picker" value="#FF8253" id="color-picker">
<input type="range" id="color-picker-alpha" min="0" max="100" value="100">
</div>
</div>
<div class="opts-cell">
<label for="svg-size">Change width:</label>
<input type="number" name="svg-size" id="svg-size">
<label for="svg-size">Width:</label>
<input type="number" name="svg-size" id="svg-size" style="max-width: 6em;">
</div>
<div class="opts-cell">
<label for="crop-by-bbox">Crop by BBox:</label>
Expand Down
Loading