RxJS Observable

We experiment with RxJS Observable to learn more about processing streams of events from existing tools. docs

We import the essential fromEvent() method from RxJS.

import {fromEvent} from 'https://cdn.jsdelivr.net/npm/rxjs@7.8.1/+esm'

We create a click counter.

output.insertAdjacentHTML( "beforebegin", `<button id="counter" data-n="0">Click</button>` ) fromEvent(counter, "click") .subscribe(event => { let {n} = counter.dataset counter.dataset.n = +n + 1 counter.innerHTML = `Count (${counter.dataset.n})` })

This example doesn't show why Observable is worth the trouble. We already have addEventListener("click"). Maybe drawing lines will reveal more.

We need a canvas on which to draw.

let canvas = document.createElement("canvas") canvas.id = "canvas" canvas.style = "border: 1px solid black;" canvas.width = 380 canvas.height = 330 let ctx = canvas.getContext("2d") output.appendChild(canvas)

Lets make drag events draw lines on the canvas.

We import a couple operators which we will explain below.

import {switchMap, takeUntil} from 'https://cdn.jsdelivr.net/npm/rxjs@7.8.1/+esm'

To detect drags we need to observe three different events: mousedown at the start of our line, a stream of mousemove events that we will draw to the canvas, and mouseup to stop the line.

let down$ = fromEvent(canvas, "mousedown") let move$ = fromEvent(canvas, "mousemove") let up$ = fromEvent(canvas, "mouseup")

The next bit is dense.

The chief benefit of using an Observable library is to be able to use and create and simple functions that process events in interesting ways. Moreover, we can compose operators into more complex assemblies.

Observable.pipe() lets us send forward the events to one or more operators.

switchMap() is a special sort of map() over the stream of events. docs In this case, the first "stream" is the mousedown event that is piped into switchMap. We switch the single mousedown event into a stream of mousemove events.

Before switching streams, we take the opportunity to position the start of our line in the canvas.

takeUntil() is special operator which passes the incoming stream of events from the pipe until it notices a signal to stop. In this case, the incoming stream are mousemove events and the stop signal is a mouseup event.

let drag$ = down$.pipe(switchMap(e => { ctx.moveTo(e.offsetX,e.offsetY) return move$.pipe(takeUntil(up$)) }))

We subscribe to this complex assembly with a simple function that draws lines on the canvas.

drag$.subscribe(e => { ctx.lineTo(e.offsetX, e.offsetY) ctx.stroke() })

We'll finish with some instructions to the reader.

export default `<em> Try drawing lines in the box above. Reload to clear. </em>`

In the frame below we can view the results.

//wiki.dbbs.co/assets/pages/js-snippet-template/importjs.html HEIGHT 400