Filter generator
by Comandeer
HTML
<div id="filters" class="filters">
<label for="filter-contrast" class="filters__label">Contrast</label>
<input id="filter-contrast" class="filters__value" type="range" name="contrast" data-unit="%" min="0" max="200" value="100">
<label for="filter-saturate" class="filters__label">Saturate</label>
<input id="filter-saturate" class="filters__value" type="range" name="saturate" data-unit="%" min="0" max="100" value="100">
<label for="filter-brightness" class="filters__label">Brightness</label>
<input id="filter-brightness" class="filters__value" type="range" name="brightness" data-unit="%" min="0" max="100" value="50">
<label for="filter-color" class="filters__label">Color</label>
<input id="filter-color" class="filters__value" type="range" name="hue-rotate" data-unit="deg" min="0" max="360" value="0">
<label for="filter-sepia" class="filters__label">Sepia</label>
<input id="filter-sepia" data-unit="%" class="filters__value" type="range" name="sepia" min="0" max="360" value="0">
</div>
<pre id="filters-output" class="filters-output"><code class="language-css"></code></pre>
<img src="https://www.comandeer.pl/images/custom/comandeer.jpg" alt="Preview of applied filters" id="filters-preview" class="filters-preview">
CSS
.filters {
overflow: hidden;
}
.filters__label, .filters__value {
float: left;
}
.filters__label {
clear: left;
}
.filters-output {
user-select: all;
max-width: 100%;
overflow: auto;
white-space: pre-wrap;
background: pink;
}
JavaScript
// IIFE żeby nic nie wyciekło
// http://benalman.com/news/2010/11/immediately-invoked-function-expression/
( function() {
// Pobieramy potrzebne elementy.
var filtersContainer = document.getElementById( 'filters' ),
output = document.getElementById( 'filters-output' ),
preview = document.getElementById( 'filters-preview' );
// Deklaruję funkcję, która będzie mi pobierać wartość wszystkich filtrów. Jako parametr bierze kontener filtrów.
function generateCSSString( container ) {
// Pobieram wszystkie filtry i przetwarzam tę kolekcję na tablicę przy pomocy Array.from.
var filters = Array.from( container.querySelectorAll( '.filters__value' ) );
// Stosuję reduce, żeby wyciągnąć wartości ze wszystkich pól i złączyć w jeden string.
// Być może czytelniej byłoby rozbić to na map, a potem reduce.
return filters.reduce( ( code, input ) => {
// Stosuję template literals, żeby nie bawić się w bezsensowne +.
// Nazwa filtru jest w [name] pola, wartość we własności value, a jednostkę wrzuciłem do [data-unit].
code += `${ input.name }(${ input.value }${ input.dataset.unit }) `;
return code;
}, '' )
// Z racji tego, że produkujemy string, przepuszczamy go na końcu przez trim, żeby wywalić nadmiarową spację.
.trim();
}
function updateOutput( outputElement, cssString ) {
outputElement.textContent = `filter: ${ cssString };`;
}
function updatePreview( previewElement, cssString ) {
previewElement.style.filter = cssString;
}
// W sumie jedyne, co tu chcemy zrobić, to wygenerować nowy CSS i wywołać updateOutput i updatePreview z nim jako parametrem,
function update() {
var cssString = generateCSSString( filtersContainer );
updateOutput( output, cssString );
updatePreview( preview, cssString );
}
// Teraz zastosuję event delegation, żeby nie przypinać tak dużo listenerów.
filtersContainer.addEventListener( 'change', update );
// Przy wczytaniu wywołujemy update, żeby wygenerować podgląd i...