import { applyEffect, getAvailableEffects } from './effects.js'; const tagDisplayNames = { japanese: "日本語", english: "英語", kanji: "漢字対応", business: "ビジネス", fancy: "装飾的", playful: "遊び心", display: "ディスプレイ", handwritten: "手書き", retro: "レトロ", calm: "落ち着いた", cute: "かわいい", script: "筆記体", bold: "太字", horror: "ホラー", comic: "コミック" }; const fontTags = [ // 日本語フォント { name: "Aoboshi One", tags: ["japanese"] }, { name: "BIZ UDGothic", tags: ["japanese", "kanji", "business"] }, { name: "BIZ UDMincho", tags: ["japanese", "kanji", "business"] }, { name: "BIZ UDPGothic", tags: ["japanese", "kanji", "business"] }, { name: "BIZ UDPMincho", tags: ["japanese", "kanji", "business"] }, { name: "Cherry Bomb One", tags: ["japanese", "cute"] }, { name: "Chokokutai", tags: ["japanese", "fancy"] }, { name: "Darumadrop One", tags: ["japanese", "playful"] }, { name: "Dela Gothic One", tags: ["japanese", "kanji", "display"] }, { name: "DotGothic16", tags: ["japanese", "kanji", "retro"] }, { name: "Hachi Maru Pop", tags: ["japanese", "kanji", "cute"] }, { name: "Hina Mincho", tags: ["japanese", "kanji", "fancy"] }, { name: "IBM Plex Sans JP", tags: ["japanese", "kanji", "business"] }, { name: "Kaisei Decol", tags: ["japanese", "kanji", "fancy"] }, { name: "Kaisei HarunoUmi", tags: ["japanese", "kanji", "fancy"] }, { name: "Kaisei Opti", tags: ["japanese", "kanji", "business"] }, { name: "Kaisei Tokumin", tags: ["japanese", "kanji", "business"] }, { name: "Kiwi Maru", tags: ["japanese", "kanji", "cute"] }, { name: "Klee One", tags: ["japanese", "kanji", "handwritten"] }, { name: "Kosugi", tags: ["japanese", "kanji", "business"] }, { name: "Kosugi Maru", tags: ["japanese", "kanji", "calm"] }, { name: "M PLUS 1", tags: ["japanese", "kanji", "business"] }, { name: "M PLUS 1 Code", tags: ["japanese", "kanji", "display"] }, { name: "M PLUS 1p", tags: ["japanese", "kanji", "business"] }, { name: "M PLUS 2", tags: ["japanese", "kanji", "business"] }, { name: "M PLUS Rounded 1c", tags: ["japanese", "kanji", "calm"] }, { name: "Mochiy Pop One", tags: ["japanese", "kanji", "playful"] }, { name: "Mochiy Pop P One", tags: ["japanese", "kanji", "playful"] }, { name: "Monomaniac One", tags: ["japanese", "display"] }, { name: "Murecho", tags: ["japanese", "business"] }, { name: "New Tegomin", tags: ["japanese", "kanji", "fancy"] }, { name: "Noto Sans JP", tags: ["japanese", "kanji", "business"] }, { name: "Noto Serif JP", tags: ["japanese", "kanji", "business"] }, { name: "Palette Mosaic", tags: ["japanese", "display"] }, { name: "Potta One", tags: ["japanese", "kanji", "playful"] }, { name: "Rampart One", tags: ["japanese", "kanji", "display"] }, { name: "Reggae One", tags: ["japanese", "kanji", "display"] }, { name: "Rock 3D", tags: ["japanese", "display"] }, { name: "RocknRoll One", tags: ["japanese", "kanji", "playful"] }, { name: "Sawarabi Gothic", tags: ["japanese", "kanji", "business"] }, { name: "Sawarabi Mincho", tags: ["japanese", "kanji", "business"] }, { name: "Shippori Antique", tags: ["japanese", "kanji", "retro"] }, { name: "Shippori Antique B1", tags: ["japanese", "kanji", "retro"] }, { name: "Shippori Mincho", tags: ["japanese", "kanji", "business"] }, { name: "Shippori Mincho B1", tags: ["japanese", "kanji", "business"] }, { name: "Shizuru", tags: ["japanese", "display"] }, { name: "Slackside One", tags: ["japanese", "handwritten"] }, { name: "Stick", tags: ["japanese", "kanji", "display"] }, { name: "Train One", tags: ["japanese", "kanji", "display"] }, { name: "Tsukimi Rounded", tags: ["japanese", "calm"] }, { name: "Yomogi", tags: ["japanese", "kanji", "handwritten"] }, { name: "Yuji Boku", tags: ["japanese", "kanji", "fancy"] }, { name: "Yuji Hentaigana Akari", tags: ["japanese", "fancy"] }, { name: "Yuji Hentaigana Akebono", tags: ["japanese", "fancy"] }, { name: "Yuji Mai", tags: ["japanese", "kanji", "fancy"] }, { name: "Yuji Syuku", tags: ["japanese", "kanji", "fancy"] }, { name: "Yusei Magic", tags: ["japanese", "kanji", "playful"] }, { name: "Zen Antique", tags: ["japanese", "kanji", "retro"] }, { name: "Zen Antique Soft", tags: ["japanese", "kanji", "retro"] }, { name: "Zen Kaku Gothic Antique", tags: ["japanese", "kanji", "business"] }, { name: "Zen Kaku Gothic New", tags: ["japanese", "kanji", "business"] }, { name: "Zen Kurenaido", tags: ["japanese", "calm"] }, { name: "Zen Maru Gothic", tags: ["japanese", "calm"] }, { name: "Zen Old Mincho", tags: ["japanese", "kanji", "retro"] }, // 英語フォント - ビジネス/フォーマル { name: "Montserrat", tags: ["english", "business"] }, { name: "Playfair Display", tags: ["english", "business", "fancy"] }, { name: "Roboto", tags: ["english", "business"] }, { name: "Lato", tags: ["english", "business"] }, { name: "Poppins", tags: ["english", "business", "calm"] }, { name: "Quicksand", tags: ["english", "calm"] }, { name: "Raleway", tags: ["english", "calm"] }, // デコラティブ/ファンシー { name: "Pacifico", tags: ["english", "fancy", "script"] }, { name: "Great Vibes", tags: ["english", "fancy", "script"] }, { name: "Lobster", tags: ["english", "fancy"] }, { name: "Dancing Script", tags: ["english", "fancy", "script"] }, { name: "Satisfy", tags: ["english", "fancy", "script"] }, { name: "Courgette", tags: ["english", "fancy", "script"] }, { name: "Kaushan Script", tags: ["english", "fancy", "script"] }, { name: "Sacramento", tags: ["english", "fancy", "script", "handwritten"] }, // かわいい/プレイフル { name: "Bubblegum Sans", tags: ["english", "display", "cute", "playful"] }, { name: "Comic Neue", tags: ["english", "comic", "cute", "handwritten"] }, { name: "Sniglet", tags: ["english", "display", "cute", "playful"] }, { name: "Patrick Hand", tags: ["english", "handwritten", "playful"] }, { name: "Indie Flower", tags: ["english", "handwritten", "playful"] }, // 手書き/筆記体 { name: "Caveat", tags: ["english", "handwritten", "script"] }, { name: "Shadows Into Light", tags: ["english", "handwritten"] }, { name: "Architects Daughter", tags: ["english", "handwritten"] }, { name: "Covered By Your Grace", tags: ["english", "handwritten"] }, { name: "Just Another Hand", tags: ["english", "handwritten"] }, // 太字/ディスプレイ { name: "Righteous", tags: ["english", "display"] }, { name: "Permanent Marker", tags: ["english", "display", "handwritten"] }, { name: "Press Start 2P", tags: ["english", "display", "retro"] }, { name: "Fredoka One", tags: ["english", "display", "playful"] }, { name: "Creepster", tags: ["english", "display", "horror"] }, { name: "Bangers", tags: ["english", "display", "comic"] }, { name: "Rubik Mono One", tags: ["english", "display", "bold"] }, { name: "Bungee", tags: ["english", "display", "bold"] }, { name: "Bungee Shade", tags: ["english", "display", "fancy"] }, { name: "Monoton", tags: ["english", "display", "retro"] }, { name: "Anton", tags: ["english", "display", "bold"] }, { name: "Bebas Neue", tags: ["english", "display", "bold"] }, { name: "Black Ops One", tags: ["english", "display", "bold"] }, { name: "Bowlby One SC", tags: ["english", "display", "bold"] } ]; // フォントの読み込みを管理する関数 async function loadGoogleFont(fontFamily) { // フォントファミリー名を正しく整形 const formattedFamily = fontFamily.replace(/ /g, '+'); // Google Fonts APIのURLを構築 const url = `https://fonts.googleapis.com/css2?family=${formattedFamily}&display=swap`; // 既存のリンクタグがあれば削除 const existingLink = document.querySelector(`link[href*="${formattedFamily}"]`); if (existingLink) { existingLink.remove(); } // 新しいリンクタグを追加 const link = document.createElement('link'); link.href = url; link.rel = 'stylesheet'; document.head.appendChild(link); // フォントの読み込みを待つ await new Promise((resolve, reject) => { link.onload = async () => { try { // フォントの読み込みを確認 await document.fonts.load(`16px "${fontFamily}"`); // 少し待機して確実にフォントを利用可能にする setTimeout(resolve, 100); } catch (error) { reject(error); } }; link.onerror = reject; }); } // テキストを画像に変換する関数を更新 async function textToImage(text, fontFamily, fontSize = '48px', effectType = 'simple') { console.debug(`テキスト描画開始: ${effectType}`, { text, fontFamily, fontSize }); try { await document.fonts.load(`${fontSize} "${fontFamily}"`); const fontSizeNum = parseInt(fontSize); const verticalText = document.getElementById('verticalText').checked; const verticalSpacing = document.getElementById('verticalSpacing').value; // エフェクトを適用 const imageUrl = await applyEffect(effectType, text, { font: fontFamily, fontSize: fontSizeNum, vertical: verticalText, verticalSpacing: verticalSpacing }); return imageUrl; } catch (error) { console.error('フォント描画エラー:', error); throw error; } } // デバウンス関数の実装 let renderTimeout = null; let isRendering = false; function debounceRender(callback, delay = 200) { if (renderTimeout) { clearTimeout(renderTimeout); } if (isRendering) { return; } renderTimeout = setTimeout(async () => { isRendering = true; try { await callback(); } finally { isRendering = false; } }, delay); } // イベントリスナーの設定を更新 document.addEventListener('DOMContentLoaded', async () => { const fontSelect = document.getElementById('googleFontInput'); const fontTagFilter = document.getElementById('fontTagFilter'); const textInput = document.getElementById('textInput'); const fontSizeInput = document.getElementById('fontSize'); const verticalTextInput = document.getElementById('verticalText'); const effectGrid = document.querySelector('.effect-grid'); const noFontsMessage = document.getElementById('noFontsMessage'); // 利用可能なタグを収集し、使用頻度をカウント function getTagsWithCount() { const tagCount = new Map(); fontTags.forEach(font => { font.tags.forEach(tag => { tagCount.set(tag, (tagCount.get(tag) || 0) + 1); }); }); return tagCount; } // 言語関連のタグかどうかを判定 function isLanguageTag(tag) { return ['japanese', 'english', 'kanji'].includes(tag); } // フィルターボタンを動的に生成 function createFilterButtons() { const tagCount = getTagsWithCount(); fontTagFilter.innerHTML = ''; // タグを言語関連とその他に分類し、個数でソート const languageTags = [...tagCount.entries()] .filter(([tag]) => isLanguageTag(tag)) .sort((a, b) => b[1] - a[1]); const otherTags = [...tagCount.entries()] .filter(([tag]) => !isLanguageTag(tag)) .sort((a, b) => b[1] - a[1]); // 言語関連のタグを追加 if (languageTags.length > 0) { const langGroup = document.createElement('div'); langGroup.className = 'filter-group mb-2'; langGroup.innerHTML = '