Categorii
Programare

Explorarea CSS Paint API: efect de fragmentare a unei imagini *preluat de pe CSS-Tricks

Nu este nevoie să căutăm cu lupa după articole pe Internet despre acest subiect (deși nu este o idee rea să investigăm în detaliu) și nici să fim intimidați de el, dar îmi place subiectul și am zis că traduc un articol despre el, cu mici adaosuri din partea mea care sper să aducă avantaje cititorilor. Cu curaj înainte, căci vom acumula cunoștințe interesante și utile care ne dezvoltă abilitatea de a crea original!

Ce înțelegem prin efect de fragmentare a unei imagini? De exemplu, o imagine face tranziție la altă imagine prin pătrățele de dimensiuni egale peste ea cu nivele diverse de transparență care devin tot mai puțin transparente, toate convergând la vizibilitate 100% a imaginii finale. Puteți vedea mai jos elemente interactive înglobate în acest articol cu acest efect și altele similare, dar pentru a le vedea trebuie să folosești, cel puțin temporar, un navigator web care suportă CSS Paint API (în momentul scrierii acestui articol, acestea sunt: Chromium, Chrome și Edge).

Sunt multe site-uri pe Internet despre design și dezvoltare web, acesta fiind umil unul dintre ele, și, deși e departe de a fi vorba de un graf complet, este o artă aceea de a-ți alege sursele de informare și modelare a propriei experiențe de artist web.

Dintre multe site-uri cu design-uri web, un site pe care mi l-a recomandat un prieten bun acum mai mulți ani și care continuă să mă impresioneze, mai ales date fiind noutățile constante în domeniul design-ului și dezvoltării web în cazul tuturor navigatoarelor web, este CSS Tricks.

Îmi place mult cum se leagă între ele postările de pe acest minunat site. O optimizare ușoară și clară pentru motoarele de căutare, gen Google ori DuckDuckGo: punerea de link-uri la postări mai vechi din postări mai noi. Este un site bine cunoscut și cu explicații detaliate și interesante de la mai mulți autori. Realizat cu WordPress! (Dacă ai nevoie de un site WordPress, nu ezita să mă contactezi.)

Încep prin a traduce în stilul meu, cu imagini când se poate, un articol foarte bun și interesant de pe acest site.

Un API este un serviciu sau modul pe care programatorii îl pot folosi pentru a realiza ceva deosebit fără să reinventeze roata. Este ca un prelungitor în care introduci ștechere. O extensie a curentului electric.

Sunt multe de explorat la CSS Paint API (tradus aproximativ „API de pictare CSS”) și dacă dorești să aprofundez un anumit subiect te rog să îmi scrii mai jos în comentarii! Dar, în principal, este vorba de extinderea CSS prin JS, ca o prelungire a CSS. API-ul este de fapt o reutilizare a API-ului de context 2D al elementului HTML5 <canvas>. Este foarte flexibil fiindcă poți controla fiecare pixel în parte, cu o viteză de procesare foarte mare și, evident, cu accelerație hardware. CSS Paint API este parte din proiectul Houdini și în prezent este suportat doar de navigatoarele web Chromium, Chrome și Edge. Aștept cu bucurie să implementeze și cei de la Firefox acest standard!

Tradițional, CSS-ul este declarativ (la fel ca HTML: nu dai comenzi, ci descrii) și JS-ul imperativ (dai comenzi, nu descrii). Îmbinarea celor 2 este o minunăție datorită flexibilității absolute!

În acest articol explorăm crearea unei animații de fragmentare a unei imagini, de exemplu la trecerea cu mausul deasupra ei, sau într-o prezentare de diapozitive.

Acest lucru se poate realiza și fără Houdini și CSS Paint API! Dar un exercițiu minunat este acesta în orice caz și este mai flexibil pe termen lung decât folosirea de SCSS, o grămadă de <div>-uri și măști CSS. În plus, este și mai eficient. Și este creație originală în joc! Posibilitățile sunt practic infinite!

Ce se potrivește de minune cu CSS Paint API sunt variabilele CSS!

Aceasta este ceea ce dorim să realizăm în acest articol:

See the Pen houdini mask by Temani Afif (@t_afif) on CodePen.

Cu nu mai mult de 5 declarații CSS obținem o animație destul de frumoasă de acoperire cu cursorul mausului, sau cu stilusul pe o tabletă.

Ce este Paint API?

