1.2.1 • Published 1 year ago

tiny-atlas v1.2.1

Weekly downloads
-
License
ISC
Repository
-
Last release
1 year ago

tiny-atlas

Utility to produce data for drawing labels using signed distance fields in a webgl context. Internally uses tiny-sdf and potpack to create label props that glyphs index into a single texture. Made to be paired with regl.

See example/atlas.cjs for a complete example with regl based rendering. example/atlas-instances.cjs is the same example but done with instancing, properties are all attached to a single object.

API Interface Example

const { Atlas } = require('tiny-atlas')

// The arguments object is sent directly to `tiny-sdf`
const atlas = new Atlas({
  fontSize: 48,
  buffer: 3,
  radius: 8,
  cutoff: 0.25,
  fontFamily: 'Arial',
})

// Make as many labels as you want. `text` is string that is processed
// any other keys are passed to the final object in the `glyphs`
const labels = [{ text: 'coquí' }]

// `texture` is passed into `regl.texture` to produce a `sampler2D`
// compatible object.
// `glyphs` are in the shape described below, they hold all the properties
// to render with a reference to the `texture`.
const { texture, glyphs } = atlas.prepare({ labels })
const glyphsTexture = regl.texture(texture)

API

Atlas is the exported class. Its constructor takes an object passed along to tiny-sdf. This class is used to manage label's, which are in turn made up of glyphs.

atlas.prepare({ labels: [{ text }] }) method accepts an array of labels. The objects in this array only required a string value at the text key, any other keys will be spread across the glyphs object that corresponds to that particular label. The texture return value can be passed directly into regl.texture. The baselineOffsets key is a two element array with the first value being the max top distance from the baseline across all labels, and the second value being the max bottom distance from the baseline.

If drawing labels using instancing is desired, a truthy value at the instances key of the options object of atlas.prepare can be used. Additional label props can be spread in the return value by setting the instances value to an object with the shape { create, onGlyph}. create & onGlyph are expected to be functions. create gets passed an object with keys { props, size } where props is the return value that we are spreading across, and size is the total number of glyphs that are being accounted for with the output props. This allows for determining the type and length of array that will be returned. onGlyph is a function that is called with keys { props, labelIndex, charIndex, glyphIndex }. Again, props is the return value. labelIndex is the index of the current label that is being processed from the labels array. charIndex is the character index within that label. glyphIndex is the position in the array with the same length as the size that was used in the create function.

Instanced and object preperation will return a labels key that is the original label data that includes a glyphIndicies array. For instanced preperation the indicies will map into the individual arrays available on the glyphs arrays. For example, getting the labelDim for a label would look like:

const prepared = atlas.prepare({ labels, instances: true })
for (let i = 0; i < prepared.labels.length; i++) {
  const label = prepare.labels[i]
  const { glyphIndicies } = label
  const gi = glyphIndicies[0]
  const labelDim = [
    prepared.glyphs.labelDim[gi * 2 + 0],
    prepared.glyphs.labelDim[gi * 2 + 1],
  ]
}

Where as object preperation (non-instanced) data will be accessible indexing into glyphs, as follows:

const prepared = atlas.prepare({ labels })
for (let i = 0; i < prepared.labels.length; i++) {
  const label = prepare.labels[i]
  const { glyphIndicies } = label
  const gi = glyphIndicies[0]
  const { labelDim } = prepared.glyphs[gi]
}

If requesting instanced props, there will be an additional label key on the return value whose value will be an array of the original input labels, with the additional glyphIndicies array. glyphIndicies carries the integer index values that can be used to pull data from the various props arrays for the any input label.

atlas.prepare({
    labels : [{ text, ... }],
  }) => {
    texture: {
      data,
      width,
      height,
      format,
      type,
      mag,
      min,
    },
    glyphs: [{
      // 0-1 value of the position of the glyph in the label
      glyphInLabelStringIndex: Float, 
      // accumulated glyph widths preceding this glyph in the label
      glyphInLabelStringOffset: vec2<Float>,
      // glyph offset in the texture
      glyphTexOffset: vec2<Float>,
      // glyph dimensions in the texture
      glyphTexDim: vec2<Float>,
      // glyph's dimensions in SDF space
      // (tinySDFResult.{glyphWidth,glyphHeight})
      glyphRasterDim: vec2<Float>,
      // glyphs rasterized max distance from the baseline in SDF space
      glyphRasterTop: Float,
      // dimensions of the label in SDF space
      labelDim: vec2<Float>,
    }],
    // offsets from the baseline, describing the max distance above
    // and below the baseline: [top, bottom]
    baselineOffset: vec2<Float>,
    labels: {
      // includes all original label props
      ...label,
      // glyphIndicies are the indicies of glyphs of this label
      glyphIndicies: [Integer]
    }
  }
atlas.prepare({
    labels : [{ text, ... }],
    instances? : {
      init?: ({ props, size }) => void,
      onGlyph?: ({ props, labelIndex, charIndex, glyphIndex }) => void,
    },
  }) => {
    texture: {
      data,
      width,
      height,
      format,
      type,
      mag,
      min,
    },
    glyphs: {
      // 0-1 value of the position of the glyph in the label
      // length = size * 1
      glyphInLabelStringIndex: Float32Array, 
      // accumulated glyph widths preceding this glyph in the label
      // length = size * 2
      glyphInLabelStringOffset: Float32Array,
      // glyph offset in the texture
      // length = size * 2
      glyphTexOffset: Float32Array,
      // glyph dimensions in the texture
      // length = size * 2
      glyphTexDim: Float32Array,
      // glyph's dimensions in SDF space
      // (tinySDFResult.{glyphWidth,glyphHeight})
      // length = size * 2
      glyphRasterDim: Float32Array,
      // glyphs rasterized max distance from the baseline in SDF space
      // length = size * 1
      glyphRasterTop: Float32Array,
      // dimensions of the label in SDF space
      // length = size * 2
      labelDim: Float32Array,
    },
    // offsets from the baseline, describing the max distance above
    // and below the baseline: [top, bottom]
    baselineOffset: vec2<Float>,
    labels: {
      // includes all original label props
      ...label,
      // glyphIndicies are the indicies of glyphs of this label
      glyphIndicies: [Integer]
    }
  }

atlas.clear({ cache: boolean }) method accepts an object that can include a cache key with a boolean value. If this is set to true, the tiny-sdf results that are stored internally will be cleared. If cache is falsy, only the label level data will be removed, but glyph level data will be maintained.

1.2.0

1 year ago

1.2.1

1 year ago

1.1.0

1 year ago

1.0.1

1 year ago

1.0.0

1 year ago