Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions plots/slope-basic/implementations/javascript/chartjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// anyplot.ai
// slope-basic: Basic Slope Chart (Slopegraph)
// Library: chartjs 4.4.7 | JavaScript 22.23.1
// Quality: 93/100 | Created: 2026-07-25

const t = window.ANYPLOT_TOKENS;

// --- Data (in-memory, deterministic) ----------------------------------------
// Reading tutoring program: student scores (out of 100) before and after.
const students = [
"Ava", "Liam", "Sophia", "Mason", "Isabella",
"Ethan", "Mia", "Noah", "Amelia", "Lucas",
];
const preTest = [62, 58, 71, 45, 80, 55, 67, 73, 49, 61];
const postTest = [78, 65, 74, 52, 88, 70, 66, 90, 61, 59];

const INCREASE = t.palette[0]; // #009E73 brand green — up/gain (semantic exception)
const DECREASE = "#AE3030"; // matte red — down/loss (semantic anchor, slot 5)

const datasets = students.map((name, i) => {
const color = postTest[i] >= preTest[i] ? INCREASE : DECREASE;
return {
label: name,
data: [preTest[i], postTest[i]],
borderColor: color,
backgroundColor: color,
pointBackgroundColor: color,
pointBorderColor: color,
pointRadius: 6,
pointHoverRadius: 6,
borderWidth: 3,
tension: 0,
};
});

// --- Mount -------------------------------------------------------------------
const canvas = document.createElement("canvas");
document.getElementById("container").appendChild(canvas);

// --- Endpoint label plugin (native Chart.js plugin API, no external deps) ---
// Draws entity name + value at both ends of each line, matching the spec's
// "labels at both endpoints" requirement while keeping the legend uncluttered.
const endpointLabels = {
id: "slopeEndpointLabels",
afterDatasetsDraw(chart) {
const { ctx } = chart;
ctx.save();
ctx.font = "600 15px sans-serif";
ctx.textBaseline = "middle";
chart.data.datasets.forEach((ds, i) => {
const meta = chart.getDatasetMeta(i);
if (meta.hidden) return;
const [p0, p1] = meta.data;
ctx.fillStyle = ds.borderColor;
ctx.textAlign = "right";
ctx.fillText(`${ds.label} ${ds.data[0]}`, p0.x - 14, p0.y);
ctx.textAlign = "left";
ctx.fillText(`${ds.data[1]} ${ds.label}`, p1.x + 14, p1.y);
});
ctx.restore();
},
};
Chart.register(endpointLabels);