„(To) paint” înseamnă, din limba engleză, „a picta”. Tablouri, pereți, chiar digital. Paint API este parte din proiectul Houdini. Da, „Houdini”, termenul ciudat despre care vorbesc foarte mulți cu zâmbetul pe buze. Multe articole acoperă deja aspectul teoretic al lui, deci nu te voi mai plictisi cu mai multă teorie. Dacă trebuie să însumez în puține cuvinte, aș spune: este viitorul CSS-ului. Paint API (și celelalte API-uri care stau sub umbrela Houdini) ne permit să extindem CSS cu propriile noastre funcționalități. Nu mai trebuie să așteptăm lansarea de noi facilități CSS în navigatoarele web deoarece le putem face noi înșine!

Din specificație: Un API pentru permiterea dezvoltatorilor web să definească o imagine CSS personalizată cu JavaScript, care va răspunde la schimbări de stil și dimensiune.

Și de la cel care explică: API-ul CSS Paint este dezvoltat pentru a îmbunătăți caracterul extensibil al CSS. Mai precis acest API permite dezvoltatorilor să scrie o funcție de pictare pentru ca să pictăm direct în fundalul, bordura, sau conținutul unui element.

Cred că ideea este destul de clară. Putem picta orice ne dorim. Să începem cu o demonstrație de bază a colorării de fundal:

  1. Adăugăm „pictorul” folosind CSS.paintWorklet.addModule('fisierul_meu_js').
  2. Înregistrăm o nouă metodă de pictare numită draw.
  3. Înăuntru, creăm o funcție paint() în care facem toată munca. Și ia ghicește? Totul e ca lucrul cu <canvas>. Acel ctx este contextul 2D, și pur și simplu am folosit câteva bine cunoscute funcții pentru a picta un dreptunghi roșu acoperind întreaga suprafață.

Aceasta ar putea părea complex la prima vedere, dar observi că structura principală este aceeași întotdeauna: cei trei pași de mai sus sunt partea „copy/paste” pe care o repeți pentru fiecare proiect. Creația reală este codul pe care îl scriem în funcția paint().

Hai să adăugăm o variabilă:

Așa cum poți vedea, logica este destul de simplă. Definim getter-ul inputProperties cu variabilele noastre ca o listă. Adăugăm properties ca al treilea parametru la paint() și mai târziu obținem variabila noastră folosind properties.get().

Asta este tot! Acum avem tot ce ne trebuie pentru a construi efectul nostru complex de fragmentare.

Construirea măștii

Poate te întrebi de ce folosim API-ul de pictare pentru a crea un efect de fragmentare. Am spus că este o unealtă de a picta imagini deci cum ne va permite să fragmentăm o imagine?

În articolul precedent, am realizat efectul folosind diferite straturi-măști unde fiecare este un pătrat definit cu un gradient (ține minte că un gradient este doar o imagine) deci am obținut un fel de matrice și trucul a fost să ajustăm canalul alfa al fiecăruia individual.

De această dată, în loc să folosim mai multe gradient-uri vom defini o singură imagine personalizată pentru masca noastră și acea imagine personalizată va fi gestionată de API-ul nostru de pictare.

Un exemplu!

În cel de mai sus, am creat o imagine având o culoare opacă acoperind partea stângă și o culoare semitransparentă acoperind partea dreaptă. Aplicând această imagine ca o mască ne dă rezultatul logic al unei imagini pe jumătate transparente.

Acum tot ce trebuie este să împărțim imaginea în mai multe părți. Hai să definim două variabile și să actualizăm codul nostru:

See the Pen Mask houdini #2 by Temani Afif (@t_afif) on CodePen.

Partea relevantă a codului este următoarea:

const n = properties.get('--f-n');
const m = properties.get('--f-m');

const w = size.width/n;
const h = size.height/m;

for(var i=0;i<n;i++) {
  for(var j=0;j<m;j++) {
    ctx.fillStyle = 'rgba(0,0,0,'+(Math.random())+')';    
    ctx.fillRect(i*w, j*h, w, h);
}
}

N și M definesc dimensiunea matricei noastre de dreptunghiuri. W și H sunt dimensiunea fiecărui dreptunghi. Apoi avem un ciclu de bază FOR care umple fiecare dreptunghi cu o culoare aleatorie transparentă.

Cu puțin JavaScript, obținem o mască personalizată pe care o putem controla ușor prin ajustarea variabilelor CSS:

