I have several sliders that each apply different filters to my canvas (see image below).
But when I use the same slider several times, the same filter gets applied to the canvas on top of each other. (see the filters
attribute on the image below).
I want the filters to replace each other only if they come from the same slider input. i.e. Brightness
and Saturation
can both exist simultaneously, but never 2 Brightness
stacked on top of each other. I have also found that I cannot rely on the type
attribute in filters
since some of my sliders can result in the same type
. Are there any smooth solution to this problem?
Below is example code of how filters are currently applied to the canvas.
function saturate(o, value){
value = value / 100
let filter = new fabric.Image.filters.Saturation({
saturation: value,
});
if (o.filters) {
o.filters = []
o.filters.push(filter);
o.applyFilters();
}
}
**Below is the output of `canvas.toObject()` (see the `filter` attribute)**
You're creating a new fabric.Image.filters
on each user input, you need to initialize the filter only once and register it in an object or array, and retrieve and edit its value whenever you need apply changes.
In this demo page you can see that the filters are created only once, stored in a filters
object, and updated on user input.
const canvas = new fabric.Canvas("c");
const filters = {};
init()
async function init() {
const [width, height] = [window.innerWidth, window.innerHeight/2];
// Setting the canvas size
canvas.setWidth( width );
canvas.setHeight( height );
canvas.calcOffset();
// load the image
const img = new Image();
img.crossOrigin = "";
await new Promise(res => {
img.onload = res;
img.src = `https://picsum.photos/${width}/${height}`;
});
const image = new fabric.Image(img);
canvas.add(image)
// Create and register the filters in `filters` object
const filters = {
brightness: new fabric.Image.filters.Brightness(),
saturation: new fabric.Image.filters.Saturation(),
contrast: new fabric.Image.filters.Contrast(),
hue: new fabric.Image.filters.HueRotation(),
}
// - Brightness
// Attach the filter to the image
image.filters.push(filters.brightness);
const brightnessInput = document.querySelector("#brightness")
brightnessInput.oninput = () => {
const value = parseFloat(brightnessInput.value);
// Edit the filter value
filters.brightness.brightness = value;
// Apply the changes
image.applyFilters();
// Display the result
canvas.renderAll();
}
// - Saturation
// Attach the filter to the image
image.filters.push(filters.saturation);
const saturationInput = document.querySelector("#saturation")
saturationInput.oninput = () => {
const value = parseFloat(saturationInput.value);
// Edit the filter value
filters.saturation.saturation = value;
// Apply the changes
image.applyFilters();
// Display the result
canvas.renderAll();
}
// - Contrast
// Attach the filter to the image
image.filters.push(filters.contrast);
const contrastInput = document.querySelector("#contrast")
contrastInput.oninput = () => {
const value = parseFloat(contrastInput.value);
// Edit the filter value
filters.contrast.contrast = value;
// Apply the changes
image.applyFilters();
// Display the result
canvas.renderAll();
}
// - Hue
// Attach the filter to the image
image.filters.push(filters.hue);
const hueInput = document.querySelector("#hue")
hueInput.oninput = () => {
const value = parseFloat(hueInput.value);
// Edit the filter value
filters.hue.rotation = value;
// Apply the changes
image.applyFilters();
// Display the result
canvas.renderAll();
}
}
body {
margin: 0;
font-family: arial;
}
div {
padding: .5em 1em;
}
p {
display: flex;
margin: 0 0 .5em;
}
label{
flex:.2;
}
input {
flex:1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/451/fabric.min.js" integrity="sha512-qeu8RcLnpzoRnEotT3r1CxB17JtHrBqlfSTOm4MQzb7efBdkcL03t343gyRmI6OTUW6iI+hShiysszISQ/IahA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<canvas id="c"></canvas>
<div>
<p>
<label for="brightness">Brightness</label>
<input type="range" id="brightness" value="0" min="-1" max="1" step="0.01">
<p>
<p>
<label for="saturation">Saturation</label>
<input type="range" id="saturation" value="0" min="-1" max="1" step="0.01">
<p>
<p>
<label for="contrast">Contrast</label>
<input type="range" id="contrast" value="0" min="-1" max="1" step="0.01">
<p>
<p>
<label for="hue-value">Hue</label>
<input type="range" id="hue" value="0" min="-2" max="2" step="0.01">
<p>
</div>