Drawing
The React half: the hooks a surface is built on, the components it draws labels, maths and rich text with, the footer controls, and the geometry behind a mark.
@internote/canvas-sdk@internote/canvas-sdk/reactOn this page
Everything here comes from @internote/canvas-sdk/react, the only entry point that needs React, except the geometry at the end.
A surface is built on a few hooks:
useEnvironmentSessionreads and writes the environment's session state, and re-renders when it changes. A surface and its footer share state through it.useSceneParametersreads the scene's parameters and re-renders when one moves, which a surface that draws with them needs, since they live in the scene's slot and not the environment's.useSurfaceMetricsmeasures the surface's SVG and the canvas unit, and re-measures when either changes.usePanZoomGesturesbinds wheel, drag and double-click to an element; the environment supplies the arithmetic of its own view.useTransientanduseTransientCollectionread what the surface published for its footer, such as a cursor reading, without re-rendering the surface.
A mark gets a tooltip by spreading surfaceTooltip onto the element that draws it. The environment gives the card's words, a SurfaceTip of a title, a look and rows of name and value, and the host draws the card for every environment alike: over the surface, following the cursor, gone when the pointer leaves, presses or scrolls. Pass the tip as a function and it is worked out only when the pointer arrives, so a mark of a thousand readings formats none until one is hovered. A surface that finds what is under the pointer itself, by distance rather than by element, calls pointSurfaceTooltip from its pointer move with a key for what it found. The look is a KeyLook, the same description the scene's key draws an entry from, and the card draws it with the key's own LookSwatch; build it with itemLook from the colour VALUE a mark was coloured by (its ItemColours.names), never from the CSS it paints with. formatTipNumber writes a value as the data has it, so cards in different environments print numbers alike. Every element with a tooltip carries data-cnv-tooltip, for the environment's stylesheet to give a cursor.
<circle
cx={cx}
cy={cy}
r={r}
{...surfaceTooltip(environmentKey, () => ({
title: 'Rainfall',
look: itemLook(attrs.colour, painted.names[i], 'teal'),
rows: [{ label: 'Month', value: 'Feb' }, { label: 'mm', value: formatTipNumber(6.8) }],
}))}
/>Text an author wrote can hold bold, links, maths and live values, so draw it with InlineContent or RichLabel rather than as a plain string. Maths typesets LaTeX, and parseToLatex turns a reader's typed shorthand into it.
An environment that takes a title: sets it in EnvironmentTitle, with its own class for where and how it is drawn. The host finds a title by it: a figure exported from a scene of one environment moves that title into its header, beside the mark. A title drawn as plain markup is not found, and stays where the environment put it.
{attrs['title'] && (
<EnvironmentTitle className="weather-title">
<InlineContent items={attrs['title']} />
</EnvironmentTitle>
)}The Footer… components are the controls a footer is made of: FooterSlider, FooterSelect, FooterList and the rest. Using them keeps every environment's footer consistent. The scene's own parameter rows are the host's; an environment never draws one.
highlightSpec and HighlightRing draw a cue.highlight's rings, and spotlightStrength says how far a cue.spotlight has taken the rest of the environment down.
The geometry needs no React and comes from the root: makeArrowhead and sampleShapePoints for marks, leaderLine for the line from a mark to a label, clientToSvgPoint for where the pointer is in an SVG's own coordinates, and lerp, clamp and clamp01 for the arithmetic between.
Also exported here, documented under @internote/canvas-sdk/host: BlankRenderContext, BlankElementRenderer.