Acum, dorim să controlăm canalul alfa astfel încât să creăm efectul de decolorare al fiecărui dreptunghi și să construim efectul de fragmentare.

Hai să introducem o a treia variabilă pe care o folosim pentru canalul alfa pe care de asemenea o schimbăm la acoperire.

Am definit o proprietate CSS personalizată cu tipul <number> pe care îl trecem de la 1 la 0, și aceeași proprietate este folosită pentru definirea canalului alfa al dreptunghiurilor noastre. Nimic deosebit nu se va întâmpla la acoperire deoarece toate dreptunghiurile noastre se vor decolora în exact același fel.

Ne trebuie un truc (gen iepurele din pălărie) pentru a preveni decolorarea tuturor dreptunghiurilor în același timp, să creăm în loc o întârziere între ele. Aici este o ilustrație care explică ideea pe care o voi folosi:

Figura de mai sus prezintă animația alfa pentru două dreptunghiuri. Mai întâi definim o variabilă L care ar trebui să fie mai mare sau egală cu 1 apoi pentru fiecare dreptunghi din matricea noastră (mai precis, pentru fiecare canal alfa) realizăm o tranziție între X și Y unde X - Y = L deci avem aceeași durată per ansamblu pentru toate canalele alfa. X ar trebui să fie mai mare sau egal cu 1 și Y mai mic sau egal cu 0.

Stai puțin, valoarea alfa ar trebui să fie în intervalul [1, 0], corect?

Da, așa este! Și toate trucurile pe care lucrăm se bazează pe asta. Mai sus, alfa se animează de la 8 la -2, ceea ce înseamnă că avem o culoare opacă în intervalul [8, 1], o culoare transparentă în [0, -2] și o animație în intervalul [1, 0]. Cu alte cuvinte, oricare valoare mai mare decât 1 va avea același efect ca 1, și oricare valoare mai mică decât 0 va avea același efect ca 0.

Animația din [1, 0] nu va avea loc în același moment pentru toate dreptunghiurile noastre. Dreptunghiul 2 va ajunge la [1, 0] înainte ca dreptunghiul 1 să ajungă. Aplicăm aceasta la toate canalele alfa și obținem animațiile noastre întârziate.

În codul nostru vom actualiza aceasta:

rgba(0,0,0,'+(o)+')

să fie aceasta:

rgba(0,0,0,'+((Math.random()*(l-1) + 1) - (1-o)*l)+')

L este variabila ilustrată anterior, și o este valoarea variabilei noastre CSS care trece de la 1 la 0.

Când o = 1, avem (Math.random()*(l-1) + 1). Considerând faptul că funcția random() ne dă o valoare din intervalul [0, 1], valoarea finală va fi în intervalul [L, 1].

Când o = 0, avem (Math.random()*(l-1) + 1 - l) și o valoare în intervalul[0, 1-L].

L este variabila noastră pentru controlarea întârzierii.

Hai să vedem asta în acțiune:

Ne apropiem. Avem un efect frumos de fragmentare dar nu acela pe care l-am văzut la începutul articolului. Acesta nu este atât de lin.

Defectul este legat de funcția random(). Am văzut că fiecare canal alfa trebuie să se animeze între X și Y, deci logic aceste valori trebuie să rămână aceleași. Dar funcția paint() este apelată de multe ori în timpul tranziției, deci de fiecare dată funcția random() ne dă valori diferite X și Y pentru fiecare canal alfa; de aceea și efectul „aleatoriu” pe care îl obținem.

Pentru a rezolva asta trebuie să găsim o cale să stocăm valoarea generată, de exemplu într-o variabilă, astfel încât ea este întotdeauna aceeași pentru fiecare apel al funcției paint(). Hai să considerăm o funcție pseudo-aleatoare, o funcție care generează întotdeauna aceeași secvență de valori. În alte cuvinte, vrem să controlăm sămânța.

Din nefericire, nu putem face asta cu funcția inclusă în JavaScript, random(), deci ca oricare dezvoltator bun, hai să alegem una de pe Stack Overflow.

const mask = 0xffffffff;
const seed = 30; /* actualizează asta pentru a schimba secvența generată */
let m_w  = (123456789 + seed) & mask;
let m_z  = (987654321 - seed) & mask;

let random =  function() {
  m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) & mask;
  m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) & mask;
  var result = ((m_z << 16) + (m_w & 65535)) >>> 0;
  result /= 4294967296;
  return result;
}

