Heim >Web-Frontend >CSS-Tutorial >% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei

% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei

Linda Hamilton
Linda HamiltonOriginal
2025-01-18 06:10:09390Durchsuche

Dies ist eine direkte Fortsetzung von „Abrufen von 32-Bit-API-Antwortdaten in CSS“

In CSS waren 16 Bit Antwortdaten, sowohl in der intrinsischen Breite als auch in der intrinsischen Höhe platziert, eine enorme Verbesserung im Vergleich dazu, dass API-Antwortdaten überhaupt nicht abgerufen werden konnten (ohne JavaScript)...

Aber in den Tagen, nachdem ich es herausgefunden hatte, neigten meine Gedanken zu einer Richtung:
Es würde viel mehr Spaß machen, wenn es 16 Bit 32 Mal wäre, statt nur zweimal.

Gif recording of a harsh terminal app setting several integer values to an array of variables one at a time

Packen von 512 Bit in ein SVG zur Exfiltration

Ich meditierte vor dem Schlafengehen und kam plötzlich auf einen weiteren inspirierten Gedanken -

„Was wäre, wenn es für das Bilddokument selbst möglich wäre, seine eigene intrinsische Größe zu animieren?“

Die übliche Kette von Erkenntnissen nach einem inspirierten Gedanken blitzte mit dem Verständnis auf, wie es erreicht werden könnte ... Ich musste nur herausfinden, ob ein solcher Bildtyp existiert.

Ich schnappte mir mein Handy und durchsuchte alle mir bekannten animierten Bildformate, um zu sehen, ob eines davon dazu in der Lage war. svg, webp, apng, gif, vielleicht seltsame Videoformate? Ich konnte keine finden.

Am Morgen sagte etwas in mir, ich solle weiter in SVG graben.

Ich habe eingebettetes CSS, Medienabfragen, verwendete Defs und weitere verwendete Defs ausprobiert, bin in die zahlreichen SVG-Animationsdokumente eingetaucht, habe versucht, sie auszutricksen, und habe mich über andere Ideen und Eigenschaften im Zusammenhang mit Animationen informiert – nichts konnte mich durchhalten Höhe oder Breite einstellen.

Aber dieser letzte Link hat mich zum Nachdenken gebracht...

...was ist mit viewBox? Ich müsste noch einige andere Hürden überwinden, aber ... Ist das möglich, es zu animieren?

vvv
ES IST!!
^^^

Den Lösungsraum sortieren

Das Problem besteht nun darin, dass, wenn Sie keine Breiten- und Höhenattribute für das Root-SVG-Element festlegen und dann versuchen, die SVG-Datei als Inhalt für ein Pseudo zu verwenden, diese 0 x 0 Pixel rendert, da es sich um ein Vektordokument handelt und nicht mehr über ein Vektordokument verfügt Eigengröße.

Also habe ich es gesucht und „ertainAspectRatio“ hinzugefügt ... Immer noch 0x0 ... aber dann habe ich in meinem CSS die Breite auf 10 Pixel festgelegt und das beibehaltene Seitenverhältnis der ViewBox die Höhe bestimmen lassen (die ich mit ändern kann). (im SVG eingebettete Animation) uuuund... das HTML-Element, das es enthält, ist auf die erwartete Höhe gewachsen.

:3

Wenn es nur einen Frame gäbe, würde dieser meine ursprünglichen 32 Bit nehmen und ihn halbieren; da nur eine Dimension exfiltriert werden kann, während die andere statisch ist.

ABER! Nun, meine zweite Dimension war Zeit und die erste ist der Gnade der Zeit ausgeliefert, es stehen also mehr als genug Daten zur Verfügung.

Wie aufregend!

Ich habe alles über die Steuerung der Animation in SVGs gelernt und ein serverseitiges Skript erstellt, um mein erstes animiertes SVG zu generieren:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

(Warum PHP?! - weil ich bereits einen Server hatte, für den ich jahrelang bezahlt habe und der von Anfang an so eingerichtet war, dass er PHP ausführt ... Und obwohl ich mit JavaScript und Node. einen wunderbaren Lebensunterhalt verdient habe Wirklich gut, manchmal macht es Spaß, jede einzelne Funktion, jeden einzelnen Operator und jede einzelne Syntax nachzuschlagen, um etwas durchzugehen, von dem Sie wissen, dass Sie es können tun können, ohne Einzelheiten zu kennen. lol)

