Skip to content

[rdom] Issue understanding $klist #466

@arnaudchenyensu

Description

@arnaudchenyensu

Hi @postspectacular ,

I'm experimenting a bit with rdom and I slightly modified the example from rdom-svg-nodes to change the color of the currently selected circle but I'm having different behaviors (commented in the following code sample) that I don't quite understand:

import { defAtom } from "@thi.ng/atom";
import { svg } from "@thi.ng/hiccup-svg";
import { $compile, $klist } from "@thi.ng/rdom";
import { fromAtom } from "@thi.ng/rstream";
import { repeatedly } from "@thi.ng/transducers";
import { random2, type Vec } from "@thi.ng/vectors";

const WIDTH = 600;
const NUM = 4;
const R = 20;

// define atom of NUM random points
const db = defAtom({
  clicked: -1,
  pts: [...repeatedly(() => random2([], R, WIDTH - R), NUM)]
});

// reactive subscription for atom changes
const $db = fromAtom(db);

$compile([
  'div',
  {},
  svg(
    {
      width: WIDTH,
      height: WIDTH,
      viewBox: `0 0 ${WIDTH} ${WIDTH}`,
      onmousemove: (e: MouseEvent) => {
        const clicked = db.deref().clicked
        clicked !== -1 && db.resetIn(['pts', clicked], [e.clientX, e.clientY])
      },
      onmouseup: () => db.resetIn(['clicked'], -1),
      ondblclick: (e: MouseEvent) =>
        db.swap((state) => ({
          ...state,
          pts: [...state.pts, [e.clientX, e.clientY]]
        })),
    },
    $klist(
      $db.map(({ clicked, pts }): [number, number, Vec][] => pts.map((p, i) => [clicked, i, p])),
      "g",
      {
        fill: 'white',
        stroke: 'black'
      },
      ([_clicked, i, p]) => [
        "circle",
        {
          r: R,
          cx: p[0],
          cy: p[1],
          onmousedown: (e: MouseEvent) => {
            db.resetIn(['clicked'], i)
            db.resetIn(['pts', i], [e.clientX, e.clientY]);
          },
          // fill: clicked === i ? 'grey' : 'white' // -> the circle will stay grey after the first click
          fill: $db.map(({ clicked }) => clicked === i ? 'grey' : 'white') // -> correct solution
        }
      ],
      ([clicked, i, p]) => {
        const fill = clicked === i ? 'grey' : 'white'
        // return `${p}-${i}-${fill}` // -> the circle will be duplicated on click
        return `${p}-${i}` // -> correct solution
      }
    ),
  )
]).mount(document.getElementById("app")!);
  1. The selected circle will stay grey even after a mouse release but I was expecting clicked to be updated automatically because it's coming from $db.map(...) (just like the circle position is automatically updated from p):
fill: clicked === i ? 'grey' : 'white'
  1. The $klist doc says that "Like a hash, the key value MUST represent an item's current value such that if the value changes, so does the key." So I thought that I needed to make the fill color part of the key but it will actually duplicate the circle:
return `${p}-${i}-${fill}`

Can you help me understand my mistakes?

Thank you in advance 😄

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions