line.rst 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. .. _css_cookbook_lines:
  2. Lines
  3. =====
  4. While lines can also seem to be simple shapes, having length but no width, there are many options and tricks for making
  5. lines display nicely.
  6. .. _css_cookbook_lines_attributes:
  7. Example lines layer
  8. -------------------
  9. The :download:`lines layer <../../sld/cookbook/artifacts/sld_cookbook_line.zip>` used in the examples below contains road information for a
  10. fictional country. For reference, the attribute table for the points in this layer is included below.
  11. .. list-table::
  12. :widths: 30 40 30
  13. * - **fid** (Feature ID)
  14. - **name** (Road name)
  15. - **type** (Road class)
  16. * - line.1
  17. - Latway
  18. - highway
  19. * - line.2
  20. - Crescent Avenue
  21. - secondary
  22. * - line.3
  23. - Forest Avenue
  24. - secondary
  25. * - line.4
  26. - Longway
  27. - highway
  28. * - line.5
  29. - Saxer Avenue
  30. - secondary
  31. * - line.6
  32. - Ridge Avenue
  33. - secondary
  34. * - line.7
  35. - Holly Lane
  36. - local-road
  37. * - line.8
  38. - Mulberry Street
  39. - local-road
  40. * - line.9
  41. - Nathan Lane
  42. - local-road
  43. * - line.10
  44. - Central Street
  45. - local-road
  46. * - line.11
  47. - Lois Lane
  48. - local-road
  49. * - line.12
  50. - Rocky Road
  51. - local-road
  52. * - line.13
  53. - Fleet Street
  54. - local-road
  55. * - line.14
  56. - Diane Court
  57. - local-road
  58. * - line.15
  59. - Cedar Trail
  60. - local-road
  61. * - line.16
  62. - Victory Road
  63. - local-road
  64. * - line.17
  65. - Highland Road
  66. - local-road
  67. * - line.18
  68. - Easy Street
  69. - local-road
  70. * - line.19
  71. - Hill Street
  72. - local-road
  73. * - line.20
  74. - Country Road
  75. - local-road
  76. * - line.21
  77. - Main Street
  78. - local-road
  79. * - line.22
  80. - Jani Lane
  81. - local-road
  82. * - line.23
  83. - Shinbone Alley
  84. - local-road
  85. * - line.24
  86. - State Street
  87. - local-road
  88. * - line.25
  89. - River Road
  90. - local-road
  91. :download:`Download the lines shapefile <../../sld/cookbook/artifacts/sld_cookbook_line.zip>`
  92. .. _css_cookbook_lines_simpleline:
  93. Simple line
  94. -----------
  95. This example specifies lines be colored black with a thickness of 3 pixels.
  96. .. figure:: ../../sld/cookbook/images/line_simpleline.png
  97. :align: center
  98. *Simple line*
  99. Code
  100. ~~~~
  101. .. code-block:: css
  102. :linenos:
  103. * {
  104. stroke: black;
  105. stroke-width: 3px;
  106. }
  107. Details
  108. ~~~~~~~
  109. The only rule asks for a black stroke (this attribute is mandatory to get strokes to actually show up), 3 pixels wide.
  110. Line with border
  111. ----------------
  112. This example shows how to draw lines with borders (sometimes called "cased lines").
  113. In this case the lines are drawn with a 3 pixel blue center and a 1 pixel wide gray border.
  114. .. figure:: ../../sld/cookbook/images/line_linewithborder.png
  115. :align: center
  116. *Line with border*
  117. Code
  118. ~~~~
  119. .. code-block:: css
  120. :linenos:
  121. * {
  122. stroke: #333333, #6699FF;
  123. stroke-width: 5px, 3px;
  124. stroke-linecap: round;
  125. z-index: 0, 1;
  126. }
  127. Details
  128. ~~~~~~~
  129. Lines in CSS have no notion of a "fill", only "stroke". Thus, unlike points or polygons, it is not possible to style the
  130. "edge" of the line geometry. It is, however, possible to achieve this effect by drawing each line twice: once with a
  131. certain width and again with a slightly smaller width. This gives the illusion of fill and stroke by obscuring the
  132. larger lines everywhere except along the edges of the smaller lines.
  133. The style uses the "multi-valued properties" CSS support by specifying two strokes and two stroke-widths.
  134. This causes each feature to be painted twice, first with a dark gray (``#333333``) line 5 pixels wide, and then a thinner
  135. blue (``#6699FF``) line 3 pixels wide.
  136. Since every line is drawn twice, the order of the rendering is *very* important.
  137. Without the z-index indication, each feature would first draw the gray stroke and then the blue one, and then the rendering engine
  138. would move to the next feature, and so on. This would result in ugly overlaps when lines do cross.
  139. By using the z-index property (**Line 3**) instead, all gray lines will be painted first, and then all blue lines will painted on top,
  140. thus making sure the blue lines visually connect.
  141. The "stroke-linecap" property is the only one having a single value, this is because the value is the same for both the gray and blue line.
  142. The result is a 3 pixel blue line with a 1 pixel gray border, since the 5 pixel gray line will display 1 pixel on each
  143. side of the 3 pixel blue line.
  144. Dashed line
  145. -----------
  146. This example alters the :ref:`css_cookbook_lines_simpleline` to create a dashed line consisting of 5 pixels of drawn
  147. line alternating with 2 pixels of blank space.
  148. .. figure:: ../../sld/cookbook/images/line_dashedline.png
  149. :align: center
  150. *Dashed line*
  151. Code
  152. ~~~~
  153. .. code-block:: css
  154. :linenos:
  155. * {
  156. stroke: blue;
  157. stroke-width: 3px;
  158. stroke-dasharray: 5 2;
  159. }
  160. Details
  161. ~~~~~~~
  162. In this example the we create a blue line, 3 pixels wide, and specify a dash array with value "5 2", which creates a
  163. repeating pattern of 5 pixels of drawn line, followed by 2 pixels of omitted line.
  164. Railroad (hatching)
  165. -------------------
  166. This example uses hatching to create a railroad style. Both the line and the hatches are black, with a 2 pixel
  167. thickness for the main line and a 1 pixel width for the perpendicular hatches.
  168. .. figure:: ../../sld/cookbook/images/line_railroad.png
  169. :align: center
  170. *Railroad (hatching)*
  171. Code
  172. ~~~~
  173. .. code-block:: scss
  174. :linenos:
  175. * {
  176. stroke: #333333, symbol("shape://vertline");
  177. stroke-width: 3px;
  178. :nth-stroke(2) {
  179. size: 12;
  180. stroke: #333333;
  181. stroke-width: 1px;
  182. }
  183. }
  184. Details
  185. ~~~~~~~
  186. In this example a multi-valued stroke is used: the fist value makes the renderer paint a dark gray line (3 pixels wide, according to the "stroke-width" attribute),
  187. whilst the second value makes the line be painted by repeating the "shape://vertline" symbol over and over, creating the hatching effect.
  188. In order to specify how the symbol itself should be painted, the ":nth-stroke(2)" pseudo-selector is used at **Line 4** to specify the options for the repeated symbol:
  189. in particular with are instructing the renderer to create a 12px wide symbol, with a dark gray stroke 1 pixel wide.
  190. Spaced graphic symbols
  191. ----------------------
  192. This example uses a graphic stroke along with dash arrays to create a "dot and space" line type.
  193. Adding the dash array specification allows to control the amount of space between one symbol and the next one.
  194. Without using the dash array the lines would be densely populated with dots, each one touching the previous one.
  195. .. figure:: ../../sld/cookbook/images/line_dashspace.png
  196. :align: center
  197. *Spaced symbols along a line*
  198. Code
  199. ~~~~
  200. .. code-block:: scss
  201. :linenos:
  202. * {
  203. stroke: symbol(circle);
  204. stroke-dasharray: 4 6;
  205. :stroke {
  206. size: 4;
  207. fill: #666666;
  208. stroke: #333333;
  209. stroke-width: 1px;
  210. }
  211. }
  212. Details
  213. ~~~~~~~
  214. This example, like others before, uses ``symbol(circle)`` to place a graphic symbol along a line.
  215. The symbol details are specified in the nested rule at **Line 4** using
  216. the ":stroke" pseudo-selector, creating a gray fill circle, 4 pixels wide, with a dark gray outline.
  217. The spacing between symbols is controlled with the ``stroke-dasharray`` at **line 3**, which specifies 4 pixels of pen-down (just enough to draw the circle) and 6 pixels of pen-up,
  218. to provide the spacing.
  219. .. _css_cookbook_lines_dashoffset:
  220. Alternating symbols with dash offsets
  221. -------------------------------------
  222. This example shows how to create a complex line style which alternates a dashed line and a graphic symbol.
  223. The code builds on features shown in the previous examples:
  224. * ``stroke-dasharray`` controls pen-down/pen-up behavior to generate dashed lines
  225. * ``symbol(...)`` places symbols along a line combining the two allows control of symbol spacing
  226. This also shows the usage of a `dash offset`, which controls where rendering starts
  227. in the dash array.
  228. For example, with a dash array of ``5 10`` and a dash offset of ``7`` the
  229. renderer starts drawing the pattern 7 pixels from the beginning. It skips the 5 pixels pen-down
  230. section and 2 pixels of the pen-up section, then draws the remaining 8 pixels of pen-up, then 5 down, 10 up, and so on.
  231. The example shows how to use these features to create two synchronized sequences of dash arrays,
  232. one drawing line segments and the other symbols.
  233. .. figure:: ../../sld/cookbook/images/line_dashdot.png
  234. :align: center
  235. *Alternating dash and symbol*
  236. Code
  237. ~~~~
  238. .. code-block:: scss
  239. :linenos:
  240. * {
  241. stroke: blue, symbol(circle);
  242. stroke-width: 1px;
  243. stroke-dasharray: 10 10, 5 15;
  244. stroke-dashoffset: 0, 7.5;
  245. :nth-stroke(2) {
  246. stroke: #000033;
  247. stroke-width: 1px;
  248. size: 5px;
  249. }
  250. }
  251. Details
  252. ~~~~~~~
  253. | This example uses again multi-valued properties to create two subsequent strokes applied to the same lines.
  254. | The first stroke is a solid blue line, 1 pixel wide, with a dash array of "10 10".
  255. | The second one instead is a repeated circle, using a dash array of "5 15" and with a dash offset of 7.5. This makes the sequence start with 12.5 pixels of white space, then a circle (which is then centered between the two line segments of the other pattern), then 15 pixels of white space, and so on.
  256. The circle portrayal details are specified using the pseudo selector "nth-stroke(2)" at **line 6**, asking for circles that
  257. are 5 pixels wide, not filled, and with a dark blue outline.
  258. .. _css_cookbook_lines_defaultlabel:
  259. Line with default label
  260. -----------------------
  261. This example shows a text label on the simple line. This is how a label will be displayed in the absence of any other
  262. customization.
  263. .. figure:: ../../sld/cookbook/images/line_linewithdefaultlabel.png
  264. :align: center
  265. *Line with default label*
  266. Code
  267. ~~~~
  268. .. code-block:: css
  269. :linenos:
  270. * {
  271. stroke: red;
  272. label: [name];
  273. font-fill: black;
  274. }
  275. Details
  276. ~~~~~~~
  277. This example paints lines with a red stroke, and then adds horizontal black labels at the center of the line, using the "name" attribute to fill the label.
  278. .. _css_cookbook_lines_perpendicularlabel:
  279. Labels along line with perpendicular offset
  280. -------------------------------------------
  281. This example shows a text label on the simple line, just like the previous example, but will force the label to be parallel to the lines, and will offset them a few pixels away.
  282. .. figure:: ../../sld/cookbook/images/line_labelwithoffset.png
  283. :align: center
  284. *Line with default label*
  285. Code
  286. ~~~~
  287. .. code-block:: css
  288. :linenos:
  289. * {
  290. stroke: red;
  291. label: [name];
  292. label-offset: 7px;
  293. font-fill: black;
  294. }
  295. Details
  296. ~~~~~~~
  297. This example is line by line identical to the previous one, but it add a new attribute "label-offset", which in the case of lines, when having a single value, is interpreted as a perpendicular
  298. offset from the line. The label is painted along a straight line, parallel to the line orientation in the center point of the label.
  299. .. _css_cookbook_lines_labelfollowingline:
  300. Label following line
  301. --------------------
  302. This example renders the text label to follow the contour of the lines.
  303. .. figure:: ../../sld/cookbook/images/line_labelfollowingline.png
  304. :align: center
  305. *Label following line*
  306. Code
  307. ~~~~
  308. .. code-block:: css
  309. :linenos:
  310. * {
  311. stroke: red;
  312. label: [name];
  313. font-fill: black;
  314. label-follow-line: true;
  315. }
  316. Details
  317. ~~~~~~~
  318. As the :ref:`css_cookbook_lines_defaultlabel` example showed, the default label behavior isn't optimal.
  319. This example is similar to the :ref:`css_cookbook_lines_defaultlabel` example with the exception of **line 5** where the
  320. "label-follow-line" option is specified, which forces the labels to strickly follow the line.
  321. Not all labels are visible partly because of conflict resolution, and partly because the renderer cannot find a line
  322. segment long and "straight" enough to paint the label (labels are not painted over sharp turns by default).
  323. .. _css_cookbook_lines_optimizedlabel:
  324. Optimized label placement
  325. -------------------------
  326. This example optimizes label placement for lines such that the maximum number of labels are displayed.
  327. .. figure:: ../../sld/cookbook/images/line_optimizedlabel.png
  328. :align: center
  329. *Optimized label*
  330. Code
  331. ~~~~
  332. .. code-block:: css
  333. :linenos:
  334. * {
  335. stroke: red;
  336. label: [name];
  337. font-fill: black;
  338. label-follow-line: true;
  339. label-max-angle-delta: 90;
  340. label-max-displacement: 400;
  341. label-repeat: 150;
  342. }
  343. Details
  344. ~~~~~~~
  345. This example is similar to the previous example, :ref:`css_cookbook_lines_labelfollowingline`. The only differences are contained in **lines 6-8**. **Line 6** sets the maximum angle that the label will follow. This sets the label to never bend more than 90 degrees to prevent the label from becoming illegible due to a pronounced curve or angle. **Line 7** sets the maximum displacement of the label to be 400 pixels. In order to resolve conflicts with overlapping labels, GeoServer will attempt to move the labels such that they are no longer overlapping. This value sets how far the label can be moved relative to its original placement. Finally, **line 8** sets the labels to be repeated every 150 pixels. A feature will typically receive only one label, but this can cause confusion for long lines. Setting the label to repeat ensures that the line is always labeled locally.
  346. .. _css_cookbook_lines_optimizedstyledlabel:
  347. Optimized and styled label
  348. --------------------------
  349. This example improves the style of the labels from the :ref:`css_cookbook_lines_optimizedlabel` example.
  350. .. figure:: ../../sld/cookbook/images/line_optimizedstyledlabel_with_halo.png
  351. :align: center
  352. *Optimized and styled label*
  353. Code
  354. ~~~~
  355. .. code-block:: css
  356. :linenos:
  357. * {
  358. stroke: red;
  359. label: [name];
  360. font-family: Arial;
  361. font-weight: bold;
  362. font-fill: black;
  363. font-size: 10;
  364. halo-color: white;
  365. halo-radius: 1;
  366. label-follow-line: true;
  367. label-max-angle-delta: 90;
  368. label-max-displacement: 400;
  369. label-repeat: 150;
  370. }
  371. Details
  372. ~~~~~~~
  373. This example is similar to the :ref:`css_cookbook_lines_optimizedlabel`. The only differences are:
  374. * The font family and weight have been specified
  375. * In order to make the labels easier to read, a white "halo" has been added. The halo draws a thin 1 pixel white border around the text, making it stand out from the background.
  376. Attribute-based line
  377. --------------------
  378. This example styles the lines differently based on the "type" (Road class) attribute.
  379. .. figure:: ../../sld/cookbook/images/line_attributebasedline.png
  380. :align: center
  381. *Attribute-based line*
  382. Code
  383. ~~~~
  384. .. code-block:: css
  385. :linenos:
  386. [type = 'local-road'] {
  387. stroke: #009933;
  388. stroke-width: 2;
  389. z-index: 0;
  390. }
  391. [type = 'secondary'] {
  392. stroke: #0055CC;
  393. stroke-width: 3;
  394. z-index: 1;
  395. }
  396. [type = 'highway'] {
  397. stroke: #FF0000;
  398. stroke-width: 6;
  399. z-index: 2;
  400. }
  401. Details
  402. ~~~~~~~
  403. .. note:: Refer to the :ref:`css_cookbook_lines_attributes` to see the attributes for the layer. This example has eschewed labels in order to simplify the style, but you can refer to the example :ref:`css_cookbook_lines_optimizedstyledlabel` to see which attributes correspond to which points.
  404. There are three types of road classes in our fictional country, ranging from back roads to high-speed freeways:
  405. "highway", "secondary", and "local-road". In order to make sure the roads are rendered in the proper order of importance, a "z-index" attribute has been placed in each rule.
  406. The three rules are designed as follows:
  407. .. list-table::
  408. :widths: 20 30 30 20
  409. * - **Rule order**
  410. - **Rule name / type**
  411. - **Color**
  412. - **Size**
  413. * - 1
  414. - local-road
  415. - ``#009933`` (green)
  416. - 2
  417. * - 2
  418. - secondary
  419. - ``#0055CC`` (blue)
  420. - 3
  421. * - 3
  422. - highway
  423. - ``#FF0000`` (red)
  424. - 6
  425. **Lines 1-5** comprise the first rule, the filter matches all roads that the "type" attribute has a value of "local-road". If this condition is true for a particular line, the rule renders it dark green, 2 pixels wide. All these lines are rendered first, and thus sit at the bottom of the final map.
  426. **Lines 7-11** match the "secondary" roads, painting them dark blue, 3 pixels wide. Given the "z-index" is 1, they are rendered after the local roads, but below the highways.
  427. **Lines 13-17** match the "highway" roads, painting them red 6 pixels wide. These roads are pained last, thus, on top of all others.
  428. Zoom-based line
  429. ---------------
  430. This example alters the :ref:`css_cookbook_lines_simpleline` style at different zoom levels.
  431. .. figure:: ../../sld/cookbook/images/line_zoombasedlinelarge.png
  432. :align: center
  433. *Zoom-based line: Zoomed in*
  434. .. figure:: ../../sld/cookbook/images/line_zoombasedlinemedium.png
  435. :align: center
  436. *Zoom-based line: Partially zoomed*
  437. .. figure:: ../../sld/cookbook/images/line_zoombasedlinesmall.png
  438. :align: center
  439. *Zoom-based line: Zoomed out*
  440. Code
  441. ~~~~
  442. .. code-block:: css
  443. :linenos:
  444. * {
  445. stroke: #009933;
  446. }
  447. [@sd < 180M] {
  448. stroke-width: 6;
  449. }
  450. [@sd > 180M] [@sd < 360M] {
  451. stroke-width: 4;
  452. }
  453. [@sd > 360M] {
  454. stroke-width: 2;
  455. }
  456. Details
  457. ~~~~~~~
  458. It is often desirable to make shapes larger at higher zoom levels when creating a natural-looking map. This example
  459. varies the thickness of the lines according to the zoom level (or more accurately, scale denominator). Scale
  460. denominators refer to the scale of the map. A scale denominator of 10,000 means the map has a scale of 1:10,000 in the
  461. units of the map projection.
  462. .. note:: Determining the appropriate scale denominators (zoom levels) to use is beyond the scope of this example.
  463. This style contains three rules. The three rules are designed as follows:
  464. .. list-table::
  465. :widths: 15 25 40 20
  466. * - **Rule order**
  467. - **Rule name**
  468. - **Scale denominator**
  469. - **Line width**
  470. * - 1
  471. - Large
  472. - 1:180,000,000 or less
  473. - 6
  474. * - 2
  475. - Medium
  476. - 1:180,000,000 to 1:360,000,000
  477. - 4
  478. * - 3
  479. - Small
  480. - Greater than 1:360,000,000
  481. - 2
  482. The order of these rules does not matter since the scales denominated in each rule do not overlap.
  483. The first rule provides the stroke color used at all zoom levels, dark gray, while the other three rules cascade over it applying the different stroke widths based on the current zoom level leveraging the "@sd" pseudo attribute. The "@sd" pseudo attribute can only be compared using the "<" and ">" operators, using any other operator will result in errors.
  484. The result of this style is that lines are drawn with larger widths as one zooms in and smaller widths as one zooms out.