Marks versus Layers

With the exception of the FuncLine, all Marks have a corresponding Layer component. You can use the Layer version when you want to create many marks of the same type. While the two are designed to be as similar as possible, there are some subtle differences to take note of. This page will discuss these differences.

Keys

The first difference between Marks and Layers is that the Layers have a keys prop, which Marks do not have:

Prop Required Type(s) Default Unit(s)
keys false String[] undefined Array of unique keys

Interactions

The main difference between Marks and Layers in the area of interactivity is that the Layer’s event object includes an index and key. If the keys prop is not provided, the key in the event object will be undefined. For more information, consult the interactivity documentation.

Aesthetic function syntax

This will be discussed under Aesthetics: marks vs. layers.

Positioning: marks vs. layers

Single values versus arrays

The main difference between the positioning of marks and layers is that whatever type of value you would pass to the prop of a single mark, you would need to pass an Array of that type of values to the layer. So if you pass a single local coordinate (often a Number) to the x1 prop of the Rectangle, then you would pass an Array (of, in this example, Numbers) to the RectangleLayer’s x1 prop. Likewise, if you pass an Array of local coordinates to the Line, you pass an Array of Arrays of local coordinates to the LineLayer. The only exceptions to this rule is the FuncLine’s (which has no corresponding Layer component) positioning props.

To illustrate, the result of drawing three Points in the left panel is identical to drawing a PointLayer consisting of three marks in the right panel:

<script>
  import { Graphic, Section, Point, PointLayer } from '@snlab/florence'
</script>

<Graphic width={500} height={300}>

  <Section x1={0} x2={0.5} scaleX={[0, 10]} scaleY={[0, 10]}>

    <Point x={2} y={2} />
    <Point x={5} y={5} />
    <Point x={8} y={8} />

  </Section>

  <Section x1={0.5} x2={1} scaleX={[0, 10]} scaleY={[0, 10]}>
  
    <PointLayer x={[2, 5, 8]} y={[2, 5, 8]} />

  </Section>

</Graphic>

Function syntax

Again with the exception of the FuncLine’s positioning props, the positioning props of all marks and layers support the so-called ‘function syntax’. Function syntax can be used to bypass the scaling step (see the local coordinates documentation).

See the example below for another side-by-side comparison of this behavior for marks and layers:

<script>
  import { Graphic, Section, Point, PointLayer } from '@snlab/florence'
</script>

<Graphic width={500} height={300}>

  <Section x1={0} x2={0.5} scaleX={[0, 10]} scaleY={[0, 10]}>

    <Point x={() => 0.2} y={() => 0.2} />
    <Point x={() => 0.5} y={() => 0.5} />
    <Point x={() => 0.8} y={() => 0.8} />

  </Section>

  <Section x1={0.5} x2={1} scaleX={[0, 10]} scaleY={[0, 10]}>
  
    <PointLayer x={() => [0.2, 0.5, 0.8]} y={() => [0.2, 0.5, 0.8]} />

  </Section>

</Graphic>

Aesthetics: marks vs. layers

Single values versus arrays

Like with the positioning props, aesthetic props of layers need to receive Arrays of whatever would otherwise be passed to the individual marks. For example, if the fill prop of the Point mark expects a color, the fill prop of the PointLayer expects an Array of colors:

<script>
  import { Graphic, Section, Point, PointLayer } from '@snlab/florence'
</script>

<Graphic width={500} height={300}>

  <Section x1={0} x2={0.5} scaleX={[0, 10]} scaleY={[0, 10]}>

    <Point x={2} y={2} fill={'red'} />
    <Point x={5} y={5} fill={'blue'} />
    <Point x={8} y={8} fill={'green'} />

  </Section>

  <Section x1={0.5} x2={1} scaleX={[0, 10]} scaleY={[0, 10]}>
  
    <PointLayer x={[2, 5, 8]} y={[2, 5, 8]} fill={['red', 'blue', 'green']} />

  </Section>

</Graphic>

Function syntax

Aesthetic props also have a ‘function syntax’, but it works a bit different from the one used in positioning props. The aesthetic prop function syntax will execute the given function for each mark in the layer, and receives an Object containing an index and a key:

{
  index: <Number>,
  key: <String>
}

These can be used to give marks with a certain index or key a different aesthetic value. In the example below, aesthetic function syntax is used to make one point in the PointLayer blue, while the rest is red:

<script>
  import { Graphic, Section, Point, PointLayer } from '@snlab/florence'
</script>

<Graphic width={500} height={300}>

  <Section x1={0} x2={0.5} scaleX={[0, 10]} scaleY={[0, 10]}>

    <Point x={2} y={2} fill={'red'} />
    <Point x={5} y={5} fill={'blue'} />
    <Point x={8} y={8} fill={'red'} />

  </Section>

  <Section x1={0.5} x2={1} scaleX={[0, 10]} scaleY={[0, 10]}>
  
    <PointLayer 
      x={[2, 5, 8]}
      y={[2, 5, 8]}
      fill={({ key }) => key === 'b' ? 'blue' : 'red'}
      keys={['a', 'b', 'c']}
    />

  </Section>

</Graphic>

If the Layer’s keys prop is not defined, the key property in aesthetic function syntax will be undefined.

The asOnePath prop

For every Mark, the corresponding Layer has a asOnePath prop (with the exception of the LabelLayer and FuncLine, which does not have a corresponding layer element). As the name implies, this draws the entire Layer as one SVG or Canvas path, but only if all the aesthethics of that layer are being recycled. If this is not the case, asOnePath will not do anything. When you have a layer where all shapes have the same aesthetics, which is common in maps and some graphics, asOnePath can improve performance significantly. However, if you are drawing, for example, overlapping polygons or points that have a fill and a stroke, the results can look funny when asOnePath is used.