Lassen Sie uns nun meinen ersten % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei aus dem vorherigen Artikel teilen, um zu sehen, wie CSS auf --vars reagiert und die Größe ändert, während das SVG voranschreitet:

Bestätigt! Wir können die Größenänderung ablesen. Wie im vorherigen Artikel wird am Ende die View-Timeline-Messtechnik anstelle dieser tan(atan2())-Technik verwendet.

Es bringt meine CPU zum Kochen, sodass wir sie aus dem Inhalt entfernen möchten, wenn die Exfiltration abgeschlossen ist.

Konzeptionell, wie man 1D-Zeit prozedural exfiltriert

Die obige Demo ist für sich genommen nicht sehr nützlich. Es meldet eine Kopie der Höhe, wann immer sie vorhanden ist, aber wir müssen sie speichern ... und was nützen eine Reihe von 16-Bit-Werten, wenn Sie die Reihenfolge nicht kennen und ihr nicht vertrauen können?

Ich weiß, dass ich mit dem CPU-Hack Werte in CSS akkumulieren und mathematisch bestimmen kann, welche --var eingehende Werte aktualisiert, anstatt nur den vorherigen Wert beizubehalten, sodass ich mir keine besonderen Gedanken über CSS machen muss. Wie könnten wir im Allgemeinen 1D im Laufe der Zeit exfiltrieren?

Sentinel-Werte zur Rettung!

Die Größe des von uns genutzten Messbereichs MUSS nicht auf 16 Bit begrenzt sein, auch wenn ich die Datenpakete selbst auf 16 Bit beschränken möchte. Da können wir also auch ein paar Wächter reinpacken. css-api-fetch wird mit der Fähigkeit ausgeliefert, Werte bis zu 99999 zu verarbeiten, was deutlich über 65535 (der 16-Bit-Obergrenze) liegt.

Was müssen wir also wissen?

Auf welche Probleme könnten wir stoßen?

Wenn zwei Werte in unseren Daten hintereinander gleich sind, benötigen wir eine Unterbrechung, um zu wissen, dass es sich um zwei unterschiedliche Pakete handelt. Ich habe bereits beschlossen, dass wir 512 Bit anstreben, daher muss die SVG-Animation maximal 32 16-Bit-Datenrahmen haben, mit Sentinel-Rahmen dazwischen ...

Wenn sich die CPU überlastet anfühlt, kann es so aussehen, als würde die SVG-Animation einzelne Schritte vollständig überspringen. Das heißt, wir brauchen eine Möglichkeit, immer zu wissen, in welchem ​​Schritt wir uns befinden. Anstelle eines einzelnen „zwischen Datenrahmen“-Sentinels verwenden wir also den Datenindex (basiert auf 1 wie CSS-nth-*-Selektoren) als Sentinel-Wert und machen ihn so zu einem eigenen diskreten Schritt vor dem diskreten Schritt, der die Daten für diesen Index anzeigt.

Sentinel-Index -> Daten -> Sentinel-Index -> Daten ...

Das lässt uns auch wissen, wann es eine Schleife gibt, möglicherweise, wenn wir Sentinel 1 erreichen.

Aber woher wissen wir, dass es nicht zu einem anderen Datenrahmen gesprungen ist und wir es versehentlich im falschen Slot aufgezeichnet haben?

Wir müssen es in einer Schleife laufen lassen und weitermachen, bis es richtig ist, und der beste Weg, um herauszufinden, ob die Daten korrekt sind, ist eine Prüfsumme! Wir brauchen also einen weiteren Datenrahmen und einen Wächter für diesen Wert.

Erstellen des Prüfsummenalgorithmus

Ich könnte CSS-Bin-Bits verwenden, um alle Daten mit XOR zu versehen, aber das ist ziemlich umfangreich und wird nirgendwo anders benötigt – entscheiden wir uns für eine Alternative, die einfach in CSS zu realisieren ist.

Mathematisch ausgedrückt: Wenn Sie einen 16-Bit-Wert nehmen, ihn durch 256 dividieren (von der Untergrenze zur Ganzzahl) und den 16-Bit-Wert erneut modulo durch 256 nehmen, erhalten Sie die High- und Low-Bytes. Addieren Sie diese 8-Bit-Werte und Sie erhalten 9 Bit. Das scheint ein vernünftiger Prüfsummenansatz zu sein, aber lasst uns noch einmal darauf zurückkommen.