// --- Chart ---------------------------------------------------------------
new Chart(canvas, {
type: "line",
data: {
labels: ["Pre-Test", "Post-Test"],
datasets,
},
options: {
responsive: true,
maintainAspectRatio: false,
animation: false,
layout: {
padding: { left: 190, right: 190, top: 20, bottom: 10 },
},
plugins: {
title: {
display: true,
text: "slope-basic · javascript · chartjs · anyplot.ai",
color: t.ink,
font: { size: 22 },
},
legend: {
labels: {
color: t.ink,
font: { size: 16 },
generateLabels: () => [
{ text: "Increase", fillStyle: INCREASE, strokeStyle: INCREASE, lineWidth: 0 },
{ text: "Decrease", fillStyle: DECREASE, strokeStyle: DECREASE, lineWidth: 0 },
],
},
onClick: () => {},
},
tooltip: { enabled: false },
},
scales: {
x: {
type: "category",
offset: false,
ticks: { color: t.inkSoft, font: { size: 18, weight: "600" } },
grid: { color: t.grid, drawTicks: false },
border: { color: t.grid },
},
y: {
display: false,
},
},
},
});
256 changes: 256 additions & 0 deletions plots/slope-basic/metadata/javascript/chartjs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
library: chartjs
language: javascript
specification_id: slope-basic
created: '2026-07-25T23:46:19Z'
updated: '2026-07-25T23:51:01Z'
generated_by: claude-sonnet
workflow_run: 30179823665
issue: 981
language_version: 22.23.1
library_version: 4.4.7
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/javascript/chartjs/plot-light.png
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/javascript/chartjs/plot-dark.png
preview_html_light: https://storage.googleapis.com/anyplot-images/plots/slope-basic/javascript/chartjs/plot-light.html
preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/slope-basic/javascript/chartjs/plot-dark.html
quality_score: 93
review:
strengths:
- 'Correct semantic color-coding: brand green (#009E73) for score increases, matte-red
semantic anchor (#AE3030) for decreases -- a legitimate Imprint semantic exception
(gain/positive to green, loss/negative to red), identical data colors across both
themes.'
- Custom Chart.js plugin (afterDatasetsDraw) draws entity name + value at both line
endpoints, satisfying the spec's 'labels at both endpoints' requirement without
a cluttered 10-entry legend -- the legend instead explains the two semantic colors.
- 'Minimalist, theme-adaptive layout: y-axis hidden entirely (values are conveyed
directly by endpoint labels), subtle category grid lines, generous left/right
padding for the labels, chrome (title, ticks, legend) correctly flips between
#FAF8F1/#1A1A17 surfaces with readable text in both renders.'
- Realistic, neutral dataset (tutoring-program pre/post test scores) that shows
both increases and decreases plus a visible rank crossing (Noah overtakes Isabella
between Pre-Test and Post-Test), matching the spec's emphasis on direction, magnitude,
and rank change.
- 'animation: false set and the mount-node contract (canvas appended to #container,
responsive/maintainAspectRatio) followed correctly per the chartjs.md guidance.'
weaknesses:
- Title occupies only ~25-30% of canvas width at the current 22px size -- well below
the 50-70% guideline for a title this length; could grow slightly for more visual
presence without risking overflow.
- Only 2 of 10 entities (Mia, Lucas) decrease -- the 'decrease' semantic color is
thinly demonstrated; a slightly larger or more varied minority of declines would
strengthen feature-coverage storytelling.
- The endpoint-label plugin (Chart.register with an afterDatasetsDraw callback)
is a reasonable Chart.js idiom for this requirement, but it does add a function
block beyond the strict KISS imports-to-data-to-plot flow.
image_description: |-
Light render (plot-light.png):
Background: Warm off-white, matches #FAF8F1 -- not pure white.
Chrome: Title "slope-basic · javascript · chartjs · anyplot.ai" in bold dark ink, clearly readable. "Increase"/"Decrease" legend swatches at top center. Bottom x-axis ticks "Pre-Test" and "Post-Test" in bold dark text. Faint vertical grid lines at each category position. No y-axis (values are shown via direct endpoint labels instead).
Data: 10 slope lines connecting Pre-Test to Post-Test scores for 10 named students. 8 lines are brand green (#009E73, increases), 2 are matte red (#AE3030, Mia and Lucas, decreases). Each line endpoint has a colored dot plus a name + numeric value label matching the line's color. Colors are clearly distinguishable, markers are prominent for this sparse (10-entity) dataset.
Legibility verdict: PASS -- all title, legend, tick, and endpoint-label text is clearly readable against the light background; no light-on-light issues.

Dark render (plot-dark.png):
Background: Warm near-black, matches #1A1A17 -- not pure black.
Chrome: Title now rendered in light/white ink, clearly readable. Legend swatches and text in light color. "Pre-Test"/"Post-Test" tick labels in light bold text. Grid lines remain subtle and visible against the dark surface.
Data: Identical green (#009E73) and red (#AE3030) line/marker colors to the light render -- confirmed unchanged across themes, only chrome flipped. Endpoint labels remain colored to match their line and are legible against the dark background.
Legibility verdict: PASS -- no dark-on-dark failures found; all text (title, ticks, legend, endpoint labels) uses light-colored ink against the near-black surface.
criteria_checklist:
visual_quality:
score: 30
max: 30
items:
- id: VQ-01
name: Text Legibility
score: 8
max: 8
passed: true
comment: All font sizes explicitly set (title 22px, ticks 18px/600, endpoint
labels 15px/600, legend 16px); readable in both themes, no overflow or clipping.
- id: VQ-02
name: No Overlap
score: 6
max: 6
passed: true
comment: Even the tightest-spaced endpoint labels (e.g. 66 Mia / 65 Liam,
90 Noah / 88 Isabella) remain fully readable with no text collisions.
- id: VQ-03
name: Element Visibility
score: 6
max: 6
passed: true
comment: pointRadius 6 / borderWidth 3 well suited to this sparse 10-entity
dataset.
- id: VQ-04
name: Color Accessibility
score: 2
max: 2
passed: true
comment: Green/red pairing is redundantly encoded with per-line name+value
text labels, not relied on as the sole distinguishing signal.
- id: VQ-05
name: Layout & Canvas
score: 4
max: 4
passed: true
comment: Balanced margins, plot area well utilized, nothing cut off.
- id: VQ-06
name: Axis Labels & Title
score: 2
max: 2
passed: true
comment: Pre-Test/Post-Test time-point labels are descriptive; values are
labeled directly at each point.
- id: VQ-07
name: Palette Compliance
score: 2
max: 2
passed: true
comment: 'Brand green #009E73 for increase (first/majority series), matte-red
semantic anchor #AE3030 for decrease -- valid semantic exception. Identical
data colors across themes; backgrounds and chrome theme-correct in both
renders.'
design_excellence:
score: 16
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
score: 6
max: 8
passed: true
comment: Thoughtful semantic color scheme and Tufte-style direct endpoint
labeling instead of a cluttered per-entity legend -- clearly above a configured
default.
- id: DE-02
name: Visual Refinement
score: 5
max: 6
passed: true
comment: Y-axis fully hidden, subtle category grid only, generous whitespace
for labels; near-perfect refinement.
- id: DE-03
name: Data Storytelling
score: 5
max: 6
passed: true
comment: Color-coded direction plus a visible rank crossing (Noah overtakes
Isabella) creates a clear, immediate story of who improved and by how much.
spec_compliance:
score: 15
max: 15
items:
- id: SC-01
name: Plot Type
score: 5
max: 5
passed: true
comment: Correct slope/slopegraph chart via a two-category Chart.js line chart.
- id: SC-02
name: Required Features
score: 4
max: 4
passed: true
comment: Endpoint labels, direction color-coding, and labeled time-point axes
all present.
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
comment: X = time point, Y = score; all 10 entities' values visible via direct
labels.
- id: SC-04
name: Title & Legend
score: 3
max: 3
passed: true
comment: Title format exact match; legend correctly explains the two semantic
colors used for 10 series.
data_quality:
score: 14
max: 15
items:
- id: DQ-01
name: Feature Coverage
score: 5
max: 6
passed: true
comment: Shows increases, decreases, and a rank crossing; decrease category
is thinly represented (2/10).
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
comment: Neutral, real-world tutoring pre/post test scenario.
- id: DQ-03
name: Appropriate Scale
score: 4
max: 4
passed: true
comment: Scores 45-90/100 with plausible, realistic gains and one small decline.
code_quality:
score: 9
max: 10
items:
- id: CQ-01
name: KISS Structure
score: 2
max: 3
passed: true
comment: Mostly data-then-plot flow; the endpoint-label plugin adds a function
block, justified by the spec's labeling requirement.
- id: CQ-02
name: Reproducibility
score: 2
max: 2
passed: true
comment: Fully deterministic hardcoded arrays.
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
comment: No unused imports; uses only browser globals.
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
comment: Clean, no fake UI or fake interactivity.
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
comment: Correct mount-node contract, animation:false, current Chart.js API.
library_mastery:
score: 9
max: 10
items:
- id: LM-01
name: Idiomatic Usage
score: 5
max: 5
passed: true
comment: Native category-scale line chart, custom legend generateLabels, registered
plugin API -- all idiomatic Chart.js patterns.
- id: LM-02
name: Distinctive Features
score: 4
max: 5
passed: true
comment: Canvas-drawing plugin (afterDatasetsDraw) for endpoint labels is
a distinctive Chart.js-specific technique.
verdict: APPROVED
impl_tags:
dependencies: []
techniques:
- custom-legend
- annotations
patterns:
- data-generation
- iteration-over-groups
dataprep: []
styling:
- minimal-chrome
Loading