frontend: Zweiter Download-Button für PNG (neben SVG)
LibreOffice liest weder das Browser-Bild-Clipboard noch das SVG zuverlässig. Neben dem SVG-Download gibt es daher jetzt einen zweiten Button, der das Diagramm als PNG-Datei (werkbaum-diagramm.png, Raster) speichert — überall per "Bild einfügen" importierbar. Beide Download-Buttons tragen ein Format-Label (SVG/PNG). Tooltip in allen neun Sprachen; SPEC §9 ergänzt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8d35611f4c
commit
340c7e7195
+6
-5
@@ -142,11 +142,12 @@ Das Diagramm wird aus der Live-Geometrie in ein eigenständiges SVG (nur Formen
|
||||
geschrieben: `image/png` (das eigentliche Bild) und `text/html` mit
|
||||
eingebettetem PNG. Fällt der Bild-Clipboard ganz aus (fehlende
|
||||
`ClipboardItem`-Unterstützung), wird der **SVG-Quelltext** kopiert.
|
||||
- **Herunterladen** — als **SVG-Datei** (`werkbaum-diagramm.svg`, Vektor).
|
||||
Verlässlicher Weg für Programme, die das Browser-Bild-Clipboard nicht
|
||||
erkennen (z. B. LibreOffice Writer: Einfügen → Bild → Datei). Das
|
||||
Browser-Clipboard erlaubt nur `image/png`/Text als Bildtypen, kein SVG —
|
||||
daher der Datei-Weg für Vektor.
|
||||
- **Herunterladen** — als Datei, zwei Schaltflächen mit Format-Label:
|
||||
**SVG** (`werkbaum-diagramm.svg`, Vektor) und **PNG**
|
||||
(`werkbaum-diagramm.png`, Raster). Der Datei-Weg ist der verlässliche Weg
|
||||
für Programme, die das Browser-Bild-Clipboard nicht erkennen. Manche
|
||||
Programme lesen auch das SVG nicht (z. B. LibreOffice) — dafür gibt es die
|
||||
PNG-Datei, die überall per „Bild einfügen“ importierbar ist.
|
||||
- Übernommen werden Knotenfarben (Status §4), Größen-Badge, Tags und der
|
||||
Geister-Knoten; die Verbindungslinien werden je Gate neu gezogen
|
||||
(und = durchgezogen Tinte, oder = gestrichelt Grau) und treffen die Knoten
|
||||
|
||||
+37
-9
@@ -247,6 +247,8 @@
|
||||
.copybtn .ic-done{display:none}
|
||||
.copybtn.done .ic-copy{display:none}
|
||||
.copybtn.done .ic-done{display:block}
|
||||
.dlbtn{gap:3px}
|
||||
.dl-label{font-family:'IBM Plex Mono',monospace;font-size:.62rem;font-weight:600;letter-spacing:.02em}
|
||||
textarea{
|
||||
display:block;width:100%;min-height:0;
|
||||
border:0;outline:none;resize:none;
|
||||
@@ -572,8 +574,11 @@
|
||||
<svg class="ic-copy" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>
|
||||
<svg class="ic-done" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.1" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6L9 17l-5-5"/></svg>
|
||||
</button>
|
||||
<button type="button" class="copybtn" id="dlDiagram" data-i18n-title="downloadDiagramTooltip" data-i18n-aria="downloadDiagramTooltip" title="Diagramm als SVG-Datei herunterladen" aria-label="Diagramm als SVG-Datei herunterladen">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg>
|
||||
<button type="button" class="copybtn dlbtn" id="dlDiagram" data-i18n-title="downloadDiagramTooltip" data-i18n-aria="downloadDiagramTooltip" title="Diagramm als SVG-Datei herunterladen" aria-label="Diagramm als SVG-Datei herunterladen">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg><span class="dl-label">SVG</span>
|
||||
</button>
|
||||
<button type="button" class="copybtn dlbtn" id="dlDiagramPng" data-i18n-title="downloadPngTooltip" data-i18n-aria="downloadPngTooltip" title="Diagramm als PNG-Datei herunterladen" aria-label="Diagramm als PNG-Datei herunterladen">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v12M8 11l4 4 4-4M4 17v2a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-2"/></svg><span class="dl-label">PNG</span>
|
||||
</button>
|
||||
<div class="winbtns" aria-label="Diagramm">
|
||||
<button type="button" class="winbtn" data-state="a" data-i18n-title="minimize" title="minimieren">—</button>
|
||||
@@ -869,15 +874,23 @@ async function copyDiagramImage(){
|
||||
/* Als Datei speichern (SVG, Vektor). Verlässlicher Weg z. B. für LibreOffice
|
||||
Writer: Einfügen → Bild → die Datei; das Bild-Clipboard aus dem Browser
|
||||
erkennt LibreOffice nicht zuverlässig. */
|
||||
function downloadDiagramSvg(){
|
||||
const {svg} = diagramToSvg();
|
||||
const blob = new Blob([`<?xml version="1.0" encoding="UTF-8"?>\n` + svg], {type:'image/svg+xml'});
|
||||
function saveBlob(blob, filename){
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url; a.download = 'werkbaum-diagramm.svg';
|
||||
a.href = url; a.download = filename;
|
||||
document.body.appendChild(a); a.click(); a.remove();
|
||||
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||||
}
|
||||
function downloadDiagramSvg(){
|
||||
const {svg} = diagramToSvg();
|
||||
saveBlob(new Blob([`<?xml version="1.0" encoding="UTF-8"?>\n` + svg], {type:'image/svg+xml'}),
|
||||
'werkbaum-diagramm.svg');
|
||||
}
|
||||
async function downloadDiagramPng(){
|
||||
const {svg, W, H} = diagramToSvg();
|
||||
const png = await svgToPng(svg, W, H, 2);
|
||||
if(png && png.blob) saveBlob(png.blob, 'werkbaum-diagramm.png');
|
||||
}
|
||||
|
||||
/* Tab-Taste rückt ein statt den Fokus zu wechseln */
|
||||
src.addEventListener('keydown', e => {
|
||||
@@ -1044,11 +1057,17 @@ document.getElementById('copyDiagram').addEventListener('click', async () => {
|
||||
await copyDiagramImage();
|
||||
flashCopied(document.getElementById('copyDiagram'), 'copyDiagramTooltip');
|
||||
});
|
||||
function flashBtn(btn){ /* kurzer Petrol-Blitz als Rückmeldung, Tooltip bleibt */
|
||||
btn.classList.add('done');
|
||||
setTimeout(() => btn.classList.remove('done'), 1500);
|
||||
}
|
||||
document.getElementById('dlDiagram').addEventListener('click', () => {
|
||||
downloadDiagramSvg();
|
||||
const b = document.getElementById('dlDiagram'); /* kurzer Petrol-Blitz, Tooltip bleibt */
|
||||
b.classList.add('done');
|
||||
setTimeout(() => b.classList.remove('done'), 1500);
|
||||
flashBtn(document.getElementById('dlDiagram'));
|
||||
});
|
||||
document.getElementById('dlDiagramPng').addEventListener('click', async () => {
|
||||
await downloadDiagramPng();
|
||||
flashBtn(document.getElementById('dlDiagramPng'));
|
||||
});
|
||||
|
||||
/* ---------- Internationalisierung (DE/EN/ES/FR) ---------- */
|
||||
@@ -1063,6 +1082,7 @@ const I18N = {
|
||||
copy:"kopieren", copyDone:"kopiert ✓", copyTooltip:"Text in die Zwischenablage kopieren",
|
||||
copyDiagramTooltip:"Diagramm als PNG-Bild in die Zwischenablage kopieren",
|
||||
downloadDiagramTooltip:"Diagramm als SVG-Datei herunterladen (z. B. für LibreOffice: Einfügen → Bild)",
|
||||
downloadPngTooltip:"Diagramm als PNG-Datei herunterladen (Rasterbild, überall einfügbar)",
|
||||
minimize:"minimieren", normal:"normal", maximize:"maximieren",
|
||||
agenda:"Agenda", discarded:"verworfene",
|
||||
modeHorizontal:"Horizontal – Organigramm, Diagramm über dem Editor",
|
||||
@@ -1093,6 +1113,7 @@ const I18N = {
|
||||
copy:"copy", copyDone:"copied ✓", copyTooltip:"Copy text to clipboard",
|
||||
copyDiagramTooltip:"Copy diagram as a PNG image to the clipboard",
|
||||
downloadDiagramTooltip:"Download diagram as an SVG file (e.g. for LibreOffice: Insert → Image)",
|
||||
downloadPngTooltip:"Download diagram as a PNG file (raster image, insertable anywhere)",
|
||||
minimize:"minimize", normal:"normal", maximize:"maximize",
|
||||
agenda:"Legend", discarded:"discarded",
|
||||
modeHorizontal:"Horizontal – org chart, diagram above the editor",
|
||||
@@ -1123,6 +1144,7 @@ const I18N = {
|
||||
copy:"copiar", copyDone:"copiado ✓", copyTooltip:"Copiar el texto al portapapeles",
|
||||
copyDiagramTooltip:"Copiar el diagrama como imagen PNG al portapapeles",
|
||||
downloadDiagramTooltip:"Descargar el diagrama como archivo SVG (p. ej. para LibreOffice: Insertar → Imagen)",
|
||||
downloadPngTooltip:"Descargar el diagrama como archivo PNG (imagen de trama, insertable en cualquier lugar)",
|
||||
minimize:"minimizar", normal:"normal", maximize:"maximizar",
|
||||
agenda:"Leyenda", discarded:"descartados",
|
||||
modeHorizontal:"Horizontal – organigrama, diagrama sobre el editor",
|
||||
@@ -1153,6 +1175,7 @@ const I18N = {
|
||||
copy:"copier", copyDone:"copié ✓", copyTooltip:"Copier le texte dans le presse-papiers",
|
||||
copyDiagramTooltip:"Copier le diagramme comme image PNG dans le presse-papiers",
|
||||
downloadDiagramTooltip:"Télécharger le diagramme en fichier SVG (p. ex. pour LibreOffice : Insertion → Image)",
|
||||
downloadPngTooltip:"Télécharger le diagramme en fichier PNG (image matricielle, insérable partout)",
|
||||
minimize:"réduire", normal:"normal", maximize:"agrandir",
|
||||
agenda:"Légende", discarded:"abandonnés",
|
||||
modeHorizontal:"Horizontal – organigramme, diagramme au-dessus de l'éditeur",
|
||||
@@ -1183,6 +1206,7 @@ const I18N = {
|
||||
copy:"kopiuj", copyDone:"skopiowano ✓", copyTooltip:"Kopiuj tekst do schowka",
|
||||
copyDiagramTooltip:"Kopiuj diagram jako obraz PNG do schowka",
|
||||
downloadDiagramTooltip:"Pobierz diagram jako plik SVG (np. dla LibreOffice: Wstaw → Obraz)",
|
||||
downloadPngTooltip:"Pobierz diagram jako plik PNG (obraz rastrowy, wszędzie do wstawienia)",
|
||||
minimize:"minimalizuj", normal:"normalny", maximize:"maksymalizuj",
|
||||
agenda:"Legenda", discarded:"odrzucone",
|
||||
modeHorizontal:"Poziomo – schemat organizacyjny, diagram nad edytorem",
|
||||
@@ -1213,6 +1237,7 @@ const I18N = {
|
||||
copy:"копировать", copyDone:"скопировано ✓", copyTooltip:"Скопировать текст в буфер обмена",
|
||||
copyDiagramTooltip:"Скопировать диаграмму как изображение PNG в буфер обмена",
|
||||
downloadDiagramTooltip:"Скачать диаграмму как файл SVG (напр. для LibreOffice: Вставка → Изображение)",
|
||||
downloadPngTooltip:"Скачать диаграмму как файл PNG (растровое изображение, вставляется везде)",
|
||||
minimize:"свернуть", normal:"обычный", maximize:"развернуть",
|
||||
agenda:"Легенда", discarded:"отклонённые",
|
||||
modeHorizontal:"Горизонтально – оргсхема, диаграмма над редактором",
|
||||
@@ -1243,6 +1268,7 @@ const I18N = {
|
||||
copy:"कॉपी करें", copyDone:"कॉपी हो गया ✓", copyTooltip:"टेक्स्ट को क्लिपबोर्ड पर कॉपी करें",
|
||||
copyDiagramTooltip:"आरेख को PNG छवि के रूप में क्लिपबोर्ड पर कॉपी करें",
|
||||
downloadDiagramTooltip:"आरेख को SVG फ़ाइल के रूप में डाउनलोड करें (जैसे LibreOffice: सम्मिलित करें → छवि)",
|
||||
downloadPngTooltip:"आरेख को PNG फ़ाइल के रूप में डाउनलोड करें (रास्टर छवि, कहीं भी सम्मिलित करने योग्य)",
|
||||
minimize:"छोटा करें", normal:"सामान्य", maximize:"बड़ा करें",
|
||||
agenda:"लेजेंड", discarded:"अस्वीकृत",
|
||||
modeHorizontal:"क्षैतिज – संगठन-चार्ट, संपादक के ऊपर आरेख",
|
||||
@@ -1273,6 +1299,7 @@ const I18N = {
|
||||
copy:"复制", copyDone:"已复制 ✓", copyTooltip:"将文本复制到剪贴板",
|
||||
copyDiagramTooltip:"将图表作为 PNG 图片复制到剪贴板",
|
||||
downloadDiagramTooltip:"将图表下载为 SVG 文件(例如用于 LibreOffice:插入 → 图像)",
|
||||
downloadPngTooltip:"将图表下载为 PNG 文件(位图,可在任何地方插入)",
|
||||
minimize:"最小化", normal:"正常", maximize:"最大化",
|
||||
agenda:"图例", discarded:"已放弃",
|
||||
modeHorizontal:"横向——组织结构图,图表在编辑器上方",
|
||||
@@ -1303,6 +1330,7 @@ const I18N = {
|
||||
copy:"コピー", copyDone:"コピーしました ✓", copyTooltip:"テキストをクリップボードにコピー",
|
||||
copyDiagramTooltip:"ダイアグラムを PNG 画像としてクリップボードにコピー",
|
||||
downloadDiagramTooltip:"ダイアグラムを SVG ファイルとしてダウンロード(例:LibreOffice の 挿入 → 画像)",
|
||||
downloadPngTooltip:"ダイアグラムを PNG ファイルとしてダウンロード(ラスター画像、どこにでも挿入可能)",
|
||||
minimize:"最小化", normal:"標準", maximize:"最大化",
|
||||
agenda:"凡例", discarded:"破棄",
|
||||
modeHorizontal:"横 — 組織図、ダイアグラムはエディターの上",
|
||||
|
||||
Reference in New Issue
Block a user