Wir müssen nicht im 16-Bit-Bereich bleiben, um die Prüfsumme zu berechnen, solange die endgültige Prüfsumme 16 Bit beträgt, also summieren wir einfach alle (bis zu) 32 Werte.

Wir müssen jedoch auf falsche Speicherschreibvorgänge aufgrund übersprungener Frames achten, also addieren wir die geraden Indexwerte zweimal, damit einen Anschein von Ordnung besteht.

Diese Summe, 16-Bit-Werte, 32 Mal, plus weitere 16 Mal, ergibt etwa 22 Bit. Teilen und modulieren Sie 11 Bits auf jeder Seite, kehren Sie zum vorherigen Gedanken zurück, addieren Sie diese dann und erhalten Sie 12 Bits als unsere Prüfsummenantwort.

Scheint vernünftig... Es ist nicht völlig fehlersicher, aber das SVG müsste mehrere Schritte überspringen, um es so durcheinander zu bringen, dass VIELLEICHT jetzt die gleiche Prüfsumme generiert wird... Auf jeden Fall senden wir auch die Daten zurück Länge und beziehen Sie diese auch in die Prüfsumme ein, indem Sie sie einfach als letzten Schritt unserer Prüfsumme hinzufügen. Die maximale Datenlänge (Anzahl der 16-Bit-Werte, die wir verarbeiten möchten) beträgt nur 32, sodass die Addition des Längenwerts zu den 12 Bits nicht annähernd über 16 Bit hinausgeht. Juhu!

Spoiler: Das ist habe ich gemacht, aber CSS wurde irgendwo bei etwa 21 Bit verlustbehaftet, also habe ich es aufgeteilt und effektiv den gleichen Algorithmus durchgeführt, aber jeweils in kleineren Teilen. Serverseitig verwendet das Alg genau wie beschrieben.

Technisch gesehen spielt es bei dem von uns beschriebenen Setup keine Rolle, wie die Reihenfolge in der Animation ist, solange jeder Sentinel Ihnen mitteilt, welchen Index der nächste Frame in der Daten.

Noch etwas: Lassen Sie uns den Datenlängenwert zuerst in die Antwort einfügen und auch dafür einen Sentinel hinzufügen (Sentinel in der SVG-Animation vor dem Wert, wie bei den restlichen Daten).

Das sind 34 Wächter. Die SVG-ViewBox-Höhe darf nicht 0 sein, und CSS profitiert davon, wenn 0 intern keine Daten darstellt. Nehmen wir also an, wir haben 35 Sentinels, wobei 0 absichtlich nicht verwendet wird.

Alle Datenrahmen werden jetzt in das SVG eingebettet, wobei 35 zu ihrem Wert hinzugefügt werden. Längen- und Prüfsummendatenwerte erhalten AUCH 35 zum Viewbox-Wert hinzugefügt. Die ViewBox-Höhen in der SVG-Animation, die die Wächter darstellen, haben Werte von 0 bis 34 (0 wird übersprungen) und sagen uns jeweils genau, was der nächste Frame in der SVG-Animation darstellt.

CSS-Seite prüfen wir nur, ob die Rohmessung größer als 34 ist, es handelt sich um Daten, also subtrahieren Sie 35 davon, wenn es weniger als 35 ist, handelt es sich um einen Sentinel.

A meme picture of Charlie Day from It's Always Sunny in Philadelphia with a crazed look standing in front of a board covered in paper with red lines connecting them hectically

Beginnen Sie mit der Exfiltration der 512 Bits mit CSS

Nachdem ich die PHP-Seite zum Generieren der SVG-Animation wie beschrieben fertiggestellt hatte, dachte ich über bestimmte Möglichkeiten nach, wie ich das CSS für diesen Exfiltrationsprozess starten könnte.

Hier ist der PHP-Code!
<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

Es gibt einige Möglichkeiten, dies in CSS zu erreichen, und mit den jüngsten Spezifikationsergänzungen werden möglicherweise noch viele weitere hinzukommen.

