Marks versus Layers
With the exception of the FuncLine, all Mark
s 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 Mark
s and Layer
s is that the Layer
s have a keys
prop, which Mark
s do not have:
Prop | Required | Type(s) | Default | Unit(s) |
---|---|---|---|---|
keys | false |
String[] |
undefined |
Array of unique keys |
Interactions
The main difference between Mark
s and Layer
s 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, Number
s) to the RectangleLayer
’s x1
prop. Likewise, if you pass an Array
of local coordinates to the Line, you pass an Array
of Array
s 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 Point
s 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 Array
s 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.