index.html 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <!DOCTYPE html>
  2. <html lang="de">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Politische Spenden Visualisierung</title>
  7. <script src="https://unpkg.com/neovis.js@2.0.2"></script>
  8. <script src="https://cdn.tailwindcss.com"></script>
  9. <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
  10. <style>
  11. .range-slider {
  12. -webkit-appearance: none;
  13. width: 100%;
  14. height: 10px;
  15. border-radius: 5px;
  16. background: #d3d3d3;
  17. outline: none;
  18. }
  19. .range-slider::-webkit-slider-thumb {
  20. -webkit-appearance: none;
  21. appearance: none;
  22. width: 20px;
  23. height: 20px;
  24. border-radius: 50%;
  25. background: #4CAF50;
  26. cursor: pointer;
  27. }
  28. .multi-select {
  29. max-height: 200px;
  30. overflow-y: auto;
  31. }
  32. </style>
  33. </head>
  34. <body class="bg-gray-100">
  35. <!-- Explainer -->
  36. <div id="explainer" class="fixed inset-0 bg-white z-50 transform transition-transform duration-300 ease-in-out">
  37. <div class="max-w-4xl mx-auto p-8">
  38. <h1 class="text-3xl font-bold mb-6">Willkommen zur Parteispenden-Visualisierung</h1>
  39. <div class="space-y-6">
  40. <section>
  41. <h2 class="text-2xl font-semibold mb-3">Was ist Lobbyismus?</h2>
  42. <p class="text-gray-700">Die Anzahl der Lobbyisten in Berlin ist unbekannt. Schätzungen gehen von etwa 5.000 aus. Allein auf der Verbändeliste des Deutschen Bundestages sind 2300 Verbände registriert, die regelmäßig zu Anhörungen eingeladen werden. Sie beinhaltet die verschiedenen Branchenverbände wie den Verband der Chemischen Industrie VCI oder den Verband der Automobilindustrie VDA, die Spitzenverbände der Wirtschaft wie den Bundesverband der Deutschen Industrie BDI oder den Zentralverband des Deutschen Handwerks ZDH, Gewerkschaften wie die IG Metall oder Nichtregierungsorganisationen wie z.B. auch LobbyControl.</p>
  43. </section>
  44. <section>
  45. <h2 class="text-2xl font-semibold mb-3">Warum diese Visualisierung?</h2>
  46. <p class="text-gray-700">Diese Seite existiert, um Wählern bei ihrer Entscheidungsfindung zu helfen. Politische Parteien machen vor Wahlen oft viele Versprechen, die sie nicht immer einhalten. Durch die Visualisierung von Parteispenden wird transparent, welche Interessengruppen welche Parteien finanziell unterstützen.</p>
  47. </section>
  48. <section>
  49. <h2 class="text-2xl font-semibold mb-3">Was wird gezeigt?</h2>
  50. <p class="text-gray-700">Die Visualisierung zeigt Verbindungen zwischen Spendern und politischen Parteien. Die Größe der Kreise und die Dicke der Verbindungslinien repräsentieren die Höhe der Spenden. Alle Daten stammen aus dem <a class="font-bold" href="https://lobbypedia.de/wiki/Parteispenden-Datenbank">Parteispenden-Datenbank von lobbypedia.de</a></p>
  51. </section>
  52. <button onclick="closeExplainer()" class="mt-8 bg-blue-600 text-white px-6 py-2 rounded-md hover:bg-blue-700">
  53. Verstanden
  54. </button>
  55. <!-- TODO add Tutorial -->
  56. <!-- <button onclick="startTutorial()" class="w-full bg-green-600 text-white px-4 py-2 rounded-md hover:bg-green-700"> -->
  57. <!-- Tutorial starten -->
  58. <!-- </button> -->
  59. </div>
  60. </div>
  61. </div>
  62. <!-- Sidebar Toggle Button -->
  63. <button id="toggleSidebar" class="fixed top-4 left-4 z-50 bg-white p-2 rounded-lg shadow-lg">
  64. <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  65. <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h16m-7 6h7"/>
  66. </svg>
  67. </button>
  68. <!-- Sidebar -->
  69. <div id="sidebar"
  70. x-data
  71. class="fixed left-0 top-0 w-80 h-full bg-white shadow-lg transform transition-transform duration-300 ease-in-out z-40 overflow-y-auto">
  72. <div class="p-6">
  73. <h2 class="text-xl font-semibold mb-6">Filter</h2>
  74. <!-- Party Selection -->
  75. <div class="mb-6">
  76. <label class="block text-sm font-medium text-gray-700 mb-2">Parteien</label>
  77. <select id="partySelect" x-model="$store.filter.parties"
  78. multiple
  79. class="multi-select w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
  80. <!-- Populated dynamically -->
  81. </select>
  82. </div>
  83. <!-- Zeitraum Info -->
  84. <div id="zeitraum-info" class="hidden fixed bg-white p-4 rounded-lg shadow-lg w-64">
  85. <div class="flex justify-between items-center mb-2">
  86. <h3 class="font-semibold">Info</h3>
  87. <button class="text-gray-500 hover:text-gray-700" onclick="toggleZeitraumInfo()">
  88. ×
  89. </button>
  90. </div>
  91. <p>Spenden 2010-2023: Lobbypedia, später: eigene Recherche</p>
  92. </div>
  93. <!-- Year Range -->
  94. <div class="mb-6">
  95. <label class="block text-sm font-medium text-gray-700 mb-2">Zeitraum
  96. <button class="ml-1 text-gray-500 hover:text-gray-700" onclick="toggleZeitraumInfo()">
  97. </button>
  98. </label>
  99. <div class="flex items-center space-x-2">
  100. <input type="number"
  101. x-model="$store.filter.yearRange[0]"
  102. min="2010"
  103. max="2025"
  104. @change="$store.filter.updateYearRange($event.target.value, $store.filter.yearRange[1])"
  105. class="w-24 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
  106. <span>bis</span>
  107. <input type="number"
  108. x-model="$store.filter.yearRange[1]"
  109. min="2010"
  110. max="2025"
  111. @change="$store.filter.updateYearRange($store.filter.yearRange[0], $event.target.value)"
  112. class="w-24 rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
  113. </div>
  114. </div>
  115. <!-- Donor Type -->
  116. <div class="mb-6">
  117. <label class="block text-sm font-medium text-gray-700 mb-2">Spendertyp</label>
  118. <div class="flex rounded-md shadow-sm">
  119. <button @click="$store.filter.setDonorType('all')"
  120. :class="{'bg-blue-500 text-white': $store.filter.donorType === 'all', 'bg-gray-200': $store.filter.donorType !== 'all'}"
  121. class="flex-1 px-4 py-2 rounded-l">Alle</button>
  122. <button @click="$store.filter.setDonorType('person')"
  123. :class="{'bg-blue-500 text-white': $store.filter.donorType === 'person', 'bg-gray-200': $store.filter.donorType !== 'person'}"
  124. class="flex-1 px-4 py-2">Privat</button>
  125. <button @click="$store.filter.setDonorType('entity')"
  126. :class="{'bg-blue-500 text-white': $store.filter.donorType === 'entity', 'bg-gray-200': $store.filter.donorType !== 'entity'}"
  127. class="flex-1 px-4 py-2 rounded-r">Juristisch</button>
  128. </div>
  129. </div>
  130. <!-- Donor Names -->
  131. <div class="mb-6">
  132. <label class="block text-sm font-medium text-gray-700 mb-2">Geldgeber</label>
  133. <div class="space-y-2">
  134. <template x-for="(donor, index) in $store.filter.donors" :key="index">
  135. <div class="flex gap-2">
  136. <input type="text"
  137. x-model="$store.filter.donors[index]"
  138. class="w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500">
  139. <button @click="$store.filter.removeDonorField(index)"
  140. class="text-red-600 hover:text-red-800"
  141. x-show="$store.filter.donors.length > 1">
  142. ×
  143. </button>
  144. </div>
  145. </template>
  146. </div>
  147. <button @click="$store.filter.addDonorField()"
  148. class="mt-2 text-blue-600 hover:text-blue-800">
  149. + Weiteren Geldgeber hinzufügen
  150. </button>
  151. </div>
  152. <!-- Strict Mode -->
  153. <div class="mb-6">
  154. <label class="flex items-center">
  155. <input type="checkbox"
  156. x-model="$store.filter.strict"
  157. class="rounded border-gray-300 text-blue-600 shadow-sm focus:border-blue-500 focus:ring-blue-500">
  158. <span class="ml-2 text-sm text-gray-700">Strenge Suche (UND-Verknüpfung)</span>
  159. </label>
  160. </div>
  161. <!-- Donation Limit -->
  162. <div class="mb-6">
  163. <label class="block text-sm font-medium text-gray-700 mb-2">Anzahl der Spenden</label>
  164. <input type="range"
  165. x-model="$store.filter.limit"
  166. min="1"
  167. max="1000"
  168. step="5"
  169. class="range-slider w-full">
  170. <div class="text-sm text-gray-500 mt-1" x-text="$store.filter.limit + ' Spenden'"></div>
  171. </div>
  172. <button onclick="toggleExplainer()" class="mt-4 text-blue-600 hover:text-blue-800">
  173. Hilfe anzeigen
  174. </button>
  175. </div>
  176. </div>
  177. <!-- Tutorial Dialog -->
  178. <div id="tutorialDialog" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50">
  179. <div class="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 bg-white p-6 rounded-lg shadow-xl max-w-md w-full">
  180. <h3 id="tutorialTitle" class="text-xl font-bold mb-4"></h3>
  181. <p id="tutorialDescription" class="text-gray-700 mb-6"></p>
  182. <div class="flex justify-between">
  183. <button onclick="previousTutorialStep()" class="bg-gray-200 text-gray-700 px-4 py-2 rounded hover:bg-gray-300">
  184. Zurück
  185. </button>
  186. <button onclick="nextTutorialStep()" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
  187. Weiter
  188. </button>
  189. </div>
  190. </div>
  191. </div>
  192. <!-- Visualization Area -->
  193. <div class="flex-1 relative">
  194. <div id="viz" class="w-full h-screen"></div>
  195. <!-- Legend -->
  196. <div id="legend" class="hidden fixed bottom-4 right-4 bg-white p-4 rounded-lg shadow-lg">
  197. <h3 class="font-semibold mb-2">Legende</h3>
  198. <div class="space-y-2">
  199. <div class="flex items-center">
  200. <div class="w-4 h-4 rounded-full bg-orange-500 mr-2"></div>
  201. <span>Politische Parteien</span>
  202. </div>
  203. <div class="flex items-center">
  204. <div class="w-4 h-4 rounded-full bg-green-500 mr-2"></div>
  205. <span>Privatpersonen</span>
  206. </div>
  207. <div class="flex items-center">
  208. <div class="w-4 h-4 rounded-full bg-blue-500 mr-2"></div>
  209. <span>Juristische Personen</span>
  210. </div>
  211. </div>
  212. </div>
  213. <!-- Legend Toggle Button -->
  214. <button onclick="toggleLegend()" class="fixed bottom-4 right-4 p-2 rounded-full shadow-lg">
  215. </button>
  216. </div>
  217. <script type="text/javascript" src="app.js"></script>
  218. </body>
  219. </html>