Mein erster Ansatz ist konzeptionell der einfachste: Ich verwende eine Ansichtszeitleiste für jedes Datenelement und mache immer wieder das Gleiche. Es funktionierte, aber ich stöhnte während meiner Fortschritte, unzufrieden darüber, wie ekelhaft es war. Das wären fast 40 Animationen auf :root, wenn ich fortfahre.

Also ging ich schlafen.

Als ich aufwachte, lag ich einige Momente da und schaute lächelnd aus dem Fenster, mit dem Gefühl, gerade aufgewacht zu sein oder meditiert zu haben, dann schoss mir eine Flut von Gedanken durch den Kopf. Ich drehte mich um, schnappte mir mein Notizbuch und den nächstgelegenen Stift, setzte mich im Bett auf und begann, den Algorithmus aufzuschreiben, um ihn mit nur 6 CSS-Animationen herauszufiltern.

my chicken scratch handwriting on a single piece of lined notebook paper with arrows pointing to a couple of nested boxes detailing the method described below

Buchstäblich auf dem Papier gelöst; GENAUso wird es umgesetzt.

Ich stand auf, setzte mich an meinen Computer, ignorierte meine vorherige Arbeit und öffnete einen neuen % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei.

Ich habe die 4 HTML-Elemente eingerichtet, die dort im Chicken Scratch angegeben sind, und dann das CSS-Bedienfeld mit Notizen rund um die 4 entsprechenden leeren Klassenselektoren überflutet. Es wird jetzt nicht auf :root sein, aber wir können alles, was darauf angewiesen ist, darin platzieren.

Keine einzige Funktionalität wurde hinzugefügt, bis die Notizen vom Papier kopiert und detaillierter in % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei geschrieben wurden.

Als ich fertig war, habe ich einfach die Notizen gelesen und angefangen, das Gesagte umzusetzen, bis hin zum endgültigen Arbeitsergebnis.

(Ich habe „20“ statt „35“ geschrieben, weil ich mit 256 Bit testen wollte)

Ich werde näher darauf eingehen, wie es funktioniert. Aufgrund der Ansichtszeitleiste und des Zeitleistenbereichs können Sie Daten so einrichten, dass sie in einer Art Klein-Flasche-Form einfließen, wenn Sie sich vorstellen können, wie die Oberfläche animiert und in das „Loch“ gesaugt wird, zurück zur schmalen Oberseite und nach unten wieder über die Oberfläche, gewinnt durch Dom-Schichten an Größe und Komplexität und schlängelt sich dann zurück durch das Schwarze Loch in das höhere Bewusstsein (:root).

Es ist größtenteils vertikal zyklisch (und nicht hauptsächlich horizontal zyklisch oder statisch zyklisch)

Exfiltrieren der 512 Bit mit CSS

Die Notizen haben wir leicht optimiert und klarer gemacht:

256 Test -> 512 endgültig

und ich habe darin einen Präsentationsknoten hinzugefügt, was großartig ist, weil ich auch die Interna anzeigen kann, während der Algorithmus ausgeführt wird.

Aber hier sind die letzten Anmerkungen ohne den ganzen Implementierungs- und Präsentationslärm. Hier wird genau beschrieben, wie das Ganze funktioniert.

Es ist vielleicht nicht in gutem Zustand, dass ein Artikel so viele Details extern eingebettet hat, aber ich werde jeden Teil aufschlüsseln, um zu zeigen, wie er umgesetzt wird.

Hauptcontroller

Oben in dieser Struktur befinden sich 4 Zeitleistenwerte und ihre Animationen. Also lasst uns diese einfach reinstecken.

Der wichtigste Teil des Datenflusses, der dadurch ermöglicht wird, besteht darin, dass wir tief im DOM verschachtelte Daten wieder auf einen Host (Zeitachsenbereich) übertragen können. Da es nicht effizient ist, möchten wir die Häufigkeit, mit der wir es tun, begrenzen. Jede registrierte Eigenschaft und ihre Animation können ein einzelnes Datenelement vertikal hosten. Der Wert der Daten wird durch die Inline- oder Blockansichtsposition eines Elements irgendwo tief in der Struktur bestimmt – zu diesem Teil kommen wir später.

(Siehe das oben eingebettete Schleifenbeispiel für ein klareres Bild des Datenflusses)

Die vier Daten, die wir hier erheben, sind:

