diff --git a/plots/venn-labeled-items/implementations/javascript/chartjs.js b/plots/venn-labeled-items/implementations/javascript/chartjs.js new file mode 100644 index 0000000000..89acfcf72b --- /dev/null +++ b/plots/venn-labeled-items/implementations/javascript/chartjs.js @@ -0,0 +1,168 @@ +// anyplot.ai +// venn-labeled-items: Chartgeist-Style Venn Diagram with Labeled Items +// Library: chartjs 4.4.7 | JavaScript 22.23.0 +// Quality: 85/100 | Created: 2026-06-25 + +const t = window.ANYPLOT_TOKENS; + +// --- Data ------------------------------------------------------------------ +const circles = [ + { name: "Hyped Online", color: t.palette[0] }, // #009E73 — Imprint palette pos 1 + { name: "Actually Useful", color: t.palette[1] }, // #C475FD — Imprint palette pos 2 + { name: "Secretly Beloved", color: t.palette[2] }, // #4467A3 — Imprint palette pos 3 +]; + +const items = [ + { label: "NFTs", zone: "A" }, + { label: "Metaverse", zone: "A" }, + { label: "Spreadsheets", zone: "B" }, + { label: "Google Maps", zone: "B" }, + { label: "RSS Feeds", zone: "C" }, + { label: "Fax Machines", zone: "C" }, + { label: "ChatGPT", zone: "AB" }, + { label: "Slack", zone: "AB" }, + { label: "TikTok", zone: "AC" }, + { label: "Vinyl Records", zone: "AC" }, + { label: "Wikipedia", zone: "BC" }, + { label: "Duct Tape", zone: "BC" }, + { label: "The Internet", zone: "ABC" }, + { label: "Coffee", zone: "ABC" }, +]; + +// --- Mount ----------------------------------------------------------------- +const canvas = document.createElement("canvas"); +document.getElementById("container").appendChild(canvas); + +// --- Venn drawing plugin --------------------------------------------------- +const vennPlugin = { + id: "vennLabeled", + afterDraw(chart) { + const ctx = chart.ctx; + const W = chart.width; + const H = chart.height; + + // Background + ctx.fillStyle = t.pageBg; + ctx.fillRect(0, 0, W, H); + + // Layout geometry + const cx = W * 0.5; + const cy = H * 0.50; + const r = Math.min(W, H) * 0.32; + const d = r * 0.58; + + // Circle centers — equilateral-triangle arrangement + const A = { x: cx - d * Math.cos(Math.PI / 6), y: cy - d * 0.55 }; + const B = { x: cx + d * Math.cos(Math.PI / 6), y: cy - d * 0.55 }; + const C = { x: cx, y: cy + d * 0.80 }; + const ctrs = [A, B, C]; + + // Semi-transparent circle fills + for (let i = 0; i < 3; i++) { + ctx.save(); + ctx.globalAlpha = 0.21; + ctx.beginPath(); + ctx.arc(ctrs[i].x, ctrs[i].y, r, 0, 2 * Math.PI); + ctx.fillStyle = circles[i].color; + ctx.fill(); + ctx.restore(); + } + + // Circle outlines + for (let i = 0; i < 3; i++) { + ctx.save(); + ctx.globalAlpha = 0.60; + ctx.beginPath(); + ctx.arc(ctrs[i].x, ctrs[i].y, r, 0, 2 * Math.PI); + ctx.strokeStyle = circles[i].color; + ctx.lineWidth = 2.5; + ctx.stroke(); + ctx.restore(); + } + + // Zone centers — verified to lie inside the correct regions + const z = { + A: { x: A.x - r * 0.50, y: A.y - r * 0.20 }, + B: { x: B.x + r * 0.50, y: B.y - r * 0.20 }, + C: { x: cx, y: C.y + r * 0.40 }, + AB: { x: cx, y: cy - d * 1.10 }, + AC: { x: cx - d * 0.75, y: cy + d * 0.30 }, + BC: { x: cx + d * 0.75, y: cy + d * 0.30 }, + ABC: { x: cx, y: cy }, + }; + + // Category name labels (outside each circle) + const catFontSize = Math.round(r * 0.13); + ctx.font = `bold ${catFontSize}px Georgia, serif`; + ctx.textBaseline = "middle"; + const catPos = [ + { x: A.x - r * 0.95, y: A.y - r * 0.68, align: "center" }, + { x: B.x + r * 0.95, y: B.y - r * 0.68, align: "center" }, + { x: cx, y: C.y + r * 1.05, align: "center" }, + ]; + for (let i = 0; i < 3; i++) { + ctx.fillStyle = circles[i].color; + ctx.textAlign = catPos[i].align; + ctx.fillText(circles[i].name, catPos[i].x, catPos[i].y); + } + + // Group items by zone + const byZone = {}; + for (const item of items) { + (byZone[item.zone] = byZone[item.zone] || []).push(item.label); + } + + // Item labels inside each zone + const itemFontSize = Math.round(r * 0.095); + const lineH = itemFontSize * 1.65; + ctx.font = `${itemFontSize}px Georgia, serif`; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillStyle = t.inkSoft; + + for (const [zone, labels] of Object.entries(byZone)) { + const base = z[zone]; + if (!base) continue; + const startY = base.y - ((labels.length - 1) * lineH) / 2; + for (let i = 0; i < labels.length; i++) { + ctx.fillText(labels[i], base.x, startY + i * lineH); + } + } + + // Title (scaled for length) + const titleText = "Tech Zeitgeist · venn-labeled-items · javascript · chartjs · anyplot.ai"; + const titleSize = Math.max(12, Math.round(22 * 67 / titleText.length)); + ctx.font = `bold ${titleSize}px Georgia, serif`; + ctx.fillStyle = t.ink; + ctx.textAlign = "center"; + ctx.textBaseline = "top"; + ctx.fillText(titleText, W / 2, H * 0.022); + + // Subtitle + const subtitleSize = Math.max(10, Math.round(titleSize * 0.72)); + ctx.font = `italic ${subtitleSize}px Georgia, serif`; + ctx.fillStyle = t.inkSoft; + ctx.fillText("Where does it live — hype, utility, or quiet devotion?", W / 2, H * 0.022 + titleSize * 1.5); + }, +}; + +// --- Chart (blank scatter used as canvas container + custom Venn plugin) --- +new Chart(canvas, { + type: "scatter", + data: { datasets: [] }, + options: { + responsive: true, + maintainAspectRatio: false, + animation: false, + layout: { padding: 0 }, + plugins: { + legend: { display: false }, + title: { display: false }, + }, + scales: { + x: { display: false }, + y: { display: false }, + }, + }, + plugins: [vennPlugin], +}); diff --git a/plots/venn-labeled-items/metadata/javascript/chartjs.yaml b/plots/venn-labeled-items/metadata/javascript/chartjs.yaml new file mode 100644 index 0000000000..fa3304040a --- /dev/null +++ b/plots/venn-labeled-items/metadata/javascript/chartjs.yaml @@ -0,0 +1,268 @@ +library: chartjs +language: javascript +specification_id: venn-labeled-items +created: '2026-06-25T11:47:44Z' +updated: '2026-06-25T12:13:44Z' +generated_by: claude-sonnet +workflow_run: 28167044348 +issue: 5364 +language_version: 22.23.0 +library_version: 4.4.7 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/javascript/chartjs/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/javascript/chartjs/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/javascript/chartjs/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/javascript/chartjs/plot-dark.html +quality_score: 85 +review: + strengths: + - Three-circle Venn diagram correctly implements all 7 interior zones with appropriate + items in each + - Editorial Georgia serif typography creates a genuine WIRED Chartgeist feel — deliberate + and consistent + - Semi-transparent circle fills (alpha 0.21) with separate outline alpha (0.60) + creates professional depth + - Title scaling formula (22 * 67 / titleLength) correctly handles the long mandated + title + - Witty subtitle "Where does it live — hype, utility, or quiet devotion?" frames + the editorial narrative + - Imprint palette positions 1-3 correctly assigned to circles; theme-adaptive chrome + (pageBg, ink, inkSoft) in both renders + - Deterministic hardcoded data — no randomness, fully reproducible + - Chart.js plugin system (afterDraw) used as the correct idiom for extending Chart.js + with a custom chart type not in the 8 native types + weaknesses: + - '"Secretly Beloved" category label center is at y≈886px CSS in a 900px canvas + with ~37px font — bottom of descenders approach the canvas boundary; reduce `r` + by 5-8% or shift the C-circle downward to restore safe margin' + - Triple intersection (ABC) zone is geometrically small and holds 2 items ("The + Internet", "Coffee") stacked with only 1.65× lineHeight, leaving them visually + cramped; consider a slightly lower itemFontSize for zones with ≥2 items + - 'LM-02 improvement opportunity: the implementation uses raw canvas 2D drawing + inside the plugin rather than composing Chart.js datasets — using Chart.js bubble/scatter + datasets with plugin-drawn circle arcs would show deeper library mastery' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) — correct anyplot light surface; NOT pure white + Chrome: Title "Tech Zeitgeist · venn-labeled-items · javascript · chartjs · anyplot.ai" in dark ink at top center; italic subtitle "Where does it live — hype, utility, or quiet devotion?" below in inkSoft; all readable + Data: Three overlapping circles — green (#009E73, Imprint pos 1), lavender (#C475FD, pos 2), blue (#4467A3, pos 3) — with semi-transparent fills (alpha 0.21) and colored outlines (alpha 0.60). Category labels "Hyped Online" (green), "Actually Useful" (lavender), "Secretly Beloved" (blue) appear outside each circle in their respective colors. Item labels (NFTs, Metaverse, Spreadsheets, Google Maps, RSS Feeds, Fax Machines, ChatGPT, Slack, TikTok, Vinyl Records, Wikipedia, Duct Tape, The Internet, Coffee) appear in all 7 zones in inkSoft gray Georgia serif. + Legibility verdict: PASS — all text clearly readable; "Secretly Beloved" at bottom is close to canvas edge but pixels are complete + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) — correct anyplot dark surface; NOT pure black + Chrome: Title and subtitle text appear in light ink (#F0EFE8) — clearly readable against dark background. Category labels maintain their Imprint circle colors (green, lavender, blue). Item labels in #B8B7B0 (inkSoft dark) — light gray text on near-black: fully readable. NO dark-on-dark failures. + Data: Circle fill/outline colors are identical to light render — green #009E73, lavender #C475FD, blue #4467A3. Data colors correctly unchanged between themes. Only chrome (background, text) flipped. + Legibility verdict: PASS — all elements readable; theme adaptation correct; no black-on-black text + criteria_checklist: + visual_quality: + score: 26 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: 'All font sizes explicitly set via formula; category ~37px CSS, items + ~27px CSS, title ~21px CSS scaled for length. Legible in both themes. Minor: + bottom category label approaches canvas edge.' + - id: VQ-02 + name: No Overlap + score: 5 + max: 6 + passed: true + comment: Generally clean placement; minor crowding in ABC triple intersection + zone with 2 stacked items at 1.65x lineHeight. + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Circles visible with semi-transparent fills; outlines at alpha 0.60 + provide clear boundaries; labels clearly distinguishable. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Imprint palette positions 1-3 are CVD-safe; item labels use inkSoft + (adaptive neutral); no red-green sole signal. + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: Venn fills approximately 60-65% of canvas; balanced left/right; 'Secretly + Beloved' label center at y~886px CSS in 900px canvas is very close to bottom + edge. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Descriptive prefixed title + spec-id + javascript + chartjs + anyplot.ai + format correct; thematic subtitle adds context. No traditional axes needed. + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First circle #009E73 (Imprint pos 1); positions 2 and 3 correct; + pageBg used for background (theme-adaptive); ink/inkSoft chrome theme-adaptive + in both renders.' + design_excellence: + score: 13 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: Deliberate editorial Georgia serif throughout; alpha-layered circles + with calculated opacities; witty subtitle. Above 'well-configured default' + (4) but not publication-ready (6/8) — layout is competent without being + striking. + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: No grid, no spurious axes; semi-transparent fills (0.21) and outlines + (0.60) show deliberate alpha tuning; clean whitespace. Good refinement above + library defaults. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Subtitle frames the editorial question; opinionated categories (Hyped + Online, Actually Useful, Secretly Beloved) create a narrative lens; items + like NFTs/Metaverse vs Google Maps vs RSS Feeds tell a recognizable tech-culture + story. + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Three-circle symmetric Venn diagram with labeled items in all 7 interior + zones. + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Semi-transparent fills, category names outside circles, item labels + inside zones, gridless editorial background — all spec requirements met. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: All 7 zones populated; 14 items within spec's 10-25 range; zone assignments + correct. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: 'Title: ''Tech Zeitgeist · venn-labeled-items · javascript · chartjs + · anyplot.ai'' — correct {Descriptive} · {spec-id} · {lang} · {lib} · anyplot.ai + format.' + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: All 7 Venn zones (A, B, C, AB, AC, BC, ABC) populated; covers every + intersection pattern the plot type can show. + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Real tech culture references (NFTs, Google Maps, ChatGPT, Wikipedia, + etc.); neutral — no controversial political/social topics; genuine editorial + voice. + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: 14 items within 10-25 spec range; items per zone (1-2 each) appropriate + for label legibility. + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: No classes/functions; clear data → mount → plugin → chart sequence. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: Fully hardcoded deterministic data; no randomness needed. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: No imports — Chart is a harness-provided global; clean. + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean zone geometry calculations; iteration-over-groups pattern for + label rendering; no over-engineering. + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: 'animation: false set; responsive: true; maintainAspectRatio: false; + no manual file writes — harness handles output correctly.' + library_mastery: + score: 6 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 3 + max: 5 + passed: true + comment: Correct use of Chart.js plugin system (afterDraw hook) as the idiomatic + way to extend Chart.js beyond its 8 native chart types. Using a scatter + chart with empty dataset as a canvas container is the accepted Chart.js + pattern for custom layouts. + - id: LM-02 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Chart.js afterDraw plugin lifecycle hook is library-specific; the + approach of intercepting the render pipeline to draw custom geometry leverages + Chart.js extensibility architecture that is distinctive to this library. + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - annotations + patterns: + - iteration-over-groups + dataprep: [] + styling: + - alpha-blending + - minimal-chrome