@dooboostore/lib-web

NPM versionBuild and TestLicense: MIT

Canvas-centered UI components for building rich browser editors, map-like visual tools, and candlestick/technical-indicator stock charts.


Features

  • ImageEditorCanvas: multi-layer canvas editor — image/text/shape layers (rect, circle, triangle, star, heart, speech bubble, pentagon, octagon, semicircle, cross), drag/resize/rotate/flip, z-ordering, crop & erase modes, undo/redo, and final-image export.
  • GpsMarkerCanvas: GPS point/path visualization canvas with pan, zoom, optional Mercator projection, and image or color markers.
  • ImageCropCanvas: polygon (freeform, not just rectangular) crop workflow for trimming an image.
  • TradeChart: candlestick chart engine with volume/OBV/VOSC/RSI/MACD panels, moving averages, Bollinger bands, golden/dead-cross and buy/sell markers, percentage lines, zoom/pan, and an RxJS-likeobservableevent stream (from@dooboostore/core).
  • OverlayStockChart: multi-ticker overlay line chart (several tickers on one canvas) with normalization modes, multiple line-smoothing styles, and point/range event markers.
  • Root-first exports: consume all public APIs from package root.
  • Bundle entry support: dedicated./bundle-entrysubpath for bundlers or UMD/ESM interop workflows.

Public API

@dooboostore/lib-webroot currently exposes:

  • ImageEditorCanvas
  • GpsMarkerCanvas
  • ImageCropCanvas
  • TradeChart
  • OverlayStockChart

(plus their associated types, e.g.CropCanvasConfig,CropCanvasRunParameter,GpsMarkerCanvasConfig,MarkerPoint,PathData,ImageCropCanvasConfig,CropResult,ChartConfig,ChartDataPoint,OHLCV,Transaction,TickerData,LineType,NormalizeType,EventMarker, and theOverlayStockChartevent type guards.)

Import Guide

Root import (recommended)

import{ImageEditorCanvas,GpsMarkerCanvas,ImageCropCanvas,TradeChart,OverlayStockChart}from'@dooboostore/lib-web';

Bundle entry import

import{ImageEditorCanvas}from'@dooboostore/lib-web/bundle-entry';

bundle-entryalso importsreflect-metadataand re-exports the peer packages as namespaces:

import{ImageEditorCanvas,Core,CoreWeb}from'@dooboostore/lib-web/bundle-entry';// Core = @dooboostore/core, CoreWeb = @dooboostore/core-web

The root also has a default export object{ GpsMarkerCanvas, ImageCropCanvas, ImageEditorCanvas, TradeChart, OverlayStockChart }.

Installation

# pnpmpnpm add @dooboostore/lib-web# npmnpm install @dooboostore/lib-web# yarnyarn add @dooboostore/lib-web

Quick Start

Image editor

ImageEditorCanvastakes the owningWindowas its first argument and a config with acanvas(anHTMLCanvasElement, or a CSS selector string resolved viaconfig.canvas) as the second. It sizes itself from the canvas element's ownclientWidth/clientHeight— there's no separatewidth/heightoption.

import{ImageEditorCanvas}from'@dooboostore/lib-web';consteditor =newImageEditorCanvas(window, {canvas:'#app',// or an HTMLCanvasElementonSelectionChange:(layer) =>console.log('selected:', layer),onCuttingModeChange:(isActive, targetLayer) =>console.log('crop/erase mode:', isActive, targetLayer),onHistoryChange:(canUndo, canRedo) =>console.log('history:', canUndo, canRedo),
});// Add layersawaiteditor.addImage(someBlobOrImageBitmap);awaiteditor.addText('Hello', {font:'sans-serif',size:48,fillColor:'#000'});awaiteditor.addRect({fillColor:'#fff',strokeColor:'#000',strokeWidth:2});// ...also: addCircle / addTriangle / addStar / addHeart / addSpeechBubble / addPentagon / addOctagon / addSemicircle / addCross// Manipulate the currently-selected layereditor.bringSelectedLayerToFront();
editor.sendSelectedLayerToBack();
editor.enterEraseMode();// crop-out part of the selected layerawaiteditor.updateSelectedText('New text');// Historyeditor.undo();
editor.redo();// Resize the underlying canvaseditor.resize(1024,768);// Export the composited resultconstdataUrl =awaiteditor.exportFinalImage();

Also:updateSelectedText(Options),updateSelected<Shape>(options),getSelectedLayer(),getMode()('none' | 'crop' | 'erase'),isSelectedMode(). Layers can also be added viaeditor.run({ img, handle, cropStroke })sinceImageEditorCanvasimplementsRunnable<void, CropCanvasRunParameter>from@dooboostore/core.

GPS marker map

GpsMarkerCanvastakes an existingHTMLCanvasElementand tracks its size with an internalResizeObserver— give the canvas a size via CSS, not constructor options.