--xfl-cpu-phase – Dies ist ein numerischer Wert von 0 bis 4, der anzeigt, welche Phase des CPU-Hacks gerade ausgeführt wird. (Ein einzelner „Frame“ des CPU-Hacks besteht aus 4 bis 5 CSS-Renderframes, eine Schleife der Phasen „tickt“ den CPU-Hack) Ich werde dies später in diesem Artikel genauer demonstrieren.

--xfl-raw-data – Hier wird die Höhe des SVG gehostet, wo immer sich das SVG in seinem Animationszyklus befindet. Unsere Rohdaten. Wie bereits erwähnt, ist dieser diskrete Schritt der SVG-Animation ein Sentinel-Wert, wenn dieser Wert kleiner als 35 ist. Wenn er größer als 34 ist, ist dieser diskrete Schritt der SVG-Animation unser 16-Bit-Wert 35, was dem entspricht, was der vorherige Sentinel angegeben hat.

--xfl-data-type – Dies ist der aktuellste Sentinel-Wert. Dieser Wert ändert sich nicht, bis der nächste Sentinel angetroffen wird. Es gibt eine CSS-Frame-Verzögerung von der Einstellung von --xfl-raw-data bis zur Einstellung dieses Werts.

--xfl-data-value – Dies ist der aktuelle Datenwert, nachdem 35 vom Rohwert abgezogen wurde, oder 0, wenn wir diesen Schritt der Sequenz noch nicht erreicht haben. Es gibt eine CSS-Frame-Verzögerung von der Einstellung von --xfl-data-type bis zur Einstellung dieses Werts.

Ich habe den SVG-Animation-Current-State-Reporter auch präventiv in einen Zustand verpackt, der nur über Funktionalität verfügt und das animierte SVG nur lädt, während der Prozess unvollständig ist. (also werden alle Interna aus dem Speicher entfernt und das umfangreiche animierte SVG wird aus dem Rendering entfernt, wenn wir fertig sind)

Die Keyframe-Werte reichen von einem Maximalwert für dieses Datenelement bis 0. Ich werde später erklären, warum diese rückwärts sind – suchen Sie nach dem Bild der Uno Reverse-Karten.

CPU-Exfiltrator

Als nächstes richten wir die Grundbausteine ​​für einen CPU-Hack ein

Das CPU-Hack-Boilerplate folgt lediglich einem Variablennamenmuster, um Erfassungs- und Hebeanimationen einzurichten.

Wenn wir eine Ganzzahl --xfl\1 haben, die wir horizontal (im Laufe der Zeit) durchlaufen möchten, registrieren wir sie und richten Erfassungs- und Hebeanimationen wie folgt ein:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

Schließen Sie dann die zyklische Zuweisung für das .cpu-exfiltrator-Element ab, in dem die beiden CPU-Animationen gehostet werden. Ich mache es vorerst nur für einen der Werte:

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

In Chrome werden sie nicht statisch durchlaufen (werden zum Anfangswert), es sei denn, beide Animationen werden gleichzeitig ausgeführt. Das ist ein FANTASTISCHER Nebeneffekt dessen, was wahrscheinlich eine Optimierung pausierter Animationen beim Festlegen numerischer Eigenschaften ist.

Da wir schließlich eine neue automatische Version des CPU-Hacks verwenden (Sie müssen nicht mit der Maus darüber fahren, um die Phasen zu durchlaufen, wie im ursprünglichen Hack), verknüpfen wir die Variable --xfl-cpu-phase vom vorherigen (hier auf dem übergeordneten Element gehostet, sodass wir Stilabfragen verwenden können, um darauf zu reagieren) und den Wiedergabestatus unserer Animationen steuern.

Wir geben auch --cpu-next-phase aus, das später wieder an die Spitze gehoben wird und den nächsten Wert für --xfl-cpu-phase anhand seiner Ansichtsposition und seines Zeitachsenbereichs festlegt.

Ich habe eine zusätzliche Phase hinzugefügt, um den CPU-Hack anzuhalten, bis die SVG-Animationsmessung erfolgreich im nächsten --xfl-data-type blockiert wurde

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

(So wie es jetzt ist, ist der Datentyp immer noch 0, so dass, sobald die nächste Phase angeschlossen ist, der CPU-Hack bereits eine Schleife durchläuft. Sobald wir einen Datentyp-Sentinel haben, wird er nicht in einer Schleife ausgeführt, bis wir ihn haben habe es absichtlich mit dem 0-Sentinel gelöscht)

