Changelog
All notable changes to Cytoscape.js are recorded here. This file starts at the 4.0 line; for the 3.x history see the releases page.
The format follows Keep a Changelog, and this project follows semantic versioning.
[Unreleased] — 4.0.0
v4 is a rewrite of the model and the renderer. The public API keeps v3's
shape — cy.add(), eles.filter(), node.position(), the traversal and
algorithm surfaces, the alias spellings — while several v3 mechanisms were
removed rather than reimplemented.
Porting a v3 app: read MIGRATING.md. It carries the
recipe tables, the measured property-by-property diff, and the list of things
that compile and then behave differently.
Not released.
cytoscape@3remains the released library.
Added
- A columnar, CPU-canonical model. Elements live in typed-array columns
with stable slots, per-column coalesced dirty spans, a CSR adjacency index
and a dictionary-encoded
data()sidecar. Reads stay synchronous. - A WebGPU renderer: SDF node shapes, curved-edge families evaluated in the vertex stage from live positions, compute culling with indirect draws, GPU picking with a synchronous CPU fast path for nodes, an SDF glyph atlas, early-z, and an adaptive render scale.
- Structured queries and predicates replacing the selector language —
cy.nodes( { selected: true } ),cy.nodes( { data: { w: { gt: 1 } } } ), and plain functions for everything richer. - A serializable mapper DSL for style:
linear/log/sqrt/pow/symlog/diverging/ordinal/threshold/quantizescales, OKLab colour interpolation with named schemes, andcaseconditionals. Paint channels evaluate in a compute kernel; anything read by culling, picking or a columnar scan stays CPU-canonical. - Columnar and binary loading.
cytoscape.toColumnarElements(),cytoscape.serializeElements()/deserializeElements(), both accepted directly byoptions.elementsandcy.add(). Numeric columns deserialize as zero-copy views. - Style transitions (
transition-property/-duration/-delay/-timing-function) and animation controls (pause/resume/reverse, read-onlyprogress/paused). - The
forcelayout — GPU-native spring–electric, animating live at 100k nodes, with a CPU reference executor for headless and compound graphs. - A registry-free extension contract:
cy.layout( { impl } )runs an imported class or object;LayoutContextis columnar-first, and it,LayoutImplandCustomLayoutare exported types, so an external layout author writes against real types rather thanany. chart— v3's 101 numbered pie/stripe properties as one list-valued family with data-driven values, scheme palettes and donut holes.visibilityas a paint-only style property beside the structuralshow()/hide().- Slot compaction —
cy.compact()(aliascy.gc()) plus an automatic trigger, shrinking scan widths and buffers to the current graph rather than its peak. boxSelectionMode('contain'|'overlap'),boxSelectionIncludesLabels,wheelSensitivity,desktopTapThreshold,touchTapThreshold,tapholdDuration.eles.labelBoundingBox(), and labels joinboundingBox()/fit()by default.- TypeScript declarations built from the source JSDoc, so the API documentation is hover text in an editor.
Changed
The stylesheet is
{ nodes, edges, parents, core }— an object of property objects, not a list of selector blocks.Draw order is structural and stays that way: compound parents, then edges, then leaf nodes, then labels; slot order within a stream.
Animations run concurrently by channel and sequence by promise; overlapping channels evict the older animation in place.
Colours tween in OKLab, matching the mapper default (v3 tweened per-channel in sRGB).
spring( bounce )replacesspring( tension, friction ).Default
curve-styleisstraight(v3:bezier), and defaulttext-valignisbottom(v3:top).cy.elements()returns nodes then edges, not mixed insertion order.Positions are Float32 (~7 significant digits).
Compound event bubbling is v3's, with the remaining ordering deviation confined to within a phase (registration order).
stop( jumpToEnd )— theclearQueueargument is gone with the queue.font-family,font-style,font-weightare global constants, one face per glyph atlas.Rendering requires WebGPU; headless requires nothing.
Comparing elements across two instances throws instead of answering wrongly. Element identity is a slot in one store, so the first node of one graph and the first node of another used to compare as the same element:
same()returned true,intersection()returned everything,difference()returned nothing, andunion()silently dropped the other graph's elements. The twelve affected methods (same,anySame,contains,indexOf,union,difference,intersection,symmetricDifference,diff,allAreNeighbors,edgesWith,edgesTo) now reject a collection from another instance.A corrupt binary payload fails fast rather than allocating for what it declares. Three cases found by fuzzing — an out-of-range dictionary index, an over-long packed-id blob length, and an impossible data-key count — could hang a load or take tens of seconds before erroring; each now throws a contract error naming the field.
Removed
- Selector strings, everywhere — and
cy.$()with them (cy.$id()is the id lookup). Passing one throws, naming the replacement. - Classes (
addClass/removeClass/toggleClass/hasClass/flashClass) —data()plus mappers is the replacement. - Style functions (
( ele ) => props) and per-element style bypass (ele.style( name, value )) — both throw. - CSS-string stylesheets and
cytoscape.stylesheet(). z-index,z-compound-depth,z-index-compare,sortByZIndex,zDepth.restore(),clone(),copy()and the import form ofcy.json(): removed elements are terminally dead.- The animation queue, the
queueoption and thestepcallback (all three spellings throw). - Custom easing functions —
cubic-bezier()andlinear()cover any drawable curve. - Event namespaces: a type is matched whole, so
'tap.ns'is one literal name. - The
vmouse*aliases and raw mouse/touch re-emits (mousedown,click,touchstart, …) —pointer*is their modern spelling.mouseover/mouseoutstill fire. These names still register and then never fire, because custom event names must stay legal. cy.notify()/noNotifications()— the renderer is dirty-driven.renderTo; per-elementfont-family; viewport-fixed labels.- The canvas-era performance options —
hideEdgesOnViewport,textureOnViewport(+outside-texture-bg-*),motionBlur,motionBlurOpacity. - Style properties:
background-blacken,bounds-expansion,content,padding-{left,right,top,bottom},position,display,text-metrics,box-selection,box-select-labels,edge-text-rotation, themin-*-bias-*quartet, the singularcontrol-point-distance/segment-distance/segment-weight/segment-radiusspellings, themid-*-arrow-fill/-widthpairs, and the numberedpie-N-*/stripe-N-*families. The no-dash shape spellings (roundrectangle,cutrectangle,concavehexagon) throw in all three enums that took them. - The
coselayout — not ported;forceis v4's answer. - The extension registry — no
cytoscape.use(); extensions are imports.
Not yet implemented
border-style,outline-style,text-border-style(andborder-dash-pattern/-offset,border-cap/-join).cytoscape.warnings()and the error policy behind it.- Functional
preventDefault()for v4's own gesture defaults; the DOM half works. - Core, collection and renderer extension points.
Known deviations
Accepted differences from v3's rendering and semantics — arrow tips on
approximate boundaries for some shapes, butt caps on layer strokes, uneven
dashes on eccentric ellipses, a conservative edge-label bounding term, no
decimation on the curved edge stream, and others — are enumerated in
src/README.md under "Known deviations from v3". Each is recorded where the
feature is described, with the reason.