diff options
| author | Felix E. Klee | 2019-07-15 17:07:56 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2019-07-15 17:07:56 +0200 |
| commit | d6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3 (patch) | |
| tree | 47e633d687d0bda97e8613c57bed4ab816e55d44 | |
| parent | 3b6992118501d0a17b6817a91011f8e8dcdf8164 (diff) | |
| download | emacs-d6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3.tar.gz emacs-d6bc55ae2dc98c83e58a28e380ce4bcf2ed00bb3.zip | |
Add support for paths to svg.el
* doc/lispref/display.texi (SVG Images): Document svg-path,
svg-clip-path and svg-node (bug#32359).
* doc/lispref/display.texi (SVG Path Commands): New node.
* lisp/svg.el (svg--plist-delete, svg--path-command-symbol)
(svg--elliptical-arc-coordinates, svg--elliptical-arc-command)
(svg--moveto-command, svg--closepath-command)
(svg--lineto-command, svg--horizontal-lineto-command)
(svg--vertical-lineto-command, svg--curveto-command)
(svg--smooth-curveto-command)
(svg--quadratic-bezier-curveto-command)
(svg--smooth-quadratic-bezier-curveto-command)
(svg--eval-path-command, svg-path, svg-clip-path, svg-node): New
functions.
| -rw-r--r-- | doc/lispref/display.texi | 237 | ||||
| -rw-r--r-- | lisp/svg.el | 148 |
2 files changed, 385 insertions, 0 deletions
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index a38569f7263..ecaf2e054e0 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi | |||
| @@ -5587,6 +5587,9 @@ The identified of the shape. | |||
| 5587 | @item :gradient | 5587 | @item :gradient |
| 5588 | If given, this should be the identifier of a previously defined | 5588 | If given, this should be the identifier of a previously defined |
| 5589 | gradient object. | 5589 | gradient object. |
| 5590 | |||
| 5591 | @item :clip-path | ||
| 5592 | Identifier of a clip path. | ||
| 5590 | @end table | 5593 | @end table |
| 5591 | 5594 | ||
| 5592 | @defun svg-rectangle svg x y width height &rest args | 5595 | @defun svg-rectangle svg x y width height &rest args |
| @@ -5634,6 +5637,29 @@ that describe the outer circumference of the polygon. | |||
| 5634 | @end lisp | 5637 | @end lisp |
| 5635 | @end defun | 5638 | @end defun |
| 5636 | 5639 | ||
| 5640 | @defun svg-path svg commands &rest args | ||
| 5641 | Add the outline of a shape to @var{svg} according to @var{commands}, | ||
| 5642 | see @ref{SVG Path Commands}. | ||
| 5643 | |||
| 5644 | Coordinates by default are absolute. To use coordinates relative to | ||
| 5645 | the last position, or -- initially -- to the origin, set the attribute | ||
| 5646 | @var{:relative} to @code{t}. This attribute can be specified for the | ||
| 5647 | function or for individual commands. If specified for the function, | ||
| 5648 | then all commands use relative coordinates by default. To make an | ||
| 5649 | individual command use absolute coordinates, set @var{:relative} to | ||
| 5650 | @code{nil}. | ||
| 5651 | |||
| 5652 | @lisp | ||
| 5653 | (svg-path svg | ||
| 5654 | '((moveto ((100 . 100))) | ||
| 5655 | (lineto ((200 . 0) (0 . 200) (-200 . 0))) | ||
| 5656 | (lineto ((100 . 100)) :relative nil)) | ||
| 5657 | :stroke-color "blue" | ||
| 5658 | :fill-color "lightblue" | ||
| 5659 | :relative t) | ||
| 5660 | @end lisp | ||
| 5661 | @end defun | ||
| 5662 | |||
| 5637 | @defun svg-text svg text &rest args | 5663 | @defun svg-text svg text &rest args |
| 5638 | Add the specified @var{text} to @var{svg}. | 5664 | Add the specified @var{text} to @var{svg}. |
| 5639 | 5665 | ||
| @@ -5665,6 +5691,30 @@ string containing the image data as raw bytes. @var{image-type} should be a | |||
| 5665 | @end lisp | 5691 | @end lisp |
| 5666 | @end defun | 5692 | @end defun |
| 5667 | 5693 | ||
| 5694 | @defun svg-clip-path svg &rest args | ||
| 5695 | Add a clipping path to @var{svg}. If applied to a shape via the | ||
| 5696 | @var{:clip-path} property, parts of that shape which lie outside of | ||
| 5697 | the clipping path are not drawn. | ||
| 5698 | |||
| 5699 | @lisp | ||
| 5700 | (let ((clip-path (svg-clip-path svg :id "foo"))) | ||
| 5701 | (svg-circle clip-path 200 200 175)) | ||
| 5702 | (svg-rectangle svg 50 50 300 300 | ||
| 5703 | :fill-color "red" | ||
| 5704 | :clip-path "url(#foo)") | ||
| 5705 | @end lisp | ||
| 5706 | @end defun | ||
| 5707 | |||
| 5708 | @defun svg-node svg tag &rest args | ||
| 5709 | Add the custom node @var{tag} to @var{svg}. | ||
| 5710 | |||
| 5711 | @lisp | ||
| 5712 | (svg-node svg | ||
| 5713 | 'rect | ||
| 5714 | :width 300 :height 200 :x 50 :y 100 :fill-color "green") | ||
| 5715 | @end lisp | ||
| 5716 | @end defun | ||
| 5717 | |||
| 5668 | @defun svg-remove svg id | 5718 | @defun svg-remove svg id |
| 5669 | Remove the element with identifier @code{id} from the @code{svg}. | 5719 | Remove the element with identifier @code{id} from the @code{svg}. |
| 5670 | @end defun | 5720 | @end defun |
| @@ -5687,6 +5737,193 @@ circle: | |||
| 5687 | @end lisp | 5737 | @end lisp |
| 5688 | 5738 | ||
| 5689 | 5739 | ||
| 5740 | @node SVG Path Commands | ||
| 5741 | @subsubsection SVG Path Commands | ||
| 5742 | |||
| 5743 | @deffn Command moveto points | ||
| 5744 | Move the pen to the first point in @var{points}. Additional points | ||
| 5745 | are connected with lines. @var{points} is a list of X/Y coordinate | ||
| 5746 | pairs. Subsequent @command{moveto} commands represent the start of a | ||
| 5747 | new @dfn{subpath}. | ||
| 5748 | |||
| 5749 | @lisp | ||
| 5750 | (svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100)))) | ||
| 5751 | :fill "white" :stroke "black") | ||
| 5752 | @end lisp | ||
| 5753 | @end deffn | ||
| 5754 | |||
| 5755 | @deffn Command closepath | ||
| 5756 | End the current subpath by connecting it back to its initial point. A | ||
| 5757 | line is drawn along the connection. | ||
| 5758 | |||
| 5759 | @lisp | ||
| 5760 | (svg-path svg '((moveto ((200 . 100) (100 . 200) (0 . 100))) | ||
| 5761 | (closepath) | ||
| 5762 | (moveto ((75 . 125) (100 . 150) (125 . 125))) | ||
| 5763 | (closepath)) | ||
| 5764 | :fill "red" :stroke "black") | ||
| 5765 | @end lisp | ||
| 5766 | @end deffn | ||
| 5767 | |||
| 5768 | @deffn Command lineto points | ||
| 5769 | Draw a line from the current point to the first element in | ||
| 5770 | @var{points}, a list of X/Y position pairs. If more than one point is | ||
| 5771 | specified, draw a polyline. | ||
| 5772 | @lisp | ||
| 5773 | (svg-path svg '((moveto ((200 . 100))) | ||
| 5774 | (lineto ((100 . 200) (0 . 100)))) | ||
| 5775 | :fill "yellow" :stroke "red") | ||
| 5776 | @end lisp | ||
| 5777 | @end deffn | ||
| 5778 | |||
| 5779 | @deffn Command horizontal-lineto x-coordinates | ||
| 5780 | Draw a horizontal line from the current point to the first element in | ||
| 5781 | @var{x-coordinates}. Specifying multiple coordinates is possible, | ||
| 5782 | although usually this doesn’t make sense. | ||
| 5783 | |||
| 5784 | @lisp | ||
| 5785 | (svg-path svg '((moveto ((100 . 200))) | ||
| 5786 | (horizontal-lineto (300))) | ||
| 5787 | :stroke "green") | ||
| 5788 | @end lisp | ||
| 5789 | @end deffn | ||
| 5790 | |||
| 5791 | @deffn Command vertical-lineto y-coordinates | ||
| 5792 | Draw vertical lines. | ||
| 5793 | |||
| 5794 | @lisp | ||
| 5795 | (svg-path svg '((moveto ((200 . 100))) | ||
| 5796 | (vertical-lineto (300))) | ||
| 5797 | :stroke "green") | ||
| 5798 | @end lisp | ||
| 5799 | @end deffn | ||
| 5800 | |||
| 5801 | @deffn Command curveto coordinate-sets | ||
| 5802 | Using the first element in @var{coordinate-sets}, draw a cubic Bézier | ||
| 5803 | curve from the current point. If there are multiple coordinate sets, | ||
| 5804 | draw a polybézier. Each coordinate set is a list of the form | ||
| 5805 | @code{(@var{x1} @var{y1} @var{x2} @var{y2} @var{x} @var{y})}, where | ||
| 5806 | @w{(@var{x}, @var{y})} is the curve’s end point. @w{(@var{x1}, | ||
| 5807 | @var{y1})} and @w{(@var{x2}, @var{y2})} are control points at the | ||
| 5808 | beginning and at the end, respectively. | ||
| 5809 | |||
| 5810 | @lisp | ||
| 5811 | (svg-path svg '((moveto ((100 . 100))) | ||
| 5812 | (curveto ((200 100 100 200 200 200) | ||
| 5813 | (300 200 0 100 100 100)))) | ||
| 5814 | :fill "transparent" :stroke "red") | ||
| 5815 | @end lisp | ||
| 5816 | @end deffn | ||
| 5817 | |||
| 5818 | @deffn Command smooth-curveto coordinate-sets | ||
| 5819 | Using the first element in @var{coordinate-sets}, draw a cubic Bézier | ||
| 5820 | curve from the current point. If there are multiple coordinate sets, | ||
| 5821 | draw a polybézier. Each coordinate set is a list of the form | ||
| 5822 | @code{(@var{x2} @var{y2} @var{x} @var{y})}, where @w{(@var{x}, | ||
| 5823 | @var{y})} is the curve’s end point and @w{(@var{x2}, @var{y2})} is the | ||
| 5824 | corresponding control point. The first control point is the | ||
| 5825 | reflection of the second control point of the previous command | ||
| 5826 | relative to the current point, if that command was @command{curveto} | ||
| 5827 | or @command{smooth-curveto}. Otherwise the first control point | ||
| 5828 | coincides with the current point. | ||
| 5829 | |||
| 5830 | @lisp | ||
| 5831 | (svg-path svg '((moveto ((100 . 100))) | ||
| 5832 | (curveto ((200 100 100 200 200 200))) | ||
| 5833 | (smooth-curveto ((0 100 100 100)))) | ||
| 5834 | :fill "transparent" :stroke "blue") | ||
| 5835 | @end lisp | ||
| 5836 | @end deffn | ||
| 5837 | |||
| 5838 | @deffn Command quadratic-bezier-curveto coordinate-sets | ||
| 5839 | Using the first element in @var{coordinate-sets}, draw a quadratic | ||
| 5840 | Bézier curve from the current point. If there are multiple coordinate | ||
| 5841 | sets, draw a polybézier. Each coordinate set is a list of the form | ||
| 5842 | @code{(@var{x1} @var{y1} @var{x} @var{y})}, where @w{(@var{x}, | ||
| 5843 | @var{y})} is the curve’s end point and @w{(@var{x1}, @var{y1})} is the | ||
| 5844 | control point. | ||
| 5845 | |||
| 5846 | @lisp | ||
| 5847 | (svg-path svg '((moveto ((200 . 100))) | ||
| 5848 | (quadratic-bezier-curveto ((300 100 300 200))) | ||
| 5849 | (quadratic-bezier-curveto ((300 300 200 300))) | ||
| 5850 | (quadratic-bezier-curveto ((100 300 100 200))) | ||
| 5851 | (quadratic-bezier-curveto ((100 100 200 100)))) | ||
| 5852 | :fill "transparent" :stroke "pink") | ||
| 5853 | @end lisp | ||
| 5854 | @end deffn | ||
| 5855 | |||
| 5856 | @deffn Command smooth-quadratic-bezier-curveto coordinate-sets | ||
| 5857 | Using the first element in @var{coordinate-sets}, draw a quadratic | ||
| 5858 | Bézier curve from the current point. If there are multiple coordinate | ||
| 5859 | sets, draw a polybézier. Each coordinate set is a list of the form | ||
| 5860 | @code{(@var{x} @var{y})}, where @w{(@var{x}, @var{y})} is the curve’s | ||
| 5861 | end point. The control point is the reflection of the control point | ||
| 5862 | of the previous command relative to the current point, if that command | ||
| 5863 | was @command{quadratic-bezier-curveto} or | ||
| 5864 | @command{smooth-quadratic-bezier-curveto}. Otherwise the control | ||
| 5865 | point coincides with the current point. | ||
| 5866 | |||
| 5867 | @lisp | ||
| 5868 | (svg-path svg '((moveto ((200 . 100))) | ||
| 5869 | (quadratic-bezier-curveto ((300 100 300 200))) | ||
| 5870 | (smooth-quadratic-bezier-curveto ((200 300))) | ||
| 5871 | (smooth-quadratic-bezier-curveto ((100 200))) | ||
| 5872 | (smooth-quadratic-bezier-curveto ((200 100)))) | ||
| 5873 | :fill "transparent" :stroke "lightblue") | ||
| 5874 | @end lisp | ||
| 5875 | @end deffn | ||
| 5876 | |||
| 5877 | @deffn Command elliptical-arc coordinate-sets | ||
| 5878 | Using the first element in @var{coordinate-sets}, draw an elliptical | ||
| 5879 | arc from the current point. If there are multiple coordinate sets, | ||
| 5880 | draw a sequence of elliptical arcs. Each coordinate set is a list of | ||
| 5881 | the form @code{(@var{rx} @var{ry} @var{x} @var{y})}, where | ||
| 5882 | @w{(@var{x}, @var{y})} is the end point of the ellipse, and | ||
| 5883 | @w{(@var{rx}, @var{ry})} are its radii. Attributes may be appended to | ||
| 5884 | the list: | ||
| 5885 | |||
| 5886 | @table @code | ||
| 5887 | @item :x-axis-rotation | ||
| 5888 | The angle in degrees by which the x-axis of the ellipse is rotated | ||
| 5889 | relative to the x-axis of the current coordinate system. | ||
| 5890 | |||
| 5891 | @item :large-arc | ||
| 5892 | If set to @code{t}, draw an arc sweep greater than or equal to 180 | ||
| 5893 | degrees. Otherwise, draw an arc sweep smaller than or equal to 180 | ||
| 5894 | degrees. | ||
| 5895 | |||
| 5896 | @item :sweep | ||
| 5897 | If set to @code{t}, draw an arc in @dfn{positive angle direction}. | ||
| 5898 | Otherwise, draw it in @dfn{negative angle direction}. | ||
| 5899 | @end table | ||
| 5900 | |||
| 5901 | @lisp | ||
| 5902 | (svg-path svg '((moveto ((200 . 250))) | ||
| 5903 | (elliptical-arc ((75 75 200 350)))) | ||
| 5904 | :fill "transparent" :stroke "red") | ||
| 5905 | (svg-path svg '((moveto ((200 . 250))) | ||
| 5906 | (elliptical-arc ((75 75 200 350 :large-arc t)))) | ||
| 5907 | :fill "transparent" :stroke "green") | ||
| 5908 | (svg-path svg '((moveto ((200 . 250))) | ||
| 5909 | (elliptical-arc ((75 75 200 350 :sweep t)))) | ||
| 5910 | :fill "transparent" :stroke "blue") | ||
| 5911 | (svg-path svg '((moveto ((200 . 250))) | ||
| 5912 | (elliptical-arc ((75 75 200 350 :large-arc t | ||
| 5913 | :sweep t)))) | ||
| 5914 | :fill "transparent" :stroke "gray") | ||
| 5915 | (svg-path svg '((moveto ((160 . 100))) | ||
| 5916 | (elliptical-arc ((40 100 80 0))) | ||
| 5917 | (elliptical-arc ((40 100 -40 -70 | ||
| 5918 | :x-axis-rotation -120))) | ||
| 5919 | (elliptical-arc ((40 100 -40 70 | ||
| 5920 | :x-axis-rotation -240)))) | ||
| 5921 | :stroke "pink" :fill "lightblue" | ||
| 5922 | :relative t) | ||
| 5923 | @end lisp | ||
| 5924 | @end deffn | ||
| 5925 | |||
| 5926 | |||
| 5690 | @node Other Image Types | 5927 | @node Other Image Types |
| 5691 | @subsection Other Image Types | 5928 | @subsection Other Image Types |
| 5692 | @cindex PBM | 5929 | @cindex PBM |
diff --git a/lisp/svg.el b/lisp/svg.el index 86b56a03d56..2ab56d3960d 100644 --- a/lisp/svg.el +++ b/lisp/svg.el | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | ;; Copyright (C) 2014-2019 Free Software Foundation, Inc. | 3 | ;; Copyright (C) 2014-2019 Free Software Foundation, Inc. |
| 4 | 4 | ||
| 5 | ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> | 5 | ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org> |
| 6 | ;; Felix E. Klee <felix.klee@inka.de> | ||
| 6 | ;; Keywords: image | 7 | ;; Keywords: image |
| 7 | ;; Version: 1.0 | 8 | ;; Version: 1.0 |
| 8 | ;; Package-Requires: ((emacs "25")) | 9 | ;; Package-Requires: ((emacs "25")) |
| @@ -324,6 +325,153 @@ If the SVG is later changed, the image will also be updated." | |||
| 324 | "\\'"))))) | 325 | "\\'"))))) |
| 325 | (when node (dom-remove-node svg node)))) | 326 | (when node (dom-remove-node svg node)))) |
| 326 | 327 | ||
| 328 | ;; Function body copied from `org-plist-delete' in Emacs 26.1. | ||
| 329 | (defun svg--plist-delete (plist property) | ||
| 330 | "Delete PROPERTY from PLIST. | ||
| 331 | This is in contrast to merely setting it to 0." | ||
| 332 | (let (p) | ||
| 333 | (while plist | ||
| 334 | (if (not (eq property (car plist))) | ||
| 335 | (setq p (plist-put p (car plist) (nth 1 plist)))) | ||
| 336 | (setq plist (cddr plist))) | ||
| 337 | p)) | ||
| 338 | |||
| 339 | (defun svg--path-command-symbol (command-symbol command-args) | ||
| 340 | (let ((char (symbol-name command-symbol)) | ||
| 341 | (relative (if (plist-member command-args :relative) | ||
| 342 | (plist-get command-args :relative) | ||
| 343 | (plist-get command-args :default-relative)))) | ||
| 344 | (intern (if relative (downcase char) (upcase char))))) | ||
| 345 | |||
| 346 | (defun svg--elliptical-arc-coordinates | ||
| 347 | (rx ry x y &rest args) | ||
| 348 | (list | ||
| 349 | rx ry | ||
| 350 | (or (plist-get args :x-axis-rotation) 0) | ||
| 351 | (if (plist-get args :large-arc) 1 0) | ||
| 352 | (if (plist-get args :sweep) 1 0) | ||
| 353 | x y)) | ||
| 354 | |||
| 355 | (defun svg--elliptical-arc-command (coordinates-list &rest args) | ||
| 356 | (cons | ||
| 357 | (svg--path-command-symbol 'a args) | ||
| 358 | (apply 'append | ||
| 359 | (mapcar | ||
| 360 | (lambda (coordinates) | ||
| 361 | (apply 'svg--elliptical-arc-coordinates | ||
| 362 | coordinates)) | ||
| 363 | coordinates-list)))) | ||
| 364 | |||
| 365 | (defun svg--moveto-command (coordinates-list &rest args) | ||
| 366 | (cons | ||
| 367 | (svg--path-command-symbol 'm args) | ||
| 368 | (apply 'append | ||
| 369 | (mapcar | ||
| 370 | (lambda (coordinates) | ||
| 371 | (list (car coordinates) (cdr coordinates))) | ||
| 372 | coordinates-list)))) | ||
| 373 | |||
| 374 | (defun svg--closepath-command (&rest args) | ||
| 375 | (list (svg--path-command-symbol 'z args))) | ||
| 376 | |||
| 377 | (defun svg--lineto-command (coordinates-list &rest args) | ||
| 378 | (cons | ||
| 379 | (svg--path-command-symbol 'l args) | ||
| 380 | (apply 'append | ||
| 381 | (mapcar | ||
| 382 | (lambda (coordinates) | ||
| 383 | (list (car coordinates) (cdr coordinates))) | ||
| 384 | coordinates-list)))) | ||
| 385 | |||
| 386 | (defun svg--horizontal-lineto-command (coordinate-list &rest args) | ||
| 387 | (cons | ||
| 388 | (svg--path-command-symbol 'h args) | ||
| 389 | coordinate-list)) | ||
| 390 | |||
| 391 | (defun svg--vertical-lineto-command (coordinate-list &rest args) | ||
| 392 | (cons | ||
| 393 | (svg--path-command-symbol 'v args) | ||
| 394 | coordinate-list)) | ||
| 395 | |||
| 396 | (defun svg--curveto-command (coordinates-list &rest args) | ||
| 397 | (cons | ||
| 398 | (svg--path-command-symbol 'c args) | ||
| 399 | (apply 'append coordinates-list))) | ||
| 400 | |||
| 401 | (defun svg--smooth-curveto-command (coordinates-list &rest args) | ||
| 402 | (cons | ||
| 403 | (svg--path-command-symbol 's args) | ||
| 404 | (apply 'append coordinates-list))) | ||
| 405 | |||
| 406 | (defun svg--quadratic-bezier-curveto-command (coordinates-list | ||
| 407 | &rest args) | ||
| 408 | (cons | ||
| 409 | (svg--path-command-symbol 'q args) | ||
| 410 | (apply 'append coordinates-list))) | ||
| 411 | |||
| 412 | (defun svg--smooth-quadratic-bezier-curveto-command (coordinates-list | ||
| 413 | &rest args) | ||
| 414 | (cons | ||
| 415 | (svg--path-command-symbol 't args) | ||
| 416 | (apply 'append coordinates-list))) | ||
| 417 | |||
| 418 | (defun svg--eval-path-command (command default-relative) | ||
| 419 | (cl-letf | ||
| 420 | (((symbol-function 'moveto) #'svg--moveto-command) | ||
| 421 | ((symbol-function 'closepath) #'svg--closepath-command) | ||
| 422 | ((symbol-function 'lineto) #'svg--lineto-command) | ||
| 423 | ((symbol-function 'horizontal-lineto) | ||
| 424 | #'svg--horizontal-lineto-command) | ||
| 425 | ((symbol-function 'vertical-lineto) | ||
| 426 | #'svg--vertical-lineto-command) | ||
| 427 | ((symbol-function 'curveto) #'svg--curveto-command) | ||
| 428 | ((symbol-function 'smooth-curveto) | ||
| 429 | #'svg--smooth-curveto-command) | ||
| 430 | ((symbol-function 'quadratic-bezier-curveto) | ||
| 431 | #'svg--quadratic-bezier-curveto-command) | ||
| 432 | ((symbol-function 'smooth-quadratic-bezier-curveto) | ||
| 433 | #'svg--smooth-quadratic-bezier-curveto-command) | ||
| 434 | ((symbol-function 'elliptical-arc) | ||
| 435 | #'svg--elliptical-arc-command) | ||
| 436 | (extended-command (append command (list :default-relative | ||
| 437 | default-relative)))) | ||
| 438 | (mapconcat 'prin1-to-string (apply extended-command) " "))) | ||
| 439 | |||
| 440 | (defun svg-path (svg commands &rest args) | ||
| 441 | "Add the outline of a shape to SVG according to COMMANDS. | ||
| 442 | Coordinates by default are absolute. ARGS is a plist of | ||
| 443 | modifiers. If :relative is t, then coordinates are relative to | ||
| 444 | the last position, or -- initially -- to the origin." | ||
| 445 | (let* ((default-relative (plist-get args :relative)) | ||
| 446 | (stripped-args (svg--plist-delete args :relative)) | ||
| 447 | (d (mapconcat 'identity | ||
| 448 | (mapcar | ||
| 449 | (lambda (command) | ||
| 450 | (svg--eval-path-command command | ||
| 451 | default-relative)) | ||
| 452 | commands) " "))) | ||
| 453 | (svg--append | ||
| 454 | svg | ||
| 455 | (dom-node 'path | ||
| 456 | `((d . ,d) | ||
| 457 | ,@(svg--arguments svg stripped-args)))))) | ||
| 458 | |||
| 459 | (defun svg-clip-path (svg &rest args) | ||
| 460 | "Add a clipping path to SVG, where ARGS is a plist of modifiers. | ||
| 461 | If applied to a shape via the :clip-path property, parts of that | ||
| 462 | shape which lie outside of the clipping path are not drawn." | ||
| 463 | (let ((new-dom-node (dom-node 'clipPath | ||
| 464 | `(,@(svg--arguments svg args))))) | ||
| 465 | (svg--append svg new-dom-node) | ||
| 466 | new-dom-node)) | ||
| 467 | |||
| 468 | (defun svg-node (svg tag &rest args) | ||
| 469 | "Add the custom node TAG to SVG." | ||
| 470 | (let ((new-dom-node (dom-node tag | ||
| 471 | `(,@(svg--arguments svg args))))) | ||
| 472 | (svg--append svg new-dom-node) | ||
| 473 | new-dom-node)) | ||
| 474 | |||
| 327 | (provide 'svg) | 475 | (provide 'svg) |
| 328 | 476 | ||
| 329 | ;;; svg.el ends here | 477 | ;;; svg.el ends here |