Später werden wir auch die erwähnte Bedingung hinzufügen, um zu verhindern, dass CPU-Phase 1 startet, bis alle Daten vorhanden sind. Dadurch wird sichergestellt, dass wir den CPU-Hack zwischen der Sperrung des Datentyps (Sentinel) und der Sperrung des Datenwerts (Rohwert – 35) in seiner Erfassungsphase belassen wollen. Es ist also „bereit, bereit zu sein“, wie Abraham Hicks sagen würde.

Ich werde alle 32 Werte plus Prüfsumme und Länge registrieren, die die SVG-Animation voraussichtlich melden wird.

Da die Registrierung von --xfl\1 bis --xfl\32 ein großer Block ist und die CPU-Animationen ebenfalls nur Standardanimationen sind, werde ich alle diese an das Ende des Hack-Setups verschieben, damit sie in Zukunft ignoriert werden.

Automatischer CPU-Hack

Dadurch wird die nächste CPU-Phase mit dem Wert --xfl-cpu-phase verkabelt

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

Hier gibt es einige CSS-Grundbausteine, um das Element zu einem Scroll-Container zu machen und es vom Bildschirm zu entfernen. Der wichtige Teil ist:

view-timeline: --xfl-cpu-phase inline;

Das besagt, wo der rechte Rand dieses Pseudoelements in seinem 100 Pixel breiten übergeordneten Element liegt. Verknüpfen Sie es als „Fortschritt“ von links mit unserer Animation, die sich von 0 auf 4 bewegt ... 25 Pixel sind also zu 25 % vollständig. was 1 entspricht, wenn 25 % zwischen 0 und 4 liegen.

picture of two 'reverse' cards from Uno Bild stammt aus einer Google-Suche, die zu Twitter führt

TECHNISCH ist die Animation 4 zu 0 und TECHNISCH wird vom rechten Rand des Pseudos aus gemessen, während die Ansicht nach rechts verläuft. Das 25 Pixel breite Pseudo ist also 75 % von der rechten Seite seines 100 Pixel breiten Scroll-Elternteils entfernt und wird einem Wert von 1 zugeordnet, wenn 75 % zwischen 4 und 0 liegt.

Es ist einfacher zu verstehen, wenn Sie die umgekehrte Umkehrmathematik nicht kognitiv verarbeiten und einfach akzeptieren, dass das Endergebnis ein einfacher Fortschritt von 0 bis 4 ist, da der Maximalwert in der Animation 4 ist (wiederum ignorieren Sie, dass die Animation startet). um 4).

Schreiben wir auch den Bereitschaftszustand, der die CPU in Phase 0 hält, bis die Daten bereit sind. Der Hinweis befindet sich in Zeile 64 unserer Demos:

Daten bereit = Datentyp > 0 && raw-frame-data - 35 === data-value

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

Warte, === in CSS?

Diese sind jetzt ziemlich veraltet und ich würde sie heute anders machen, geschrieben, bevor „clamp()“ die Grundlinie war, aber ich öffne immer diesen alten Codepen, um gedankenlos numerische Komparatoren zu kopieren und einzufügen, wenn ich sie brauche. Es wäre ein guter Artikel, diese zu aktualisieren und zu erklären, aber in der Zwischenzeit geht es los: https://codepen.io/propjockey/pen/YzZMNaz

Lesen der SVG-Animation

Dies ist anfangs SEHR dem Abschnitt „CPU-Exfiltrator“ ähnlich, da es sich um die gleiche Technik handelt, bei der Daten von hier im DOM gemessen und nach oben dorthin verschoben werden, wo sie gehostet werden (Bereich).

Wir messen und melden die letzten drei Werte für das Basiselement, das wir ursprünglich eingerichtet haben.

Auf ::bevor wir das SVG rendern und --xfl-raw-data unter Verwendung der Blockansichtsposition festlegen, die das Maß für die Höhe des animierten SVG ist. (Denken Sie daran, dass wir die Breite auf 10 Pixel festlegen)

Auf ::after setzen wir --xfl-data-type inline (Sentinel-Werte 0 bis 34) und --xfl-data-value block (16-Bit-Werte).