Și rezultatul devine:

Avem efectul nostru de fragmentare fără cod complex:

  • un ciclu de bază îmbricat pentru a crea dreptunghiuri N x M
  • o formulă deșteaptă pentru canalul alfa pentru a crea întârzierea tranziției
  • o funcție random() pregătită luată de pe Web

Asta este tot! Tot ce trebuie să facem este să aplicăm proprietatea mask oricărui element și să ajustăm variabilele CSS. -webkit-mask funcționează astfel: când un pixel din mască are opacitatea 1, pixelul corespunzător din fundal se afișează. Când pixelul din mască are opacitatea 0, pixelul corespunzător din fundal nu se afișează. Între 0 și 1 există desigur niveluri intermediare ale aceluiași efect.

Lupta cu golurile!

Dacă te joci cu demonstrațiile de mai sus vei observa, în unele cazuri particulare, goluri ciudate între dreptunghiuri (în cazul meu, când schimb în CodePen zoom-ul la 0.25x).

Pentru a le evita, putem extinde suprafața fiecărui dreptunghi cu un mic decalaj.

Înlocuim asta:

ctx.fillRect(i*w, j*h, w, h);

…cu asta:

ctx.fillRect(i*w-.5, j*h-.5, w+.5, h+.5);

Aceasta creează o mică suprapunere între dreptunghiuri care compensează golurile dintre ele. Nu există nici o logică anume pentru valoarea 0.5 pe care am folosit-o. Poți folosi mai mari sau mai mici bazat pe cazul tău de utilizare.

Dorești mai multe forme?

Poate fi ce este mai sus extins să considere mai mult decât forme dreptunghiulare? Sigur că se poate! Hai să nu uităm că putem folosi Canvas pentru a picta oricare formă — spre deosebire de formele realizate cu CSS pur în care avem nevoie uneori de coduri ciudate. Hai să încercăm să construim acel efect de fragmentare triunghiulară.

După ce am căutat pe web, am găsit ceva numit triangularea Delaunay. Nu voi intra în teoria avansată din spatele ei, dar este un algoritm pentru o mulțime de puncte pentru a picta triunghiuri conectate cu proprietăți specifice. Sunt multe implementări gata de a fi folosite ale ei, dar vom folosi Delaunator deoarece se presupune că este cel mai rapid din mulțime.

Mai întâi definim o mulțime de puncte (vom folosi random() aici) apoi vom rula Delaunator pentru a genera triunghiurile pentru noi. În acest caz, avem nevoie doar de o variabilă care definește numărul de puncte.

const n = properties.get('--f-n');
const o = properties.get('--f-o');
const w = size.width;
const h = size.height;
const l = 7; 

var dots = [[0,0],[0,w],[h,0],[w,h]]; /* întotdeauna includem colțurile */
/* generăm N puncte aleatorii în suprafața elementului */
for (var i = 0; i < n; i++) {
  dots.push([random() * w, random() * h]);
}
/**/
/* apelăm Delaunator pentru a genera triunghiurile */
var delaunay = Delaunator.from(dots);
var triangles = delaunay.triangles;
/**/
for (var i = 0; i < triangles.length; i += 3) { /* trecem prin punctele triunghiurilor */
  /* desenăm calea triunghiurilor */
  ctx.beginPath();
  ctx.moveTo(dots[triangles[i]][0]    , dots[triangles[i]][1]);
  ctx.lineTo(dots[triangles[i + 1]][0], dots[triangles[i + 1]][1]);
  ctx.lineTo(dots[triangles[i + 2]][0], dots[triangles[i + 2]][1]);  
  ctx.closePath();
  /**/
  var alpha = (random()*(l-1) + 1) - (1-o)*l; /* the alpha value */
  /* umplem suprafața triunghiurilor cu o culoare semitransparentă */
  ctx.fillStyle = 'rgba(0,0,0,'+alpha+')';
  /* considerăm conturul pentru a umple golurile */
  ctx.strokeStyle = 'rgba(0,0,0,'+alpha+')';
  ctx.stroke();
  ctx.fill();
} 

Nu mai am de adăugat nimic la comentariile din codul de mai sus. Pur și simplu am folosit ceva JS de bază și chestii Canvas și totuși avem un efect destul de frumos.

Putem face chiar mai multe forme! Tot ce trebuie să facem este să găsim un algoritm pentru ele.

