Mouse example
MouseSourceNode
ts
// @filename: MouseSourceNode.tsimport {DataFrame ,SourceNode ,DataObject ,Absolute2DPosition } from '@openhps/core';export classMouseSourceNode extendsSourceNode <DataFrame > {privateelementId : string = "";privatetrackingArea :HTMLElement =undefined ;constructor(elementId : string) {super();this.elementId =elementId ;this.once ('build', this._initMouse .bind (this));}_initMouse () {// Get tracking areathis.trackingArea =document .getElementById (this.elementId );this.trackingArea .onmousemove = this.onMouseMove .bind (this);this.trackingArea .ontouchmove = this.onTouchMove .bind (this);}onMouseMove (e :MouseEvent ) {constrect = this.trackingArea .getBoundingClientRect ();constx =e .clientX -rect .left ;consty =e .clientY -rect .top ;this._emitPosition (x ,y );}onTouchMove (e :TouchEvent ) {if (e .touches .length > 0) {constrect = this.trackingArea .getBoundingClientRect ();consttouch =e .touches [0];constx =touch .clientX -rect .left ;consty =touch .clientY -rect .top ;this._emitPosition (x ,y );}}_emitPosition (x : number,y : number) {constmouse = newDataObject ("mouse");mouse .position = newAbsolute2DPosition (x ,y );constframe = newDataFrame (mouse );this.push (frame );}onPull ():Promise <DataFrame > {return newPromise ((resolve ) => {resolve (undefined );});}}
ChartSinkNode
ts
// @filename: ChartSinkNode.tsimport {DataFrame ,SinkNode ,DataObject ,Absolute2DPosition ,NodeData ,NodeDataService } from '@openhps/core';export classChartSinkNode extendsSinkNode <DataFrame > {privateelementId : string = "";privatechartCanvas :HTMLCanvasElement =undefined ;privatechart : any =undefined ;constructor(elementId : string) {super();this.elementId =elementId ;this.once ('build', this._initChart .bind (this));}_initChart (): void {this.chartCanvas =document .getElementById (this.elementId ) asHTMLCanvasElement ;if (!(window as any).Chart ) {// Load Chart.js if not loaded/* @ts-expect-error: Ignore dynamic import error for CDN Chart.js */import('https://cdn.jsdelivr.net/npm/chart.js').then (() => this._initChart ());return;}}onPush (frame ):Promise <void> {return newPromise ((resolve ,reject ) => {// Store and retrieve historical data (supports multiple different object UIDs)constservice :NodeDataService <any> = this.model .findDataService (NodeData );service // Find node specific data pertaining to "mouse".findData (this.uid ,frame .source ).then ((data ) => {data =data ?? [];data .push ({x :frame .source .position .x ,y :frame .source .position .y });// Store node specific data pertaining to "mouse"returnservice .insertData (this.uid ,frame .source ,data );}).then ((data ) => {// Draw chart with all X,Y locations that passed through this nodethis.drawChart (data );resolve ();}).catch (reject );});}/*** Draw the chart** @params data Array of locations*/drawChart (data : ({x : number,y : number})[]): void {constctx = this.chartCanvas .getContext ('2d');if (this.chart ) this.chart .destroy ();this.chart = new (window as any).Chart (ctx , {type : 'line',data : {labels : ["location"],datasets : [{label : 'Mouse Location',data ,borderColor : '#007bff',backgroundColor : 'rgba(0,123,255,0.1)',fill : false,showLine : true,pointRadius : 2,parsing : false,}]},options : {animation : false,scales : {x : {type : 'linear',min : 0,max : 300,title : {display : true,text : 'X Position' }},y : {type : 'linear',min : 0,max : 200,title : {display : true,text : 'Y Position' }}},plugins : {legend : {display : false }}}});}}
Positioning Model
ts
// @filename: mouse.tsimport {ModelBuilder ,DataObject ,Absolute2DPosition ,SMAFilterNode ,ReferenceSpace ,Euler ,AngleUnit } from '@openhps/core';import {MouseSourceNode } from './MouseSourceNode';import {ChartSinkNode } from './ChartSinkNode';constmouseReferenceSpace = newReferenceSpace ().translation (0, 200).rotation (newEuler (180, 0, 0, 'ZXY',AngleUnit .DEGREE ));ModelBuilder .create ()// Step 1. Obtain X,Y location from mouse (active source node).from (newMouseSourceNode ("trackArea"))// Step 2. Flip the axis.convertFromSpace (mouseReferenceSpace )// Step 3. Simple moving average of the X,Y position (average of 40 readings).via (newSMAFilterNode ((obj :DataObject ) => ([{key : "x",value : (obj .position asAbsolute2DPosition ).x },{key : "y",value : (obj .position asAbsolute2DPosition ).y }]),(key : string,value : number,obj :DataObject ) => {obj .position [key ] =value },{taps : 40 }))// Step 4. Plot the results.to (newChartSinkNode ("mouseChart")).build ();