Das übergeordnete Element muss breit genug sein, um das SVG darzustellen (mindestens 10 Pixel) und genaue Messungen für die Sentinel-Werte (0 bis 34) bereitzustellen.

Das übergeordnete Element muss außerdem groß genug sein, um 16-Bit-Werte messen zu können (35). Da wir im ersten Schritt einen Maximalwert von 100.000 festgelegt haben, verwenden wir diesen einfach, auch wenn er etwa 30 % größer ist als wir benötigen.

Und verschieben Sie es vom Bildschirm nach oben und links, damit keine Bildlaufleisten entstehen.

Deshalb

.svg-animation-current-state-reporter

erhält

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  // add 35 to all the values so we can use 0 to 34 for sentinels. 0 = CSS-side sentinel, 1-32 = data frames, 33 = length, 34 = checksum
  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return ($viewBoxXYWidth . ((string) $index) . '; ' . $viewBoxXYWidth . ((string) ($val + 35)));
  }, $data, range(1, $datalen)); // 1 up to 32 = indicator that next frame is the value(+35) for that index(1-based)

  // no matter how many are in the array, '33' indicates the next frame is data length, which is used in the checksum too
  array_unshift($frames, $viewBoxXYWidth . '33; ' . $viewBoxXYWidth . ((string) ($datalen + 35))); // + 35 b/c data
  // unshift so the length is (hopefully) the first value read and a sense of progress can be reported

  $fullsum = 0;

  for ($x = 0; $x <= ($datalen - 1); $x++) {
    // double the odd ones so there's some semblance of order accounted for
    // the odd ones with 0 based index is the even ones on the CSS side
    $fullsum += ($data[$x] + (($x & 1) * $data[$x]));
  }

  $checksum = floor($fullsum / 2048) + ($fullsum % 2048) + $datalen + 35; // + 35 because it's data

  // no matter how many are in the array, '34' indicates the next frame is checksum
  array_push($frames, $viewBoxXYWidth . '34; ' . $viewBoxXYWidth . $checksum);

  $actualNumItems = count($frames) * 2;

  $dur = $actualNumItems * 0.33; // total seconds

  $keytimeStep = 1 / ($actualNumItems); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $actualNumItems - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

und davor wird

@keyframes capture {
  0%, 100% {
    --xfl\1-captured: var(--xfl\1);
  }
}

@keyframes hoist {
  0%, 100% {
    --xfl\1-hoist: var(--xfl\1-captured, 0);
  }
}

und ::after gets

  --xfl\1: calc(
    var(--xfl\1-hoist, 0) + 1
  );

Im Wesentlichen ist das Speichermedium für diese Nachwerte hier die Ansichtsposition eines quadratischen 1-Pixel-Pseudos gegenüber seinem übergeordneten Scroll-Container. Wir subtrahieren 1 Pixel in den linken und oberen Berechnungen, da das Pseudo selbst 1x1 ist und wir möchten, dass es 0 meldet, wenn der entsprechende Wert 0 ist.

Das ist alles sehr ähnlich zu dem, was zuvor gemacht wurde.

Die Berechnung dieser Werte ist mit mehreren Komplexitäten verbunden, wie aus dem Hinweis hervorgeht:

  @container style(--xfl-cpu-phase: 4) {
    animation-play-state: paused, paused;
    --cpu-next-phase: calc(
      min(1, var(--xfl-data-type)) * 4
    );
  }

Der Schlüssel zum Verständnis der Lösung dieses Problems besteht darin, dass jeder Komparatorwert entweder auf 0 oder 1 gesetzt wird. 1, wenn er wahr ist, 0, wenn er falsch ist. Dann multiplizieren Sie es mit einem bestimmten Wert. Wenn es falsch ist, bleibt das Ergebnis 0, andernfalls wird es zu dem, was auch immer der Wert ist.

Ana Tudor geht hier ausführlich darauf ein, wie diese Idee funktioniert

Wenn wir diesen Vergleich dann zweimal durchführen, mit einem anderen oder entgegengesetzten Vergleich für den zweiten Wert, und sie addieren (wobei sichergestellt wird, dass höchstens einer der Komparatoren 1 ist), dann bedeutet die Addition von zwei von ihnen nur „sonst“. wenn".

Wenn nicht bereit *, verwenden Sie den alten Wert, sonst
Wenn es bereit ist *, verwenden Sie diesen neuen Wert