Nu pot trece mai departe fără să fac forma de hexagon!

See the Pen houdini mask – hexagon by Temani Afif (@t_afif) on CodePen.

Am luat codul din acest articol scris de Izan Pérez Cosano. Variabila noastră este acum R care va defini dimensiunea unui hexagon.

Ce urmează?

Acum că ne-am construit efectul de fragmentare, hai să ne concentrăm pe CSS. Observi că efectul este atât de simplu ca schimbarea valorii opacity (sau valoarea oricărei proprietăți cu care lucrăm) a unui element în starea lui de hover (acoperire cu mausul sau stilusul).

Animarea opacității

img {
  opacity:1;
  transition:opacity 1s;
}

img:hover {
  opacity:0;
}

Efectul de fragmentare

img {
  -webkit-mask: paint(fragmentation);
  --f-o:1;
  transition:--f-o 1s;
}

img:hover {
  --f-o:0;
}

Aceasta înseamnă că putem ușor integra acest fel de efect pentru a crea animații mai complexe. Aici sunt o mulțime de idei!

Galerie de imagini responsive

Altă versiune a aceleiași galerii:

Efect de zgomot

Ecran de încărcare

Efect de acoperire a unui card

Încheiere

Și toate acestea sunt doar vârful aisbergului a ceea ce poate fi realizat cu Paint API. Voi încheia cu două puncte importante:

  • API-ul Paint este 90% <canvas>, deci cu cât știi mai multe despre <canvas>, cu atât poți face lucruri mai interesante. Canvas este folosit mult, ceea ce înseamnă că este multă documentație și scrieri multe despre ele care să te aducă la viteză. Hei, este unul chiar aici, pe CSS-Tricks!
  • API-ul Paint ne scutește de toată complexitatea din partea CSS a lucrurilor. Nu trebuie să avem de a face cu coduri complexe și ciudate pentru a picta lucruri frumoase. Aceasta face codul CSS cu atât mai ușor de menținut, fără să menționez că este mai puțin vulnerabil la erori.

Acest articol a fost 90% preluat și tradus din:

care face parte din seria: Explorând CSS Paint API (în engleză):

Categorii
Programare

Magazin online al Lupilor Carpatini

Am realizat acest site cu WordPress și WooCommerce pentru oameni buni, frumoși, serioși, care doresc o Românie mai bună și mai frumoasă pentru noi și pentru viitoarele generații.

Îmi face plăcere să lucrez cu ei. Sunt punctuali și plini de înțelepciune.

Nu merge în fața mea, s-ar putea să nu te urmez. Să nu mergi în spatele meu, s-ar putea să nu te ghidez. Mergi alături de mine ca frate!

Lupii sunt animale care reprezintă noblețe și seriozitate, unitate în luptă! Carpații sunt munți ai României sau ai Daciei! Un magazin online pentru lupii apărători ai Daciei este binevenit! Banii câștigați revin fundației Lupilor Carpatini care luptă pentru viitorul țării noastre!

Vă recomand să vizitați site-ul și să vedeți ce produse au la vânzare!

Categorii
Versuri

DESCÂNTECUL LUMINII, de Pavel Corutz

DESCÂNTECUL LUMINII

Lumina din stele și Soare ne scaldă.
Cu mintea rece și inima caldă,
Zburăm printre aștri spre-o Lume mai bună,
S-aducem Lumina pe Terra străbună.

Lumina din oameni s-aprinde sublimă.
Cu mintea rece și inima plină
De vise de viață umană mai bună,
Pătrundem misterul din palida Lună.

Credința din oameni devine mai vie
Și mintea visează la ce va să fie.
Curg ziduri de temniți de noi sfărâmate
Și hăul cel veșnic le-nghite pe toate.

Iar Libertatea,în zboru-i năvalnic,
Sfâșie în zdrențe cel negru zăbranic.
Te-nalță,Române, din nou pân” la Soare,
Ești om între oameni și nu târâtoare!

Te-nalță,Române,departe,prin stele
Și treci cu visarea de juguri mișele !
Te-nalță,Române,prin vremea ce trece,
Cu inima caldă și mintea mai rece !

Sursa aici.

Categorii
Filme Versuri

Cel mai tare discurs, emoționant

Categorii
Versuri

Citat despre capitalism (09.09.2021)

Sursa: https://www.facebook.com/photo?fbid=355570562945078&set=a.355570599611741