Skip to main content

Assessment & read-only

Apollon has a grading workflow on top of the editor: switch the editor into assessment mode, attach a score and feedback to individual diagram elements, highlight elements, and subscribe to which element the grader selected. The same readonly switch also gives you a plain non-editable viewer. This is the workflow Artemis uses to grade modeling exercises.

Read-only viewer

Pass readonly to render a diagram nobody can edit — for previews, summaries, or a graded result.

import { Apollon, type UMLModel } from "@tumaet/apollon"
import "@tumaet/apollon/style.css"

export function DiagramViewer({ model }: { model: UMLModel }) {
return <Apollon readonly defaultModel={model} style={{ height: 400 }} />
}

Imperatively, it's the readonly constructor option (toggle later with editor.setReadonly(true)):

import { ApollonEditor, type UMLModel } from "@tumaet/apollon"

function mountViewer(container: HTMLElement, model: UMLModel) {
return new ApollonEditor(container, { model, readonly: true })
}

Assessment mode

Construct the editor in ApollonMode.Assessment (or call editor.setMode(ApollonMode.Assessment) later), then attach an Assessment to each element you grade with addOrUpdateAssessment.

import { ApollonEditor, ApollonMode, type Assessment } from "@tumaet/apollon"
import "@tumaet/apollon/style.css"

const container = document.getElementById("apollon")
if (!container) throw new Error("#apollon container missing")

const editor = new ApollonEditor(container, { mode: ApollonMode.Assessment })

const assessment: Assessment = {
modelElementId: "node-1",
elementType: "Class",
score: 2,
feedback: "Good — but the association multiplicity is missing.",
}
editor.addOrUpdateAssessment(assessment)

// Assessments live on the model, keyed by element id:
const all: Record<string, Assessment> = editor.model.assessments

The Assessment shape

FieldTypeNotes
modelElementIdstringThe diagram element this assessment grades. Required.
elementTypestringThe element's type (e.g. "Class"). Required.
scorenumberPoints awarded. Required.
feedbackstring?Free-text feedback.
labelstring?Short label shown on the element.
labelColorstring?CSS color for the label.
correctionStatus{ status: "CORRECT" | "INCORRECT" | "NOT_VALIDATED"; description?: string }?For automated/suggested feedback review.

Drive the canvas from a feedback list

A host that lists feedback beside the diagram has a problem the list alone cannot solve: an entry says what a tutor wrote, never where it applies. The reader is left matching text against boxes by eye.

revealAssessment closes that loop. It selects the element, opens its feedback popover, and pans the canvas to it — keeping the reader's zoom, because the zoom is theirs.

import { ApollonEditor } from "@tumaet/apollon"

function showFeedbackFor(
editor: ApollonEditor,
feedback: { elementId: string }
) {
editor.revealAssessment(feedback.elementId)
}

// Closing the list, or deselecting, puts the canvas back:
function clearFeedback(editor: ApollonEditor) {
editor.revealAssessment(null)
}

Pass { reveal: false } to select without panning — useful when the element is already on screen and moving the canvas would be disorienting.

Pair it with subscribeToAssessmentSelection for the other direction, so clicking an element marks its entry in the list. Together the two halves explain each other instead of sitting side by side.

The popover only opens in ApollonMode.Assessment. In assessment with readonly — a student reading a graded diagram — it opens the read-only feedback popover; without readonly, the tutor's editable one.

Highlight elements

setElementHighlights rings elements by id with a CSS color — e.g. to mark the elements that still need feedback. It draws an outline rather than a fill, so use opaque colors: the element's own content, including its assessment badge, stays fully visible underneath. Highlights are ephemeral: they are not serialized into the model and not shared over collaboration. Pass null or an empty map to clear.

To color a whole group of attributes/methods at once — e.g. by a build result — address them by tag first; see Element tags & group coloring.

import { ApollonEditor } from "@tumaet/apollon"

function highlightMissing(editor: ApollonEditor) {
editor.setElementHighlights(
new Map([
["node-2", "#0d6efd"],
["node-5", "#0d6efd"],
])
)
}

React to the element being assessed

subscribeToAssessmentSelection fires with the ids of the elements the grader selected, so you can show the matching feedback form. Like every subscribeTo* method it returns a numeric id you pass to editor.unsubscribe to tear down.

import { ApollonEditor } from "@tumaet/apollon"

function watchAssessmentSelection(editor: ApollonEditor) {
const subId = editor.subscribeToAssessmentSelection((selectedElementIds) => {
// open the feedback form for selectedElementIds[0], etc.
console.log("assessing", selectedElementIds)
})
return () => editor.unsubscribe(subId)
}

See also