mirror of
https://github.com/konvajs/konva.git
synced 2025-10-08 00:14:23 +08:00
brave detection
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>KonvaJS Sandbox</title>
|
||||
<title>KonvaJS Blur Comparison Sandbox</title>
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0, user-scalable=1.0, minimum-scale=1.0, maximum-scale=1.0"
|
||||
@@ -14,740 +14,31 @@
|
||||
font-family: Arial, sans-serif;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.section {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.demo-section {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.default-filters {
|
||||
border-top: 3px solid #e74c3c;
|
||||
}
|
||||
.custom-filters {
|
||||
border-top: 3px solid #27ae60;
|
||||
}
|
||||
|
||||
.controls {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
padding: 15px;
|
||||
border-radius: 8px;
|
||||
border: 2px solid #ddd;
|
||||
min-width: 250px;
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.control-group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.control-group:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
width: 100%;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.value-display {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
padding: 8px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-weight: bold;
|
||||
font-size: 11px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
button.active {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.emboss-btn {
|
||||
background: #3498db;
|
||||
color: white;
|
||||
}
|
||||
.emboss-btn.active {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
.solarize-btn {
|
||||
background: #f39c12;
|
||||
color: white;
|
||||
}
|
||||
.solarize-btn.active {
|
||||
background: #e67e22;
|
||||
}
|
||||
|
||||
select {
|
||||
width: 100%;
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #ddd;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
input[type='checkbox'] {
|
||||
margin-right: 5px;
|
||||
}
|
||||
</style>
|
||||
<!-- <script src="https://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script> -->
|
||||
<!-- <script src="https://unpkg.com/gifler@0.1.0/gifler.min.js"></script> -->
|
||||
<script>
|
||||
// TouchEmulator();
|
||||
</script>
|
||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.7/hammer.js"></script> -->
|
||||
<!-- <script src="https://cdn.rawgit.com/hammerjs/touchemulator/master/touch-emulator.js"></script> -->
|
||||
<!-- <script src="./hammer.js"></script> -->
|
||||
<!-- <script src="https://unpkg.com/fabric@5.2.1/dist/fabric.js"></script> -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main-container">
|
||||
<h1 style="text-align: center; margin-bottom: 30px; color: #333">
|
||||
Filter Comparison: Default vs Custom
|
||||
</h1>
|
||||
|
||||
<div class="section">
|
||||
<div class="demo-container">
|
||||
<!-- Default Filters -->
|
||||
<div class="demo-section default-filters">
|
||||
<div
|
||||
id="default-container"
|
||||
style="width: 100%; height: 400px"
|
||||
></div>
|
||||
<div class="controls">
|
||||
<h3 style="margin: 0 0 10px 0; color: #e74c3c; font-size: 14px">
|
||||
Default Konva Filters
|
||||
</h3>
|
||||
|
||||
<div class="filter-buttons">
|
||||
<button id="emboss-default" class="emboss-btn active">
|
||||
Emboss
|
||||
</button>
|
||||
<button id="solarize-default" class="solarize-btn">
|
||||
Solarize
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Default Emboss Controls -->
|
||||
<div id="emboss-controls-default">
|
||||
<div class="control-group">
|
||||
<label for="emboss-strength-default"
|
||||
>Strength:
|
||||
<span
|
||||
id="emboss-strength-value-default"
|
||||
class="value-display"
|
||||
>0.5</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="emboss-strength-default"
|
||||
min="0"
|
||||
max="1"
|
||||
value="0.5"
|
||||
step="0.1"
|
||||
/>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label for="emboss-white-default"
|
||||
>White Level:
|
||||
<span id="emboss-white-value-default" class="value-display"
|
||||
>0.5</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="emboss-white-default"
|
||||
min="0"
|
||||
max="1"
|
||||
value="0.5"
|
||||
step="0.1"
|
||||
/>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label for="emboss-direction-default">Direction:</label>
|
||||
<select id="emboss-direction-default">
|
||||
<option value="top-left" selected>Top Left</option>
|
||||
<option value="top">Top</option>
|
||||
<option value="top-right">Top Right</option>
|
||||
<option value="right">Right</option>
|
||||
<option value="bottom-right">Bottom Right</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
<option value="bottom-left">Bottom Left</option>
|
||||
<option value="left">Left</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label
|
||||
><input type="checkbox" id="emboss-blend-default" /> Blend
|
||||
Mode</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Default Solarize Controls -->
|
||||
<div id="solarize-controls-default" style="display: none">
|
||||
<div class="control-group">
|
||||
<label for="solarize-threshold-default"
|
||||
>Threshold:
|
||||
<span
|
||||
id="solarize-threshold-value-default"
|
||||
class="value-display"
|
||||
>127</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="solarize-threshold-default"
|
||||
min="0"
|
||||
max="255"
|
||||
value="127"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Filters -->
|
||||
<div class="demo-section custom-filters">
|
||||
<div id="custom-container" style="width: 100%; height: 400px"></div>
|
||||
<div class="controls">
|
||||
<h3 style="margin: 0 0 10px 0; color: #27ae60; font-size: 14px">
|
||||
Custom Implementations
|
||||
</h3>
|
||||
|
||||
<div class="filter-buttons">
|
||||
<button id="emboss-custom" class="emboss-btn active">
|
||||
Emboss
|
||||
</button>
|
||||
<button id="solarize-custom" class="solarize-btn">
|
||||
Solarize
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Custom Emboss Controls -->
|
||||
<div id="emboss-controls-custom">
|
||||
<div class="control-group">
|
||||
<label for="emboss-strength-custom"
|
||||
>Strength:
|
||||
<span
|
||||
id="emboss-strength-value-custom"
|
||||
class="value-display"
|
||||
>1</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="emboss-strength-custom"
|
||||
min="0"
|
||||
max="3"
|
||||
value="1"
|
||||
step="0.1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Custom Solarize Controls -->
|
||||
<div id="solarize-controls-custom" style="display: none">
|
||||
<div class="control-group">
|
||||
<label for="solarize-threshold-custom"
|
||||
>Threshold:
|
||||
<span
|
||||
id="solarize-threshold-value-custom"
|
||||
class="value-display"
|
||||
>128</span
|
||||
></label
|
||||
>
|
||||
<input
|
||||
type="range"
|
||||
id="solarize-threshold-custom"
|
||||
min="0"
|
||||
max="255"
|
||||
value="128"
|
||||
step="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="container"></div>
|
||||
<script type="module">
|
||||
import Konva from '../src/index.ts';
|
||||
|
||||
// ===============================
|
||||
// Custom filter implementations
|
||||
// ===============================
|
||||
function solarizeImageData(imageData, threshold = 128) {
|
||||
const d = imageData.data;
|
||||
for (let i = 0; i < d.length; i += 4) {
|
||||
const r = d[i],
|
||||
g = d[i + 1],
|
||||
b = d[i + 2];
|
||||
// sRGB luma
|
||||
const L = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
||||
if (L >= threshold) {
|
||||
d[i] = 255 - r;
|
||||
d[i + 1] = 255 - g;
|
||||
d[i + 2] = 255 - b;
|
||||
}
|
||||
}
|
||||
return imageData;
|
||||
}
|
||||
|
||||
function embossImageData(imageData) {
|
||||
const data = imageData.data;
|
||||
const w = imageData.width;
|
||||
const h = imageData.height;
|
||||
|
||||
debugger;
|
||||
// Inputs from Konva node
|
||||
const strength01 = Math.min(
|
||||
1,
|
||||
Math.max(0, this.embossStrength?.() ?? 0.5)
|
||||
); // [0..1]
|
||||
const whiteLevel01 = Math.min(
|
||||
1,
|
||||
Math.max(0, this.embossWhiteLevel?.() ?? 0.5)
|
||||
); // [0..1]
|
||||
// Convert string direction to degrees
|
||||
const directionMap = {
|
||||
'top-left': 315,
|
||||
top: 270,
|
||||
'top-right': 225,
|
||||
right: 180,
|
||||
'bottom-right': 135,
|
||||
bottom: 90,
|
||||
'bottom-left': 45,
|
||||
left: 0,
|
||||
};
|
||||
const directionDeg =
|
||||
directionMap[this.embossDirection?.() ?? 'top-left'] ?? 315; // degrees
|
||||
const blend = !!(this.embossBlend?.() ?? false);
|
||||
|
||||
// Internal mapping:
|
||||
// - Pixastic "strength" was 0..10; we honor your 0..1 API and scale accordingly.
|
||||
// - Sobel directional response is roughly in [-1020..1020] for 8-bit luminance; scale to ~±128.
|
||||
const strength = strength01 * 10;
|
||||
const bias = whiteLevel01 * 255;
|
||||
const dirRad = (directionDeg * Math.PI) / 180;
|
||||
const cx = Math.cos(dirRad);
|
||||
const cy = Math.sin(dirRad);
|
||||
const SCALE = (128 / 1020) * strength; // ≈0.1255 * strength
|
||||
|
||||
// Precompute luminance (Rec.709)
|
||||
const src = new Uint8ClampedArray(data); // snapshot
|
||||
const lum = new Float32Array(w * h);
|
||||
for (let p = 0, i = 0; i < data.length; i += 4, p++) {
|
||||
lum[p] = 0.2126 * src[i] + 0.7152 * src[i + 1] + 0.0722 * src[i + 2];
|
||||
}
|
||||
|
||||
// Sobel kernels (flattened)
|
||||
const Gx = [-1, 0, 1, -2, 0, 2, -1, 0, 1];
|
||||
const Gy = [-1, -2, -1, 0, 0, 0, 1, 2, 1];
|
||||
|
||||
// neighbor offsets around center pixel in lum space
|
||||
const OFF = [-w - 1, -w, -w + 1, -1, 0, 1, w - 1, w, w + 1];
|
||||
|
||||
// Helpers
|
||||
const clamp8 = (v) => (v < 0 ? 0 : v > 255 ? 255 : v);
|
||||
|
||||
// Process: leave a 1px border unchanged (faster/cleaner)
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
for (let x = 1; x < w - 1; x++) {
|
||||
const p = y * w + x;
|
||||
|
||||
// Directional derivative = (cosθ * Gx + sinθ * Gy) • neighborhood(lum)
|
||||
let sx = 0,
|
||||
sy = 0;
|
||||
// unroll loop for speed
|
||||
sx += lum[p + OFF[0]] * Gx[0];
|
||||
sy += lum[p + OFF[0]] * Gy[0];
|
||||
sx += lum[p + OFF[1]] * Gx[1];
|
||||
sy += lum[p + OFF[1]] * Gy[1];
|
||||
sx += lum[p + OFF[2]] * Gx[2];
|
||||
sy += lum[p + OFF[2]] * Gy[2];
|
||||
sx += lum[p + OFF[3]] * Gx[3];
|
||||
sy += lum[p + OFF[3]] * Gy[3];
|
||||
// center has 0 weights in both Sobel masks; can skip if desired
|
||||
sx += lum[p + OFF[5]] * Gx[5];
|
||||
sy += lum[p + OFF[5]] * Gy[5];
|
||||
sx += lum[p + OFF[6]] * Gx[6];
|
||||
sy += lum[p + OFF[6]] * Gy[6];
|
||||
sx += lum[p + OFF[7]] * Gx[7];
|
||||
sy += lum[p + OFF[7]] * Gy[7];
|
||||
sx += lum[p + OFF[8]] * Gx[8];
|
||||
sy += lum[p + OFF[8]] * Gy[8];
|
||||
|
||||
const r = cx * sx + cy * sy; // directional response
|
||||
const outGray = clamp8(bias + r * SCALE); // biased, scaled, clamped
|
||||
|
||||
const o = p * 4;
|
||||
if (blend) {
|
||||
// Add the emboss "relief" around chosen bias to original RGB
|
||||
const delta = outGray - bias; // symmetric around whiteLevel
|
||||
data[o] = clamp8(src[o] + delta);
|
||||
data[o + 1] = clamp8(src[o + 1] + delta);
|
||||
data[o + 2] = clamp8(src[o + 2] + delta);
|
||||
data[o + 3] = src[o + 3];
|
||||
} else {
|
||||
// Grayscale embossed output
|
||||
data[o] = data[o + 1] = data[o + 2] = outGray;
|
||||
data[o + 3] = src[o + 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy border (untouched) to keep edges clean
|
||||
// top & bottom rows
|
||||
for (let x = 0; x < w; x++) {
|
||||
let oTop = x * 4,
|
||||
oBot = ((h - 1) * w + x) * 4;
|
||||
data[oTop] = src[oTop];
|
||||
data[oTop + 1] = src[oTop + 1];
|
||||
data[oTop + 2] = src[oTop + 2];
|
||||
data[oTop + 3] = src[oTop + 3];
|
||||
data[oBot] = src[oBot];
|
||||
data[oBot + 1] = src[oBot + 1];
|
||||
data[oBot + 2] = src[oBot + 2];
|
||||
data[oBot + 3] = src[oBot + 3];
|
||||
}
|
||||
// left & right columns
|
||||
for (let y = 1; y < h - 1; y++) {
|
||||
let oL = y * w * 4,
|
||||
oR = (y * w + (w - 1)) * 4;
|
||||
data[oL] = src[oL];
|
||||
data[oL + 1] = src[oL + 1];
|
||||
data[oL + 2] = src[oL + 2];
|
||||
data[oL + 3] = src[oL + 3];
|
||||
data[oR] = src[oR];
|
||||
data[oR + 1] = src[oR + 1];
|
||||
data[oR + 2] = src[oR + 2];
|
||||
data[oR + 3] = src[oR + 3];
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
// Add custom properties
|
||||
// Konva.Factory.addGetterSetter(Konva.Node, 'solarizeThreshold', 128);
|
||||
// Konva.Factory.addGetterSetter(Konva.Node, 'embossStrengthCustom', 1);
|
||||
|
||||
const containerWidth = 400;
|
||||
const containerHeight = 400;
|
||||
|
||||
// ===============================
|
||||
// Default Filters Stage
|
||||
// ===============================
|
||||
const defaultStage = new Konva.Stage({
|
||||
container: 'default-container',
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
const stage = new Konva.Stage({
|
||||
container: 'container',
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
});
|
||||
|
||||
const defaultLayer = new Konva.Layer();
|
||||
defaultStage.add(defaultLayer);
|
||||
const layer = new Konva.Layer();
|
||||
stage.add(layer);
|
||||
|
||||
// ===============================
|
||||
// Custom Filters Stage
|
||||
// ===============================
|
||||
const customStage = new Konva.Stage({
|
||||
container: 'custom-container',
|
||||
width: containerWidth,
|
||||
height: containerHeight,
|
||||
const circle = new Konva.Circle({
|
||||
x: stage.width() / 2,
|
||||
y: stage.height() / 2,
|
||||
radius: 100,
|
||||
fill: 'red',
|
||||
draggable: true,
|
||||
});
|
||||
|
||||
const customLayer = new Konva.Layer();
|
||||
customStage.add(customLayer);
|
||||
|
||||
// Load image and create both versions
|
||||
const imageObj = new Image();
|
||||
imageObj.onload = function () {
|
||||
// Default filters image
|
||||
const defaultImage = new Konva.Image({
|
||||
image: imageObj,
|
||||
x: 50,
|
||||
y: 50,
|
||||
width: 300,
|
||||
height: 225,
|
||||
draggable: true,
|
||||
});
|
||||
defaultImage.cache({ pixelRatio: 2 });
|
||||
defaultImage.filters([Konva.Filters.Emboss]);
|
||||
defaultLayer.add(defaultImage);
|
||||
defaultLayer.draw();
|
||||
|
||||
// Custom filters image
|
||||
const customImage = new Konva.Image({
|
||||
image: imageObj,
|
||||
x: 50,
|
||||
y: 50,
|
||||
width: 300,
|
||||
height: 225,
|
||||
draggable: true,
|
||||
});
|
||||
customImage.cache({ pixelRatio: 2 });
|
||||
customImage.embossStrength(
|
||||
parseFloat(document.getElementById('emboss-strength-default').value)
|
||||
);
|
||||
customImage.embossWhiteLevel(
|
||||
parseFloat(document.getElementById('emboss-white-default').value)
|
||||
);
|
||||
customImage.embossDirection(
|
||||
document.getElementById('emboss-direction-default').value
|
||||
);
|
||||
customImage.embossBlend(
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
customImage.filters([embossImageData]);
|
||||
customLayer.add(customImage);
|
||||
customLayer.draw();
|
||||
|
||||
// ===============================
|
||||
// Control Logic
|
||||
// ===============================
|
||||
|
||||
let currentDefaultFilter = 'emboss';
|
||||
let currentCustomFilter = 'emboss';
|
||||
|
||||
function updateDefaultFilter() {
|
||||
if (currentDefaultFilter === 'emboss') {
|
||||
defaultImage.filters([Konva.Filters.Emboss]);
|
||||
defaultImage.embossStrength(
|
||||
parseFloat(
|
||||
document.getElementById('emboss-strength-default').value
|
||||
)
|
||||
);
|
||||
defaultImage.embossWhiteLevel(
|
||||
parseFloat(document.getElementById('emboss-white-default').value)
|
||||
);
|
||||
defaultImage.embossDirection(
|
||||
document.getElementById('emboss-direction-default').value
|
||||
);
|
||||
defaultImage.embossBlend(
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
} else {
|
||||
// Use custom solarize function for default filter to add threshold control
|
||||
defaultImage.filters([Konva.Filters.Solarize]);
|
||||
}
|
||||
defaultLayer.batchDraw();
|
||||
updateCustomFilter();
|
||||
}
|
||||
|
||||
function updateCustomFilter() {
|
||||
console.log(currentCustomFilter);
|
||||
if (currentCustomFilter === 'emboss') {
|
||||
customImage.embossStrength(
|
||||
parseFloat(
|
||||
document.getElementById('emboss-strength-default').value
|
||||
)
|
||||
);
|
||||
customImage.embossWhiteLevel(
|
||||
parseFloat(document.getElementById('emboss-white-default').value)
|
||||
);
|
||||
customImage.embossDirection(
|
||||
document.getElementById('emboss-direction-default').value
|
||||
);
|
||||
customImage.embossBlend(
|
||||
document.getElementById('emboss-blend-default').checked
|
||||
);
|
||||
|
||||
customImage.filters([embossImageData]);
|
||||
} else {
|
||||
customImage.filters([
|
||||
(imageData) =>
|
||||
solarizeImageData(
|
||||
imageData,
|
||||
parseFloat(
|
||||
document.getElementById('solarize-threshold-custom').value
|
||||
)
|
||||
),
|
||||
]);
|
||||
}
|
||||
customLayer.batchDraw();
|
||||
}
|
||||
|
||||
// Default filter button controls
|
||||
document
|
||||
.getElementById('emboss-default')
|
||||
.addEventListener('click', () => {
|
||||
currentDefaultFilter = 'emboss';
|
||||
document.getElementById('emboss-default').classList.add('active');
|
||||
document
|
||||
.getElementById('solarize-default')
|
||||
.classList.remove('active');
|
||||
document.getElementById('emboss-controls-default').style.display =
|
||||
'block';
|
||||
document.getElementById('solarize-controls-default').style.display =
|
||||
'none';
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('solarize-default')
|
||||
.addEventListener('click', () => {
|
||||
currentDefaultFilter = 'solarize';
|
||||
document.getElementById('solarize-default').classList.add('active');
|
||||
document
|
||||
.getElementById('emboss-default')
|
||||
.classList.remove('active');
|
||||
document.getElementById('solarize-controls-default').style.display =
|
||||
'block';
|
||||
document.getElementById('emboss-controls-default').style.display =
|
||||
'none';
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Custom filter button controls
|
||||
document
|
||||
.getElementById('emboss-custom')
|
||||
.addEventListener('click', () => {
|
||||
currentCustomFilter = 'emboss';
|
||||
document.getElementById('emboss-custom').classList.add('active');
|
||||
document
|
||||
.getElementById('solarize-custom')
|
||||
.classList.remove('active');
|
||||
document.getElementById('emboss-controls-custom').style.display =
|
||||
'block';
|
||||
document.getElementById('solarize-controls-custom').style.display =
|
||||
'none';
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('solarize-custom')
|
||||
.addEventListener('click', () => {
|
||||
currentCustomFilter = 'solarize';
|
||||
document.getElementById('solarize-custom').classList.add('active');
|
||||
document.getElementById('emboss-custom').classList.remove('active');
|
||||
document.getElementById('solarize-controls-custom').style.display =
|
||||
'block';
|
||||
document.getElementById('emboss-controls-custom').style.display =
|
||||
'none';
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Default emboss controls
|
||||
document
|
||||
.getElementById('emboss-strength-default')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById(
|
||||
'emboss-strength-value-default'
|
||||
).textContent = e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter;
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('emboss-white-default')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById('emboss-white-value-default').textContent =
|
||||
e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter;
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('emboss-direction-default')
|
||||
.addEventListener('change', () => {
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
document
|
||||
.getElementById('emboss-blend-default')
|
||||
.addEventListener('change', () => {
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Default solarize controls
|
||||
document
|
||||
.getElementById('solarize-threshold-default')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById(
|
||||
'solarize-threshold-value-default'
|
||||
).textContent = e.target.value;
|
||||
updateDefaultFilter();
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
// Custom filter controls
|
||||
document
|
||||
.getElementById('emboss-strength-custom')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById(
|
||||
'emboss-strength-value-custom'
|
||||
).textContent = e.target.value;
|
||||
updateCustomFilter();
|
||||
});
|
||||
|
||||
document
|
||||
.getElementById('solarize-threshold-custom')
|
||||
.addEventListener('input', (e) => {
|
||||
document.getElementById(
|
||||
'solarize-threshold-value-custom'
|
||||
).textContent = e.target.value;
|
||||
updateCustomFilter();
|
||||
});
|
||||
};
|
||||
|
||||
imageObj.crossOrigin = 'anonymous';
|
||||
imageObj.src = 'https://konvajs.org/assets/darth-vader.jpg';
|
||||
layer.add(circle);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Reference in New Issue
Block a user