<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Inkubator</title>
    <link>https://inkubator.koppatz.com/</link>
    <description>Inkubator</description>
    <atom:link href="https://inkubator.koppatz.com/tags/TextInFarbe/feed.xml" rel="self" type="application/rss+xml"/>
    
    <item>
      <title>Tschechow — Farben im Text</title>
      <link>https://inkubator.koppatz.com/extras/cosmoscop-tchechow/</link>
      <guid>https://inkubator.koppatz.com/extras/cosmoscop-tchechow/</guid>
      <pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[&lt;blockquote&gt;&lt;p&gt;In diesem Projekt, werden diverse farbliche Beschreibung aus einer
Auswahl von Büchern visualisiert. Mit dem Kunstprojekt teste ich auch
diverse Darstellungsmöglichkeiten.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;iframe src=&quot;https://inkubator.koppatz.com/extras/tschechow-langweilige-geschichte.html&quot; title=&quot;Farbe im Text&quot;&gt;&lt;/iframe&gt; 
&lt;p&gt;HINWEIS: Mit öffnen des »Frame in neuem Fenster« kann die volle Breite des Browser genutzt werden.&lt;/p&gt;]]></description>
    </item>
    
    <item>
      <title>Mark Twain — Cosma</title>
      <link>https://inkubator.koppatz.com/extras/cosmoscope/</link>
      <guid>https://inkubator.koppatz.com/extras/cosmoscope/</guid>
      <pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[&lt;blockquote&gt;&lt;p&gt;In diesem Projekt, werden diverse farbliche Beschreibung aus einer
Auswahl von Büchern visualisiert. Mit dem Kunstprojekt teste ich auch
diverse Darstellungsmöglichkeiten.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;iframe src=&quot;https://inkubator.koppatz.com/extras/cosmoscope.html&quot; title=&quot;description&quot;&gt;&lt;/iframe&gt; 
&lt;p&gt;HINWEIS: Mit öffnen des »Frame in neuem Fenster« kann die volle Breite des Browser genutzt werden.&lt;/p&gt;]]></description>
    </item>
    
    <item>
      <title>Mark Twain — Cytoscape</title>
      <link>https://inkubator.koppatz.com/extras/cytoscape/</link>
      <guid>https://inkubator.koppatz.com/extras/cytoscape/</guid>
      <pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate>
      <description><![CDATA[&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;In diesem Projekt, werden diverse farbliche Beschreibung aus einer
Auswahl von Büchern visualisiert. Mit dem Kunstprojekt teste ich auch
diverse Darstellungsmöglichkeiten.&lt;/code&gt;&lt;/pre&gt;
  &lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.28.1/cytoscape.min.js&quot;&gt;&lt;/script&gt;
  &lt;style&gt;
    *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

    :root {
      --bg: #ffffff;
      --bg2: #f5f5f3;
      --border: #d8d8d6;
      --text: #222;
      --text2: #666;
      --text3: #999;
      --accent: #ff6a6a;
      --info: #2277cc;
    }

    @media (prefers-color-scheme: dark) {
      :root {
        --bg: #1a1a18;
        --bg2: #242422;
        --border: #3a3a38;
        --text: #e8e8e4;
        --text2: #a0a09a;
        --text3: #66665e;
        --accent: #ff6a6a;
        --info: #66aaee;
      }
    }

    body {
      font-family: system-ui, -apple-system, sans-serif;
      font-size: 14px;
      background: var(--bg);
      color: var(--text);
      padding: 20px;
      max-width: 900px;
      margin: 0 auto;
    }

    h1 {
      font-size: 18px;
      font-weight: 500;
      margin-bottom: 4px;
    }

    .subtitle {
      font-size: 12px;
      color: var(--text3);
      margin-bottom: 14px;
    }

    /* Toolbar */
    #toolbar {
      display: flex;
      gap: 8px;
      align-items: center;
      margin-bottom: 8px;
      flex-wrap: wrap;
    }

    .search-wrap {
      position: relative;
      flex: 1;
      min-width: 160px;
    }

    #search-input {
      width: 100%;
      padding: 6px 10px;
      border: 1px solid var(--border);
      border-radius: 6px;
      font-size: 13px;
      background: var(--bg);
      color: var(--text);
      outline: none;
    }

    #search-input:focus {
      border-color: var(--info);
    }

    #search-results {
      position: absolute;
      top: calc(100% + 4px);
      left: 0;
      z-index: 100;
      background: var(--bg);
      border: 1px solid var(--border);
      border-radius: 6px;
      width: 100%;
      max-height: 200px;
      overflow-y: auto;
      display: none;
      box-shadow: 0 4px 12px rgba(0,0,0,0.12);
    }

    #search-results div {
      padding: 6px 10px;
      font-size: 12px;
      cursor: pointer;
      color: var(--text);
      border-bottom: 1px solid var(--border);
    }

    #search-results div:last-child { border-bottom: none; }
    #search-results div:hover { background: var(--bg2); }

    .btn {
      padding: 6px 12px;
      border: 1px solid var(--border);
      border-radius: 6px;
      font-size: 12px;
      background: var(--bg2);
      color: var(--text);
      cursor: pointer;
      white-space: nowrap;
    }

    .btn:hover { border-color: var(--text2); }
    .btn.active { border-color: var(--info); color: var(--info); }

    /* Graph */
    #cy {
      width: 100%;
      height: 480px;
      border: 1px solid var(--border);
      border-radius: 8px;
      background: var(--bg2);
    }

    /* Hint */
    #drag-hint {
      font-size: 11px;
      color: var(--text3);
      margin: 5px 0;
    }

    /* Panel */
    #panel {
      margin-top: 8px;
      padding: 10px 14px;
      border: 1px solid var(--border);
      border-radius: 8px;
      background: var(--bg2);
      font-size: 13px;
      color: var(--text2);
      line-height: 1.6;
      min-height: 52px;
    }

    #panel strong { color: var(--text); }
    #panel p + p { margin-top: 4px; }

    /* Legende */
    #legend {
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
      margin-top: 10px;
      font-size: 11px;
      color: var(--text2);
    }

    .legend-item {
      display: flex;
      align-items: center;
      gap: 5px;
    }

    .legend-dot {
      width: 10px;
      height: 10px;
      border-radius: 50%;
      flex-shrink: 0;
    }

    /* Kommentar-Bereich */
    #hints {
      margin-top: 14px;
      padding: 10px 14px;
      border-left: 3px solid var(--border);
      font-size: 12px;
      color: var(--text3);
      line-height: 1.7;
    }

    #hints strong { color: var(--text2); }
    #hints code {
      background: var(--bg);
      border: 1px solid var(--border);
      border-radius: 3px;
      padding: 1px 5px;
      font-family: monospace;
      font-size: 11px;
    }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;

  &lt;h1&gt;Mark-Twain-Buch — Farben im Text&lt;/h1&gt;
  &lt;p class=&quot;subtitle&quot;&gt;Cosma-Graph, neu gerendert mit Cytoscape.js · Experimentelle Version&lt;/p&gt;

  &lt;div id=&quot;toolbar&quot;&gt;
    &lt;div class=&quot;search-wrap&quot;&gt;
      &lt;input id=&quot;search-input&quot; type=&quot;search&quot; placeholder=&quot;Knoten suchen…&quot; autocomplete=&quot;off&quot;&gt;
      &lt;div id=&quot;search-results&quot;&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;button class=&quot;btn&quot; id=&quot;btn-drag&quot; onclick=&quot;toggleDrag()&quot;&gt;Drag: Netz&lt;/button&gt;
    &lt;button class=&quot;btn&quot; id=&quot;btn-reset&quot; onclick=&quot;resetView()&quot;&gt;Zurücksetzen&lt;/button&gt;
    &lt;button class=&quot;btn&quot; onclick=&quot;cy.fit()&quot;&gt;Einpassen&lt;/button&gt;
    &lt;button class=&quot;btn&quot; onclick=&quot;rerunLayout()&quot;&gt;Layout neu&lt;/button&gt;
  &lt;/div&gt;

  &lt;div id=&quot;cy&quot;&gt;&lt;/div&gt;

  &lt;div id=&quot;drag-hint&quot;&gt;
    Klick → Details &amp;nbsp;·&amp;nbsp;
    Doppelklick → Fokus auf Nachbarn &amp;nbsp;·&amp;nbsp;
    Hintergrund-Klick → Auswahl aufheben &amp;nbsp;·&amp;nbsp;
    Scroll → Zoom
  &lt;/div&gt;

  &lt;div id=&quot;panel&quot;&gt;Knoten anklicken für Details und hinterlegten Text.&lt;/div&gt;

  &lt;div id=&quot;legend&quot;&gt;&lt;/div&gt;

  &lt;div id=&quot;hints&quot;&gt;
    &lt;strong&gt;Zum Experimentieren:&lt;/strong&gt;&lt;br&gt;
    · &lt;code&gt;typeColors&lt;/code&gt; — Farben je Typ ändern&lt;br&gt;
    · &lt;code&gt;nodeTexts&lt;/code&gt; — Texte je Knoten ergänzen&lt;br&gt;
    · &lt;code&gt;layout.name&lt;/code&gt; — z.B. &lt;code&gt;&#39;cose&#39;&lt;/code&gt;, &lt;code&gt;&#39;circle&#39;&lt;/code&gt;, &lt;code&gt;&#39;grid&#39;&lt;/code&gt;, &lt;code&gt;&#39;breadthfirst&#39;&lt;/code&gt;&lt;br&gt;
    · &lt;code&gt;nodeRepulsion&lt;/code&gt; — Abstoßungskraft der Knoten&lt;br&gt;
    · Drag-Modus &quot;Frei&quot; → nur der gezogene Knoten bewegt sich&lt;br&gt;
    · Drag-Modus &quot;Netz&quot; → Nachbarn folgen mit (50 % gedämpft)
  &lt;/div&gt;

  &lt;script&gt;
  // ─── Farben je Cosma-Typ ──────────────────────────────────────────────────
  const typeColors = {
    F4G1: &#39;#00CC00&#39;,   // Grün
    F4G2: &#39;#e0e000&#39;,   // Gelb
    F4G3: &#39;#a9a9a9&#39;,   // Grau
    F4B1: &#39;#4444FF&#39;,   // Blau
    F4B2: &#39;#785441&#39;,   // Braun
    F4R1: &#39;#FF4444&#39;,   // Rot
    F4S1: &#39;#555555&#39;,   // Schwarz
    F4W1: &#39;#999999&#39;,   // Weiß
    undefined: &#39;#858585&#39;
  };

  const typeLabels = {
    F4G1:&#39;Grün&#39;, F4G2:&#39;Gelb&#39;, F4G3:&#39;Grau&#39;,
    F4B1:&#39;Blau&#39;, F4B2:&#39;Braun&#39;, F4R1:&#39;Rot&#39;,
    F4S1:&#39;Schwarz&#39;, F4W1:&#39;Weiß&#39;, undefined:&#39;Undefiniert&#39;
  };

  // ─── Texte je Knoten (aus Cosma-Quelldaten) ───────────────────────────────
  const nodeTexts = {
    &#39;8449&#39;: &#39;Zentrale Übersichtsseite zum Mark-Twain-Buch.&#39;,
    &#39;70527149&#39;: &#39;Grün — Farbe im Text. Verbunden mit Seiten: 37, 50, 87, 94.&#39;,
    &#39;70526650&#39;: &#39;Braun — Farbe im Text. Verbunden mit Seiten: 06, 08, 09, 16.&#39;,
    &#39;70528749&#39;: &#39;Weiß — Farbe im Text. Verbunden mit Seiten: 13, 36, 52, 87.&#39;,
    &#39;70528349&#39;: &#39;Schwarz — Farbe im Text. Verbunden mit Seiten: 36, 37, 38, 87.&#39;,
    &#39;70528249&#39;: &#39;Rot — Farbe im Text. Verbunden mit Seite 37.&#39;,
    &#39;70527151&#39;: &#39;Grau — Farbe im Text. Verbunden mit Seite 56.&#39;,
    &#39;70527150&#39;: &#39;Gelb — Farbe im Text. Verbunden mit Seite 37.&#39;,
    &#39;70526649&#39;: &#39;Blau — Farbe im Text. Verbunden mit Seite 16.&#39;,
    &#39;8449834854&#39;: &#39;Seite 06: Tante Polly saß in ihrem braunen Schaukelstuhl, und der Brief lag in ihrem Schoß.&#39;,
    &#39;8449834856&#39;: &#39;Seite 08: Als Jupiter Dunlap sich ausgezogen hatte, sah der Lehrer bei ihm ein rundes braunes Mal an seinem linken Bein über dem Knie.&#39;,
    &#39;8449834857&#39;: &#39;Seite 09: Aber er ist auch irgendwie gutmütig und trägt lange braune Haare und keinen Bart.&#39;,
    &#39;8449834951&#39;: &#39;Seite 13: Aber schließlich entschloß er sich doch, erfreut zu sein — zuerst war sein Gesicht ganz weiß gewesen.&#39;,
    &#39;84498349544850&#39;: &#39;Seite 16: Er trug eine blaue Brille und einen ganz natürlich aussehenden langen, braunen Backenbart.&#39;,
    &#39;8449834954454849&#39;: &#39;Seite 16: Er trug eine blaue Brille und einen ganz natürlich aussehenden langen, braunen Backenbart.&#39;,
    &#39;84498351544849&#39;: &#39;Seite 36: Dann kam der Mond hinter den Bäumen heraufgezogen — schwarze Schatten und weiße Flecken huschten umher.&#39;,
    &#39;84498351544850&#39;: &#39;Seite 36: Dann kam der Mond hinter den Bäumen heraufgezogen — schwarze Schatten und weiße Flecken huschten umher.&#39;,
    &#39;84498351554849&#39;: &#39;Seite 37: Karierte Hosen, grün und schwarz — die feuerrote Weste aus Baumwollsamt, gelb gemustert.&#39;,
    &#39;84498351554850&#39;: &#39;Seite 37: Karierte Hosen, grün und schwarz — die feuerrote Weste aus Baumwollsamt, gelb gemustert.&#39;,
    &#39;84498351554851&#39;: &#39;Seite 37: Die feuerrote Weste aus Baumwollsamt, gelb gemustert.&#39;,
    &#39;84498351554852&#39;: &#39;Seite 37: Die feuerrote Weste aus Baumwollsamt, gelb gemustert.&#39;,
    &#39;8449835156&#39;: &#39;Seite 38: schwarz und steif wie ein Ofenrohr, hoch und hart und oben abgerundet wie ein Zuckerhut.&#39;,
    &#39;8449835348&#39;: &#39;Seite 50: Tom sah, daß der alte abgetragene, grüne Arbeitskittel verschwunden war.&#39;,
    &#39;8449835350&#39;: &#39;Seite 52: Wir sahen eine lange Schaufel über seiner Schulter und die weißen Flecken auf dem alten Arbeitskittel.&#39;,
    &#39;8449835354&#39;: &#39;Seite 56: Sie nahm seinen grauen Kopf an ihre Schulter und begann, ihn sanft zu streicheln.&#39;,
    &#39;84498356554849&#39;: &#39;Seite 87: Er kehrte mir seinen Rücken zu — ich erkannte ihn an seinem alten grünen Arbeitskittel.&#39;,
    &#39;84498356554850&#39;: &#39;Seite 87: grüner Arbeitskittel mit den weißen Flicken mitten auf dem Rücken.&#39;,
    &#39;84498356554851&#39;: &#39;Seite 87: Mitten in diesem Durcheinander sprang der alte Onkel Sila auf, weiß wie ein Bettlaken.&#39;,
    &#39;84498356554852&#39;: &#39;Seite 87: Er rief, daß er seine schwarze Seele von dem Verbrechen reinigen wolle.&#39;,
    &#39;8449835752&#39;: &#39;Seite 94: Nach Mitternacht ging er dann zu Onkel Silas\&#39; Haus, nahm dessen alten grünen Arbeitskittel vom Haken.&#39;
  };

  // ─── Rohdaten (aus Cosma data-Block) ──────────────────────────────────────
  const rawNodes = [
    {id:&#39;8449835752&#39;,label:&#39;Seite 94&#39;,types:[&#39;F4G1&#39;],size:4},
    {id:&#39;84498356554852&#39;,label:&#39;Seite 87&#39;,types:[&#39;F4S1&#39;],size:4},
    {id:&#39;84498356554851&#39;,label:&#39;Seite 87&#39;,types:[&#39;F4W1&#39;],size:4},
    {id:&#39;84498356554850&#39;,label:&#39;Seite 87&#39;,types:[&#39;F4W1&#39;],size:4},
    {id:&#39;84498356554849&#39;,label:&#39;Seite 87&#39;,types:[&#39;F4G1&#39;],size:4},
    {id:&#39;8449835354&#39;,label:&#39;Seite 56&#39;,types:[&#39;F4G3&#39;],size:4},
    {id:&#39;8449835350&#39;,label:&#39;Seite 52&#39;,types:[&#39;F4W1&#39;],size:4},
    {id:&#39;8449835348&#39;,label:&#39;Seite 50&#39;,types:[&#39;F4G1&#39;],size:4},
    {id:&#39;8449835156&#39;,label:&#39;Seite 38&#39;,types:[&#39;F4S1&#39;],size:4},
    {id:&#39;84498351554852&#39;,label:&#39;Seite 37&#39;,types:[&#39;F4G2&#39;],size:4},
    {id:&#39;84498351554851&#39;,label:&#39;Seite 37&#39;,types:[&#39;F4R1&#39;],size:4},
    {id:&#39;84498351554850&#39;,label:&#39;Seite 37&#39;,types:[&#39;F4S1&#39;],size:4},
    {id:&#39;84498351554849&#39;,label:&#39;Seite 37&#39;,types:[&#39;F4G1&#39;],size:4},
    {id:&#39;84498351544850&#39;,label:&#39;Seite 36&#39;,types:[&#39;F4W1&#39;],size:4},
    {id:&#39;84498351544849&#39;,label:&#39;Seite 36&#39;,types:[&#39;F4S1&#39;],size:4},
    {id:&#39;84498349544850&#39;,label:&#39;Seite 16&#39;,types:[&#39;F4B2&#39;],size:4},
    {id:&#39;8449834954454849&#39;,label:&#39;Seite 16&#39;,types:[&#39;F4B1&#39;],size:4},
    {id:&#39;8449834951&#39;,label:&#39;Seite 13&#39;,types:[&#39;F4W1&#39;],size:4},
    {id:&#39;8449834857&#39;,label:&#39;Seite 09&#39;,types:[&#39;F4B2&#39;],size:4},
    {id:&#39;8449834856&#39;,label:&#39;Seite 08&#39;,types:[&#39;F4B2&#39;],size:4},
    {id:&#39;8449834854&#39;,label:&#39;Seite 06&#39;,types:[&#39;F4B2&#39;],size:4},
    {id:&#39;8449&#39;,label:&#39;Mark-Twain&#39;,types:[&#39;undefined&#39;],size:18},
    {id:&#39;70528749&#39;,label:&#39;Weiß&#39;,types:[&#39;F4W1&#39;],size:14},
    {id:&#39;70528349&#39;,label:&#39;Schwarz&#39;,types:[&#39;F4S1&#39;],size:12},
    {id:&#39;70528249&#39;,label:&#39;Rot&#39;,types:[&#39;F4R1&#39;],size:6},
    {id:&#39;70527151&#39;,label:&#39;Grau&#39;,types:[&#39;F4G3&#39;],size:6},
    {id:&#39;70527150&#39;,label:&#39;Gelb&#39;,types:[&#39;F4G2&#39;],size:6},
    {id:&#39;70527149&#39;,label:&#39;Grün&#39;,types:[&#39;F4G1&#39;],size:12},
    {id:&#39;70526650&#39;,label:&#39;Braun&#39;,types:[&#39;F4B2&#39;],size:12},
    {id:&#39;70526649&#39;,label:&#39;Blau&#39;,types:[&#39;F4B1&#39;],size:6}
  ];

  const rawLinks = [
    {s:&#39;8449835752&#39;,t:&#39;70527149&#39;},{s:&#39;84498356554852&#39;,t:&#39;70528349&#39;},
    {s:&#39;84498356554851&#39;,t:&#39;70528749&#39;},{s:&#39;84498356554850&#39;,t:&#39;70528749&#39;},
    {s:&#39;84498356554849&#39;,t:&#39;70527149&#39;},{s:&#39;8449835354&#39;,t:&#39;70527151&#39;},
    {s:&#39;8449835350&#39;,t:&#39;70528749&#39;},{s:&#39;8449835348&#39;,t:&#39;70527149&#39;},
    {s:&#39;8449835156&#39;,t:&#39;70528349&#39;},{s:&#39;84498351554852&#39;,t:&#39;70527150&#39;},
    {s:&#39;84498351554851&#39;,t:&#39;70528249&#39;},{s:&#39;84498351554850&#39;,t:&#39;70528349&#39;},
    {s:&#39;84498351554849&#39;,t:&#39;70527149&#39;},{s:&#39;84498351544850&#39;,t:&#39;70528749&#39;},
    {s:&#39;84498351544849&#39;,t:&#39;70528349&#39;},{s:&#39;84498349544850&#39;,t:&#39;70526650&#39;},
    {s:&#39;8449834954454849&#39;,t:&#39;70526649&#39;},{s:&#39;8449834951&#39;,t:&#39;70528749&#39;},
    {s:&#39;8449834857&#39;,t:&#39;70526650&#39;},{s:&#39;8449834856&#39;,t:&#39;70526650&#39;},
    {s:&#39;8449834854&#39;,t:&#39;70526650&#39;},{s:&#39;70528749&#39;,t:&#39;8449&#39;},
    {s:&#39;70528349&#39;,t:&#39;8449&#39;},{s:&#39;70528249&#39;,t:&#39;8449&#39;},
    {s:&#39;70527151&#39;,t:&#39;8449&#39;},{s:&#39;70527150&#39;,t:&#39;8449&#39;},
    {s:&#39;70527149&#39;,t:&#39;8449&#39;},{s:&#39;70526650&#39;,t:&#39;8449&#39;},
    {s:&#39;70526649&#39;,t:&#39;8449&#39;}
  ];

  // ─── Legende aufbauen ─────────────────────────────────────────────────────
  const usedTypes = [...new Set(rawNodes.map(n =&gt; n.types[0]))];
  const legendEl = document.getElementById(&#39;legend&#39;);
  usedTypes.forEach(t =&gt; {
    const item = document.createElement(&#39;div&#39;);
    item.className = &#39;legend-item&#39;;
    item.innerHTML = `&lt;span class=&quot;legend-dot&quot; style=&quot;background:${typeColors[t]}&quot;&gt;&lt;/span&gt;${typeLabels[t] || t}`;
    legendEl.appendChild(item);
  });

  // ─── Cytoscape initialisieren ─────────────────────────────────────────────
  let dragMode = &#39;network&#39;;

  const cy = cytoscape({
    container: document.getElementById(&#39;cy&#39;),
    elements: [
      ...rawNodes.map(n =&gt; ({
        data: {
          id: n.id,
          label: n.label,
          color: typeColors[n.types[0]] || &#39;#888&#39;,
          size: Math.max(n.size * 2.4, 14),
          type: n.types[0]
        }
      })),
      ...rawLinks.map((l, i) =&gt; ({
        data: { id: &#39;e&#39; + i, source: l.s, target: l.t }
      }))
    ],
    style: [
      {
        selector: &#39;node&#39;,
        style: {
          &#39;background-color&#39;: &#39;data(color)&#39;,
          &#39;width&#39;: &#39;data(size)&#39;,
          &#39;height&#39;: &#39;data(size)&#39;,
          &#39;label&#39;: &#39;data(label)&#39;,
          &#39;font-size&#39;: &#39;9px&#39;,
          &#39;color&#39;: &#39;#333&#39;,
          &#39;text-valign&#39;: &#39;bottom&#39;,
          &#39;text-margin-y&#39;: &#39;3px&#39;,
          &#39;text-outline-width&#39;: 2,
          &#39;text-outline-color&#39;: &#39;#fff&#39;,
          &#39;border-width&#39;: 1.5,
          &#39;border-color&#39;: &#39;#fff&#39;
        }
      },
      {
        selector: &#39;node:selected&#39;,
        style: { &#39;border-width&#39;: 3, &#39;border-color&#39;: &#39;#ff6a6a&#39; }
      },
      {
        selector: &#39;node.found&#39;,
        style: { &#39;border-width&#39;: 3, &#39;border-color&#39;: &#39;#ff6a6a&#39; }
      },
      {
        selector: &#39;node.faded&#39;,
        style: { &#39;opacity&#39;: 0.15 }
      },
      {
        selector: &#39;edge&#39;,
        style: {
          &#39;width&#39;: 0.8,
          &#39;line-color&#39;: &#39;#ccc&#39;,
          &#39;target-arrow-color&#39;: &#39;#ccc&#39;,
          &#39;target-arrow-shape&#39;: &#39;triangle&#39;,
          &#39;curve-style&#39;: &#39;bezier&#39;,
          &#39;arrow-scale&#39;: 0.7,
          &#39;opacity&#39;: 0.5
        }
      },
      {
        selector: &#39;edge.highlighted&#39;,
        style: {
          &#39;line-color&#39;: &#39;#ff6a6a&#39;,
          &#39;target-arrow-color&#39;: &#39;#ff6a6a&#39;,
          &#39;opacity&#39;: 1,
          &#39;width&#39;: 1.5
        }
      },
      {
        selector: &#39;edge.faded&#39;,
        style: { &#39;opacity&#39;: 0.04 }
      }
    ],
    layout: {
      name: &#39;cose&#39;,
      animate: true,
      animationDuration: 700,
      nodeRepulsion: 10000,
      idealEdgeLength: 70,
      gravity: 0.5,
      numIter: 600,
      fit: true,
      padding: 24
    }
  });

  // ─── Layout neu berechnen ─────────────────────────────────────────────────
  function rerunLayout() {
    cy.layout({
      name: &#39;cose&#39;,
      animate: true,
      animationDuration: 700,
      nodeRepulsion: 10000,
      idealEdgeLength: 70,
      gravity: 0.5,
      numIter: 600,
      fit: true,
      padding: 24
    }).run();
  }

  // ─── Drag-Modus ───────────────────────────────────────────────────────────
  function toggleDrag() {
    dragMode = dragMode === &#39;network&#39; ? &#39;free&#39; : &#39;network&#39;;
    const btn = document.getElementById(&#39;btn-drag&#39;);
    btn.textContent = &#39;Drag: &#39; + (dragMode === &#39;network&#39; ? &#39;Netz&#39; : &#39;Frei&#39;);
    btn.classList.toggle(&#39;active&#39;, dragMode === &#39;free&#39;);
  }

  cy.on(&#39;grab&#39;, &#39;node&#39;, function(e) {
    if (dragMode !== &#39;network&#39;) return;
    e.target.scratch(&#39;_dn&#39;, e.target.neighborhood(&#39;node&#39;).map(n =&gt; ({
      node: n,
      ox: n.position(&#39;x&#39;), oy: n.position(&#39;y&#39;),
      sx: e.target.position(&#39;x&#39;), sy: e.target.position(&#39;y&#39;)
    })));
  });

  cy.on(&#39;drag&#39;, &#39;node&#39;, function(e) {
    if (dragMode !== &#39;network&#39;) return;
    const neighbors = e.target.scratch(&#39;_dn&#39;);
    if (!neighbors || !neighbors.length) return;
    const dx = e.target.position(&#39;x&#39;) - neighbors[0].sx;
    const dy = e.target.position(&#39;y&#39;) - neighbors[0].sy;
    neighbors.forEach(({ node, ox, oy }) =&gt; {
      node.position({ x: ox + dx * 0.5, y: oy + dy * 0.5 });
    });
  });

  // ─── Klick: Details anzeigen ──────────────────────────────────────────────
  function showNodePanel(node) {
    const id = node.id();
    const text = nodeTexts[id] || &#39;(kein hinterlegter Text)&#39;;
    const deg = node.connectedEdges().length;
    document.getElementById(&#39;panel&#39;).innerHTML =
      `&lt;p&gt;&lt;strong&gt;${node.data(&#39;label&#39;)}&lt;/strong&gt; &amp;nbsp;·&amp;nbsp; ` +
      `Typ: ${node.data(&#39;type&#39;)} &amp;nbsp;·&amp;nbsp; ` +
      `${deg} Verbindung${deg !== 1 ? &#39;en&#39; : &#39;&#39;}&lt;/p&gt;` +
      `&lt;p style=&quot;margin-top:4px&quot;&gt;${text}&lt;/p&gt;`;
  }

  cy.on(&#39;tap&#39;, &#39;node&#39;, function(e) {
    const node = e.target;
    showNodePanel(node);
    cy.elements().removeClass(&#39;faded highlighted&#39;);
    const hood = node.closedNeighborhood();
    cy.elements().not(hood).addClass(&#39;faded&#39;);
    hood.edges().addClass(&#39;highlighted&#39;);
  });

  // ─── Doppelklick: Fokus-Modus ─────────────────────────────────────────────
  cy.on(&#39;dblclick&#39;, &#39;node&#39;, function(e) {
    const node = e.target;
    const hood = node.closedNeighborhood();
    cy.elements().not(hood).style(&#39;display&#39;, &#39;none&#39;);
    hood.style(&#39;display&#39;, &#39;element&#39;);
    cy.fit(hood, 40);
    document.getElementById(&#39;btn-reset&#39;).classList.add(&#39;active&#39;);
  });

  // ─── Hintergrund-Klick: Auswahl aufheben ──────────────────────────────────
  cy.on(&#39;tap&#39;, function(e) {
    if (e.target !== cy) return;
    cy.elements().removeClass(&#39;faded highlighted&#39;);
    document.getElementById(&#39;panel&#39;).innerHTML =
      &#39;Knoten anklicken für Details und hinterlegten Text.&#39;;
  });

  // ─── Reset ────────────────────────────────────────────────────────────────
  function resetView() {
    cy.elements().style(&#39;display&#39;, &#39;element&#39;);
    cy.elements().removeClass(&#39;faded highlighted found&#39;);
    cy.fit();
    document.getElementById(&#39;btn-reset&#39;).classList.remove(&#39;active&#39;);
    document.getElementById(&#39;panel&#39;).innerHTML =
      &#39;Knoten anklicken für Details und hinterlegten Text.&#39;;
  }

  // ─── Suche ────────────────────────────────────────────────────────────────
  const searchInput = document.getElementById(&#39;search-input&#39;);
  const searchResults = document.getElementById(&#39;search-results&#39;);

  searchInput.addEventListener(&#39;input&#39;, function() {
    const q = this.value.trim().toLowerCase();
    searchResults.innerHTML = &#39;&#39;;
    cy.elements().removeClass(&#39;found&#39;);
    if (!q) { searchResults.style.display = &#39;none&#39;; return; }
    const hits = rawNodes.filter(n =&gt;
      n.label.toLowerCase().includes(q) ||
      (nodeTexts[n.id] || &#39;&#39;).toLowerCase().includes(q)
    ).slice(0, 8);
    if (!hits.length) { searchResults.style.display = &#39;none&#39;; return; }
    hits.forEach(n =&gt; {
      const d = document.createElement(&#39;div&#39;);
      const preview = nodeTexts[n.id] ? &#39; — &#39; + nodeTexts[n.id].slice(0, 50) + &#39;…&#39; : &#39;&#39;;
      d.textContent = n.label + preview;
      d.onclick = () =&gt; selectNode(n.id);
      searchResults.appendChild(d);
    });
    searchResults.style.display = &#39;block&#39;;
  });

  document.addEventListener(&#39;click&#39;, e =&gt; {
    if (!e.target.closest(&#39;.search-wrap&#39;)) searchResults.style.display = &#39;none&#39;;
  });

  function selectNode(id) {
    searchResults.style.display = &#39;none&#39;;
    searchInput.value = &#39;&#39;;
    const node = cy.getElementById(id);
    cy.elements().removeClass(&#39;faded highlighted found&#39;);
    node.addClass(&#39;found&#39;);
    const hood = node.closedNeighborhood();
    cy.elements().not(hood).addClass(&#39;faded&#39;);
    hood.edges().addClass(&#39;highlighted&#39;);
    cy.animate({ center: { eles: node }, zoom: 2.5 }, { duration: 400 });
    showNodePanel(node);
  }
  &lt;/script&gt;
]]></description>
    </item>
    
  </channel>
</rss>