Started work on pre-computing geometry, to allow shuffling labels.

This commit is contained in:
Simon Brooke 2024-07-10 20:07:33 +01:00
parent b75d7f8839
commit b9d98957eb

View file

@ -10,6 +10,13 @@
(def ^:dynamic *foreground* "black")
;; TODO: Right, so most of this is good. But I need to adjust the positions
;; of minor segment labels -- by sliding some of them sideways -- before
;; rendering. So probably what I need to do is one pass through the data
;; structure, tagging each node with geometry information (especially for
;; minor segment labels); then a second pass to sort out spacial collisions;
;; and don't try to generate the SVG until that has been done. But I need
;; *all* the geometry to be complete.
(defn polar-to-cartesian
"Return, as a map with keys :x. :y, the cartesian coordinates at the point
@ -44,18 +51,27 @@
(defn- font-size [thickness]
(int (* 0.15 thickness)))
(defn left-half?
[datum]
(> (+ (:left datum) (:right datum)) 1))
(defn- label-width
"Return the anticipated width of the label associated with this `datum`."
[datum thickness]
(* (count (:label datum)) (font-size thickness)))
(defn- text-path [datum tp-id geometry thickness start-angle end-angle]
[:path {:class "rsvggraph-text-path"
:id tp-id
:style {:fill "none"
:stroke "none"}
:d (let [angle (if (> (+ start-angle end-angle) 360) start-angle end-angle)
:d (let [angle (if (left-half? datum) start-angle end-angle)
radius (:radius geometry)
end (polar-to-cartesian (assoc geometry :radius (* 1.2 (:radius geometry)) :angle angle))
height (int (:y end))]
(if (minor-segment? datum)
(if (> angle 180)
(format "M %d %d L %d %d" (- (int (:x end)) (* (count (:label datum)) (font-size thickness))) height
(if (left-half? datum)
(format "M %d %d L %d %d" (- (int (:x end)) (label-width datum thickness)) height
(int (:x end)) height)
(format "M %d %d L %d %d" (int (:x end)) height (:width geometry) height))
(describe-arc (assoc geometry :radius (- radius (* 0.9 thickness)))
@ -69,8 +85,31 @@
(int (:x end)) (int (:y end)))))
(defn- label-indicator [datum geometry start-angle end-angle]
(when (minor-segment? datum)[:path {:class "rsvggraph-minor-label-indicator" :style {:fill "none" :stroke *foreground* :stroke-width "thin"}
:d (label-indicator-path geometry (if (> (+ start-angle end-angle) 360) start-angle end-angle))}]))
(when (minor-segment? datum) [:path {:class "rsvggraph-minor-label-indicator" :style {:fill "none" :stroke *foreground* :stroke-width "thin"}
:d (label-indicator-path geometry (if (left-half? datum) start-angle end-angle))}]))
(defn segment-geometry
[datum geometry]
(let [thickness (/ (:radius geometry) (:ring datum))
left? (left-half? datum)
start-angle (* (:left datum) 360)
end-angle (* (:right datum) 360)
angle (if left? start-angle end-angle)
kink (polar-to-cartesian
(assoc geometry :radius (* 1.2 (:radius geometry)) :angle angle))
label-bottom (int (:y kink))]
(merge geometry
{:thickness thickness
:radius (- (:radius geometry) (/ thickness 2))
:start-angle start-angle
:end-angle end-angle
:text-box (when (minor-segment? datum)
{:left (if left? (- (int (:x kink)) (label-width datum thickness))
(int (:x kink)))
:right (if left? (int (:x kink))
(+ (int (:x kink)) (label-width datum thickness)))
:bottom label-bottom
:top (+ label-bottom (font-size datum))})})))
(defn draw-segment
[datum geometry]