import{GpsMarkerCanvas}from'@dooboostore/lib-web';constcanvas =document.getElementById('map')asHTMLCanvasElement;constmap =newGpsMarkerCanvas({
    canvas,useMercatorProjection:true,// false = simple equirectangular (lon,lat) projectionmarkerColor:'red',markerSize:32,// also: lineWidth, padding, labelFont, labelColor, labelOffset});

map.setPaths([{points: [{lat:37.5,lon:127.0}, {lat:37.6,lon:127.1}],color:'#2196F3',closePath:false}]);
map.setMarkers([{lat:37.5,lon:127.0,label:'Start',marker: {type:'color',color:'#4CAF50'} }]);

map.setUseMercatorProjection(false);
map.zoomIn();
map.zoomOut();
map.resetViewAndFitData();// reset pan/zoom and refit to current datamap.destroy();// remove listeners + disconnect the ResizeObserver

Image crop (polygon)

ImageCropCanvasalso takes an existingHTMLCanvasElement. The user clicks to add polygon points on the loaded image (at least 3), drags them to adjust, and taps a point's × handle to remove it.

import{ImageCropCanvas}from'@dooboostore/lib-web';constcropper =newImageCropCanvas({canvas:document.getElementById('crop')asHTMLCanvasElement,onDone:(result) =>{// result: { points: {x,y}[], dataUrl: string | null } — image-relative polygon points + cropped PNG data URLconsole.log(result.dataUrl);
    },
});

cropper.loadImage('/path/to/image.png');// ...user clicks/drags to build a polygon on the canvas...cropper.done();// fires onDone with the cropped resultcropper.cancel();// clear the in-progress polygoncropper.destroy();

Candlestick chart (TradeChart)

import{TradeChart}from'@dooboostore/lib-web';constdata =TradeChart.createData(ohlcvInputs, { transactions,maPeriods: [5,20,60] });constchart =newTradeChart({canvas:document.getElementById('chart')asHTMLCanvasElement,initialConfig: {show: {volume:true,rsi:true,macd:true,movingAverages:true,goldenCross:true,deadCross:true},enableZoom:true,
  },
});
chart.setConfig({show: {bollingerBands:true} });// merge in more config later, chainable (returns `this`)chart.observable.subscribe(evt=>console.log(evt));// zoom/pan/click events (@dooboostore/core Observable)chart.getViewState();// { startIndex, count }; setViewState(...) to restorechart.resize();
chart.destroy();

TradeChart.createData(inputs, config)turns raw OHLCV rows into theChartDataPoint[]the chart consumes, computing moving averages / OBV / VOSC / RSI / MACD and golden/dead-cross state along the way. Data setters (setTitle,setTransactions,setCross,setMAPeriods,setIsGroup) anddraw()are also chainable. Mostshow*toggles (e.g.showVolumePercentageLines,showPriceBollingerBands,showBuyMarkers, ...) are fluent (this-returning) shortcuts for the equivalentsetConfig({ show: { ... } })call.

Multi-ticker overlay chart (OverlayStockChart)

import{OverlayStockChart}from'@dooboostore/lib-web';constdataMap =newMap([
  ['AAPL', {data: {datas: aaplChartData,events: [] },color:'#2196F3'}],
  ['MSFT', {data: {datas: msftChartData },lineMode:'line-smooth'}],
]);constoverlay =newOverlayStockChart(document.getElementById('overlay')asHTMLCanvasElement,
  dataMap,
  {initialState: {showCandles:false,showGrid:true,showAverage: [] } }// also: commonEvents, config);
overlay.updateState({showGrid:false});// partial RenderState update; getState() reads itoverlay.setData(dataMap);// replace data (optional commonEvents)overlay.destroy();

OverlayStockChartdraws several tickers' series on one canvas for comparison, normalizing their scales ('none' | 'rangeNormalize' | 'normalize') and supporting several line-drawing styles ('line' | 'line-smooth' | 'line-smooth-open/high/low/middle' | 'step-to' | 'step-from' | 'step-center') plus point/range event markers (XPointEvent/YPointEvent/XYPointEvent/XRangeEvent/YRangeEvent/XYRangeEvent, distinguished via the exportedisXPointEvent/isRangeEvent/etc. type guards).

Best Practices

  • Keep canvas dimensions explicit for stable rendering quality — size via CSS/attributes on the<canvas>element itself;GpsMarkerCanvas/ImageCropCanvastrack size automatically viaResizeObserver, whileImageEditorCanvasreadsclientWidth/clientHeightonce at construction (callresize()after layout changes).
  • Debounce high-frequency pointer events in host application state updates.
  • Export from finalized state (exportFinalImage()) rather than per-frame snapshots.
  • Calldestroy()onGpsMarkerCanvas/ImageCropCanvaswhen done to disconnect theirResizeObserverand event listeners.
  • Use root import paths (@dooboostore/lib-web) as default; keep deep imports internal.

Troubleshooting

Issue:Blurry canvas output on high-DPI displays
Solution:GpsMarkerCanvasalready scales bywindow.devicePixelRatiointernally; forImageEditorCanvas/ImageCropCanvas, align canvas internal size with device pixel ratio yourself if you need the same treatment.

Issue:Slow interaction with many objects
Solution:reduce redraw region, batch operations, and disable expensive effects while dragging.

Issue:Import path errors in consumers
Solution:use root path or@dooboostore/lib-web/bundle-entry, not internal source paths.

Learn More

The detailed API documentation for each component is available on our documentation website.

Related Packages

License

This package is licensed under theMIT License.