Skip to content

v3.0.0

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Oct 08:13
· 7 commits to main since this release
v3.0.0
7b1c769

Pivotick 3.0.0

A large graph is mostly repetition, and Simplify folds it away: nodes that play the same role collapse into one group drawn in their place, without touching the data. The interface now speaks the host's language, with complete Chinese, French, German and Portuguese catalogues bundled, and so does the documentation site.

Nodes pick their drawing from the zoom, edges into clusters are drawn at any depth, and a structured layout gives a small graph the same picture every time.

Read Breaking changes before upgrading: a few defaults change what an existing graph looks like, and each has a one-line opt-out.


Simplify: fold what plays the same role

UI.simplify.rules lists the rules, in the order they run, and a new Simplify rail mode switches each one and says what it folded.

simplify
  • Built-in rules fold nodes of one type linked to exactly the same nodes (a hub's leaves are the simplest case), chains that hang off one node, nodes with too few links or outside the k-core, and whole neighbourhoods found with the Leiden algorithm.
  • A rule of your own is a partition(view) returning a key per node. Nodes sharing a key become one group.
  • A group is drawn as a node, a disc in its type's colour with the count on it, and acts for its members: open it, pull a member out, select, pivot or delete them all. Search finds folded nodes and lights the groups holding them.
  • Group a selection by hand from the bulk bar or the node menu. Group, rename and ungroup are undo steps.
  • Pivot results can land grouped, one group per type, with pivotIngestGrouped or Review's Ingest in a group.
  • Groups are view state. getNodes(), the history, the table and exports see the real nodes.

The UI in the host's language

i18n-de
  • GraphOptions.i18n covers every string the library writes: the rail, menus, sidebar, table, pivot panel, history, toasts, tooltips and aria-labels. locale picks a bundled catalogue (zh, fr, de, pt), messages replaces text by key, and translate bridges an existing translation library. English fills every gap.
  • locale also formats counts, lists and sorting, and plurals are right in English too: no more "1 nodes".
  • Gettext PO catalogues ship in locales/, checked at build time for completeness, plural forms and placeholders.
  • The documentation site is in English, Chinese, French, German and Portuguese, guides and API reference alike.

Detail that follows the zoom

detail-tiers
  • NodeStyle.tiers gives a node several drawings, a dot on an overview, a chip once there is room, a card up close, chosen by the size it renders at. The layout footprint stays put, so nothing moves when one drawing gives way to the next, and the two cross-fade.
  • Nodetyle.focusTier is the drawing for the node under the pointer, at a readable size whatever the zoom.
  • Labels too small to read are not drawn (render.minLabelFontSize, 9px). On a 2500-node graph that cuts a tick's reposition pass from 23.5ms to 7.0ms.
  • textMaxWidth and textFontSize cap a node label's width and set its font size.

Edges across clusters, at any depth

One rule decides what the canvas draws for an edge touching a cluster: each end lands on the node on screen for it, and edges landing on the same two nodes share one line. Edges from inside a cluster to outside it, and edges two or more levels down, are now drawn. A line standing for one edge looks like it and clicks through to it, and filters reach a closed cluster's children.

Pivots

  • Fetch & ingest lands a pivot's results without triage.
  • menuChoices turns a pivot's row in the Pivot ▸ submenu into one row per choice.
  • A facet can declare a default, and a summary can leave its total unknown.
  • Saving got finer: graph.pivots.save({ elements }) writes only what you name, a save can open a prompt and be cancelled, and pivotSaveControls: false hides the Save buttons.
  • Rim badges show only while Pivot mode is open.

Everything else

New options

  • layout: { type: 'structured' }: a deterministic layout for small graphs, with fans of leaves lined up beside their hub and labels on the free side.
  • FilterFieldConfig.negate and an is / is not switch on every filter field.
  • UI.topBar.actions: host pills in the top bar, with split-button menus.
  • UI.emptyState: a card on a canvas with no node and no note.
  • UI.busyIndicator: a spinner while an async hook is thinking.
  • UI.tooltip.enabled takes a per-kind map or a function.
  • UI.neighborsPanel.graph overrides the neighbour graph's render and layout.
  • render.minFitScale and render.fitAnchor floor the opening fit, and ready waits for it.
  • graph.addNote(options), note.toJSON() and graph.setNotes(); Note is exported.
  • A propertiesPanel.render or mainHeader.render returning undefined draws the default.

Interaction

  • A right-click on a multi-selection acts on the whole selection, and table rows get their element's context menu.
  • Del hides the selected nodes, as one undo step.
  • The context menus read in one order: Pivot, group entries, the rest, delete last. The canvas menu gains Release pinned nodes.

Fixed

  • A second graph on the same page draws its own arrowheads.
  • graph.updateData re-renders once per call instead of once per element.
  • simulation.warmupTicks: 0 keeps given positions, and simulation.layout is honoured.
  • A graph built in a hidden or resizing container fits once it has a size.
  • Selecting a node inside a closed cluster lights and centres the cluster.
  • A viewer canvas takes the height its container gives it.
  • graph.removeBySource is recorded in the history and can be undone.
  • Portaled tooltips and menus follow UI.theme.
  • An unlabelled edge no longer carries a label container, which cost almost all of a tick's reposition pass on a 1000-node graph.

Breaking changes

Most apps need no change. The defaults are the ones to read.

Before After
Labels drawn at any zoom Hidden below 9 rendered px; render: { minLabelFontSize: 0 } restores them
A blank empty canvas A card; UI: { emptyState: false } removes it
Rim badges outside Pivot mode pivotRimBadgeVisible: 'always'
App menu entries below Delete Now above it
A viewer relying on a 300px minimum height Set a height on its container
warmupTicks: 0 running the full warmup Runs none; leave it unset for the default
Markup in Flyout.headerRow / sectionLabel / toggleRow Plain text
edge.isCrossCluster, get/setSubgraphFromNode, get/setSubgraphToNode, writable isSynthetic Gone; stand-ins are drawing only and getEdges() returns real edges
'endpoint' in the Edges tab for an edge into a closed cluster 'nested'
A switch over HistoryKind Add 'group' and 'removal'
A content hook returning null printing "null" Renders nothing

The full list is in CHANGELOG.md.

Documentation