Auf diese Weise behalten wir den Sentinel-Wert über die Dauer des diskreten Schritts der SVG-Animation für den Wert bei, nachdem der Typ bereits gemeldet wurde.

Der CSS-Code, der es implementiert, beginnt hier in Zeile 191, direkt über dem großen Block von --xfl\...-Eigenschaftsregistrierungen, den wir unten platziert haben
@property --xfl\1 { syntax: ""; Anfangswert: 0; erbt: wahr; }
...
und es enthält zusätzliche Hinweise:

Festlegen spezifischer CSS--var-Werte (adressierte Zuweisungen)

Die Logik, die wir gerade angesprochen haben, ist genau das gleiche Konzept, das wir für alle --xfl\1, 2, 32 Werte verwenden.

<?php header('Content-type: image/svg+xml');

  $data = array(
    400,
    450,
    150,
    20,
    175
  );

  $datalen = count($data);

  $viewBoxXYWidth = '0 0 10 ';

  $frames = array_map(function ($val, $index) use ($viewBoxXYWidth) {
      return $viewBoxXYWidth . ((string) ($val));
  }, $data, range(1, $datalen));

  $dur = $datalen * 0.33; // total seconds

  $keytimeStep = 1 / ($datalen); // uniform portion per frame

  $keytimes = implode("; ", array_map(function ($index) use ($keytimeStep) {
      return ($index * $keytimeStep);
  }, range(0, $datalen - 1)));

  $values = implode("; ", $frames); 

  echo '<svg viewBox="0 0 10 100" preserveAspectRatio="xMinYMin meet" xmlns="http://www.w3.org/2000/svg">
    <animate attributename="viewBox" dur="' . $dur . 's" fill="freeze" begin="0.1s;" values="' . $values . '" keytimes="' . $keytimes . '" repeatcount="indefinite" calcmode="discrete"></animate>
  ';
?>

Sie lesen --xfl-set\1 so, als ob --xfl-data-type gleich 1 wäre, verwenden Sie --xfl-data-is-ready mit einem impliziten else 0

--xfl-data-is-ready wurde früher als Flag etabliert, das uns in Phase 0 hält, bis es Zeit ist, zu Phase 1 zu wechseln.

Das bedeutet, dass unsere Bedingung && Logik ist. Zum Bestehen müssen beide Flags 1 sein.

Dann lesen Sie weiter --xfl\1, als ob --xfl-set\1 --xfl-data-value (den aktuellen SVG-Animationswert) verwenden würde, andernfalls, wenn NICHT --xfl-set\1 verwenden würde -- xfl\1-hoist (der vorherige Wert, den der CPU-Hack für --xfl1 hielt)

Dies ist sehr repetitiv und beschreibt fast den gesamten Rest dieser Exfiltration.

Die letzten Schritte bestehen darin, grundlegende calc()- und mod()-Mathematiken auszuführen, um die Prüfsumme wie zuvor beschrieben zu erstellen, und dann die in der SVG-Animation eingebettete Prüfsumme zum CPU-Hack hinzuzufügen, damit wir wissen, wann die berechnete Prüfsumme === ist vollständig. Alles beim Alten.

Jetzt ist es also soweit. :)

Präsentation: Der CSS Animated SVG Exfiltration Hack

Da ich jedem einzelnen Teil dieses Hacks einen Wert pro Element zeigen wollte, ist die Präsentation dafür widerlich umfangreich. Über 2000 Zeilen HTML und über 400 Zeilen CSS. Außerdem verwende ich CSS-Bin-Bits, um jedes Register in Binärdateien usw. umzuwandeln.

(Klicken Sie unten rechts im Codepen-Frame auf „Neu ausführen“, um den Vorgang in Echtzeit zu sehen!)

Kein JavaScript!


Kontakt öffnen?

Wenn Sie das toll finden und mehr erfahren möchten, wenden Sie sich bitte an uns! Bei Fragen stehe ich jederzeit gerne zur Verfügung.

% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei DEV Blog % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei
% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei DEV Blog % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei % CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei

?@JaneOri.% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei

?@Jane0ri

Das obige ist der detaillierte Inhalt von% CSS: Abrufen und Herausfiltern von Teilen servergenerierter Daten, eingebettet in eine animierte SVG-Datei. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn