edemaine / svgtiler

Tool for drawing diagrams on a grid, combining grids of SVGs into a big SVG figure
MIT License
61 stars 6 forks source link

Mappings specified by classes or objects #95

Closed edemaine closed 2 years ago

edemaine commented 2 years ago

Yevhenii suggested an alternative form for specifying a mapping:

export default class # maybe: extends Mapping
  constructor: ->
    # initialize drawing-specific data
    @sawSomething = 0
    # essentially a beforeRender callback,
    # but with globals replaced by instance variables
  afterRender: ->
    # equivalent to afterRender callback
    console.log 'saw', @sawSomething
  beforeRender: ->
    # maybe also supported for symmetry
    # called after constructor
  map: (key) ->
    # the main mapping
    @sawSomething++
    return ...

The cool thing about this is that the lifecycle of class instances corresponds to each drawing/render, so you have a clear place to initialize drawing-specific things, and a clear place (the instance) to store drawing-specific data. Maybe you can do interesting things with inheritance too?

Otherwise it doesn't seem to offer much benefit. So I'm wondering about adding it as another option for how to specify mapping data, for complicated uses of beforeRender/afterRender.


A different but related approach is for import * from './mapping.js' to give the desired objects. Something like this:

export init = -> ...
export preprocess = -> ...
export default = ...

One advantage is that creating a custom mapping is really easy: just build an object {init: ..., preprocess: ..., default: ...}.

Another cool feature is that then svgtiler('map.js') is equivalent to svgtiler(require('./map.js')). But this equivalence is incompatible with top-level effects like svgtiler.preprocess and svgtiler.background. We could redefine svgtiler.background to only be callable within postprocess callbacks, with the meaning "add background rect now"; or keep its scheduling behavior, but restrict to running within a render (either preprocess or postprocess).

edemaine commented 2 years ago

The first part doesn't seem consistent with the new split of beforeRender into init and preprocess. The constructor would naturally be an alternative to init, but then the object lifetime doesn't correspond to a render.

However, preprocess and postprocess are called with this set to the Render instance, so there already is a somewhat natural place to put data... but it can't be set in init.

The second part is replaced by #100.