@julieisbaka/graphjs
v0.4.0
Published
A zero-dependency, lightweight JavaScript graphing core with powerful plugin hooks.
Maintainers
Readme
GraphJS
GraphJS is a zero-dependency, lightweight JavaScript graphing core built for plugin-first extension.
See CHANGELOG.md for release history.
Goals
- Tiny core, no external runtime dependencies
- Clean graph lifecycle and rendering pipeline
- Comprehensive plugin hooks for first-party and third-party extensions
- Simple line-series baseline to build on
Install
Install from npm:
npm install @julieisbaka/graphjsDevelopment
- Run the test suite with
npm test. The test script uses Node's test runner directory mode so it works consistently across Windows shells, WSL, and Linux/macOS shells.
Quick Start
import { Graph } from "@julieisbaka/graphjs";
const graph = new Graph("#graph", {
width: 800,
height: 420,
plugins: []
});
graph
.setData([
{
id: "revenue",
type: "line",
color: "#2563eb",
pointRadius: 3,
points: [
{ x: 0, y: 12 },
{ x: 1, y: 16 },
{ x: 2, y: 11 },
{ x: 3, y: 19 }
]
}
])
.render();Plugin System
Plugins can be registered globally or passed per graph instance.
Global plugin registration
import { Graph } from "@julieisbaka/graphjs";
Graph.registerPlugin(myPlugin);
const graph = new Graph("#graph", {
plugins: ["myPlugin"]
});Instance plugin registration
const graph = new Graph("#graph", {
plugins: [
{
plugin: myPlugin,
options: { /* plugin config */ }
}
]
});Plugin shape
const myPlugin = {
id: "myPlugin",
priority: 10,
before: ["someOtherPlugin"],
after: ["basePlugin"],
capabilities: {
hooks: ["beforeRender", "afterRender"],
needsLayout: true,
needsBounds: true
},
defaults: {
enabled: true
},
install(graph, options, api) {
// setup work
// api.getPluginState / api.setState / api.registerHook / api.registerCommand
},
commands: {
// declarative command support (optional)
ping(payload, graph, options, api) {
return { ok: true, payload };
}
},
hooks: {
beforeRender(graph, ctx, options, api) {
// return false to cancel this phase
}
}
};Built-in lifecycle hooks
beforeInit,afterInitbeforeSetData,afterSetDatabeforeLayout,afterLayoutbeforeRender,beforeDrawSeries,afterDrawSeries,afterRenderbeforeResize,afterResizebeforeDestroy,afterDestroy
Any hook can return false to cancel the current stage.
Plugin maturity features
- Dependency-aware plugin ordering via
before/after - Optional capability flags (
hooks,needsLayout,needsBounds,needsData) for optimized hook dispatch - Optional plugin error boundary (
pluginErrorBoundary) — live-reconfigurable viagraph.setOptions({ pluginErrorBoundary: ... })
Core API
Instance methods
new Graph(canvasOrSelector, options)graph.setOptions(options)graph.getOptions()graph.setDomain(domain)graph.clearDomain()graph.getDomain()graph.setBoundsStrategy(fn)graph.setData(series[])graph.addSeries(series)graph.resize(width, height)graph.render({ force?: boolean })graph.clear()graph.destroy()graph.registerCommand(name, handler, metadata?, pluginId?)graph.unregisterCommand(name)graph.executeCommand(name, payload?)graph.listCommands()
Static methods and registries
Graph.registerPlugin(plugin)— add a plugin to the global registryGraph.unregisterPlugin(pluginId)— remove a plugin from the global registryGraph.registerRenderer(type, fn)— register a custom series renderer (e.g."bar","scatter")Graph.renderers—Map<string, fn>of all registered renderersGraph.registerSampler(name, fn)— register a custom data samplerGraph.samplers—Map<string, fn>of all registered samplers
Notable core options
immutableInputs(boolean): freeze normalized data for safer consumptiondomain({ xMin, xMax, yMin, yMax } | null): override data-derived boundsseries:{ type, color, lineWidth, pointRadius }— per-graph series defaults applied when a series omits those fieldssampling:{ enabled, maxPoints, method }—methodis the name of any registered sampler (built-in:"stride")scalability:{ dirtyRender, layerCaching, useOffscreenCanvas }pluginErrorBoundary:{ enabled, onError }— can be updated live viagraph.setOptions({ pluginErrorBoundary: ... })
Utility exports
GraphJS exports helpers for use in extensions and custom renderers.
All utility functions are available exclusively via the @julieisbaka/graphjs/utils subpath:
decimatePointsStrideresolveCanvasgetDevicePixelRationormalizeSeriesDatagetDataBoundsmakeLinearScaleinvertLinearScaleclampBoundsapplyDomainOverridefilterVisibleSeriesisPlainObjectdeepMergedeepFreezeclamp
Typed API support
GraphJS ships TypeScript declaration files for the core API, plugin contract,
command system, and options (src/index.d.ts). Utility function types are
declared separately in src/utils.d.ts and are exposed via the @julieisbaka/graphjs/utils
subpath entry.
First-party extensions
First-party extensions live at extensions/ in this workspace:
extensions/crosshairextensions/legendextensions/pan-zoomextensions/time-scaleextensions/tooltip-cursorextensions/watermark
Each extension is a standalone package with its own package.json and can be used independently.
