Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
;; esvg-build.el. -*- lexical-binding: nil; -*-
;; This file:
;;   https://anggtwu.net/elisp/esvg-build.el.html
;;   https://anggtwu.net/elisp/esvg-build.el
;;           (find-angg "elisp/esvg-build.el")
;; Author: Eduardo Ochs <eduardoochs@gmail.com>
;; Version: 2026aug13
;;
;; This is the fourth lowest-level file in esvg - edrx's (REPL for) SVG.
;;
;; It implements my functions that build SVG objects. Note that
;; `svg-rectangle' builds an SVG object, calls `svg--append' to append
;; it to a certain top-level SVG object, and then runs
;; `svg-possibly-update-image'. In contrast, `esvg-rectangle' just
;; builds an SVG object; appending and updating the image are done
;; elsewhere.
;;
;; (defun e () (interactive) (find-angg "elisp/esvg-build.el"))
;; (defun o () (interactive) (find-angg "elisp/2026-esvg.el"))
;; (defun o () (interactive) (find-angg "elisp/2026-esvg-objects.el"))
;;
;; «.esvg-translate»		(to "esvg-translate")
;; «.esvg-flatten»		(to "esvg-flatten")
;; «.esvg-make-simple»		(to "esvg-make-simple")

(require 'esvg-show)		; (find-angg "elisp/esvg-show.el")
(require 'esvg-eepitch)		; (find-angg "elisp/esvg-eepitch.el")
(require 'esvg-append)		; (find-angg "elisp/esvg-append.el")



;; «esvg-translate»  (to ".esvg-translate")
;; Based on: (find-angg "elisp/2026-esvg.el" "esvg-translate")
;; Tests: (esvg-translate-1 '(:a 1 :b 2         foo  bar))
;;        (esvg-translate     :a 1 :b 2        'foo 'bar)
;;        (esvg-translate-el  :a 1 :b 2 '(:c 3  foo  bar))
;;
(defun esvg-translate-1 (list)
  (let (attrs)
    (while (keywordp (car list))
      (let* ((key (intern (substring (symbol-name (car list)) 1)))
	     (val (cadr list)))
	(push `(,key . ,val) attrs)
	(setq list (cddr list))))
    `(,(reverse attrs) ,@list)))

(defun esvg-expand-last  (list) (append (butlast list) (car (last list))))
(defun esvg-translate    (&rest args) (esvg-translate-1 args))
(defun esvg-translate-el (&rest args) (esvg-translate-1 (esvg-expand-last args)))


;; «esvg-flatten»  (to ".esvg-flatten")
;; svg.el expects the lists of points for polylines and polygons to be
;; lists of dotted pairs; here we also accepts other formats. See:
;;   (find-efile "svg.el" "(svg-polyline svg '((200 . 100) ")
;;   (find-efile "svg.el" "(defun svg-polyline " "mapconcat")
;;   (find-angg "elisp/2026-esvg.el" "esvg-flatten")
;;
(defvar esvg-flattened)

(defun esvg-flattened-add (o)
  "A recursive function used by `esvg-flatten-to-list'."
  (cond ((null o))
	((atom o) (push o esvg-flattened))
	(t (esvg-flattened-add (car o))
	   (esvg-flattened-add (cdr o)))))

;; Test: (esvg-flatten-to-list '(1 2 (3 . "4")))
(defun esvg-flatten-to-list (o)
  (setq esvg-flattened nil)
  (esvg-flattened-add o)
  (reverse esvg-flattened))

;; Test: (esvg-flatten-points  '(1 2 (3 . "4")))
(defun esvg-flatten-points (o)
  (if (stringp o) o
    (let* ((ns  (esvg-flatten-to-list o))
	   (xys (cl-loop for (x y) on ns by 'cddr
			 collect (format "%s %s" x y))))
      (mapconcat 'identity xys ", "))))


;; «esvg-make-simple»  (to ".esvg-make-simple")
;; Based on: (find-efunction 'svg-rectangle)
;;           (find-efunction 'svg-circle)
;;           (find-efunction 'svg-ellipse)
;;           (find-efunction 'svg-line)
;;           (find-efunction 'svg-polyline)
;;           (find-efunction 'svg-polygon)

;; Tests: (esvg-rectangle 1 2 3 4 :foo "red")
;;        (esvg-circle    1 2 3   :foo "red")
;;        (esvg-elipse    1 2 3 4 :foo "red")
;;        (esvg-line      1 2 3 4 :foo "red")
;;        (esvg-polyline  "1 2  3 4  5 6" :foo "red")
;;        (esvg-polygon   "1 2  3 4  5 6" :foo "red")
;;        (esvg-polyline  '((1 . 2) (3 . 4) (5 . 6)) :foo "red")
;;        (esvg-polygon   '((1 . 2) (3 . 4) (5 . 6)) :foo "red")
;;
(defun esvg-rectangle (x y width height &rest rest)
   `(rect ,@(esvg-translate-el :x x :y y :width width :height height rest)))

(defun esvg-circle (cx cy r &rest rest)
   `(circle ,@(esvg-translate-el :cx cx :cy cy :r r rest)))

(defun esvg-ellipse (cx cy rx ry rest)
  `(ellipse ,@(esvg-translate-el :cx cx :cy cy :rx rx :ry ry rest)))

(defun esvg-line (x1 y1 x2 y2 &rest rest)
  `(line ,@(esvg-translate-el :x1 x1 :y1 y1 :x2 x2 :y2 y2 rest)))

(defun esvg-polyline (points &rest rest)
  `(polyline ,@(esvg-translate-el :points (esvg-flatten-points points) rest)))

(defun esvg-polygon (points &rest rest)
  `(polygon ,@(esvg-translate-el :points (esvg-flatten-points points) rest)))



;; New:
(defun esvg-g (&rest rest)
  `(g ,@(esvg-translate-el rest)))

  (defun esvg-clippath (&rest rest)
    `(clipPath ,@(esvg-translate-el rest)))



(provide 'esvg-append)




;; Local Variables:
;; coding:  utf-8-unix
;; End: