Reimplement getAllTextDimensions
Create SVG text elements so that the dimensions are representative
This commit is contained in:
@@ -15,7 +15,7 @@ import Effect (Effect)
|
|||||||
import Effect.Console (log)
|
import Effect.Console (log)
|
||||||
import Effect.Class (liftEffect)
|
import Effect.Class (liftEffect)
|
||||||
import Effect.Exception (throw)
|
import Effect.Exception (throw)
|
||||||
import TernaryGraph (Dimension, ternaryGraph, TextStyle, tickLabelStrings)
|
import TernaryGraph (Dimension, svgTextID, ternaryGraph, ternaryGraphSvg, TextStyle, tickLabelStrings)
|
||||||
import Web.DOM.Document (contentType
|
import Web.DOM.Document (contentType
|
||||||
, createElement
|
, createElement
|
||||||
, Document
|
, Document
|
||||||
@@ -54,47 +54,55 @@ getNodeById doc id = do
|
|||||||
Nothing -> throw $ "Unable to find element with ID '" <> id <> "'"
|
Nothing -> throw $ "Unable to find element with ID '" <> id <> "'"
|
||||||
Just e -> pure $ Element.toNode e
|
Just e -> pure $ Element.toNode e
|
||||||
|
|
||||||
getTextDimensions :: HTMLDoc.HTMLDocument -> TextStyle -> String -> Effect Dimension
|
getAllTextDimensions :: forall f. Foldable.Foldable f => Document -> Node -> f (Tup.Tuple String TextStyle) -> Effect (Map.Map (Tup.Tuple String TextStyle) Dimension)
|
||||||
getTextDimensions htmlDoc style text = do
|
getAllTextDimensions document svgContainer strings = do
|
||||||
let doc = HTMLDoc.toDocument htmlDoc
|
myDomParser <- makeDOMParser
|
||||||
el :: Element.Element <- createElement "span" doc
|
|
||||||
|
|
||||||
bodyMay <- HTMLDoc.body htmlDoc
|
-- Create svg fragments
|
||||||
bodyNode <- case bodyMay of
|
let textID = \i -> "text-" <> (show i)
|
||||||
Nothing -> throw "Could not find body of HTML document"
|
let (Tup.Tuple idMap _) = Foldable.foldr (\strTup (Tup.Tuple map i) -> Tup.Tuple (Map.insert (textID i) strTup map) (i + 1)) (Tup.Tuple Map.empty 0) strings
|
||||||
Just e -> pure $ Element.toNode (HTMLElement.toElement e)
|
let frag = \str style i -> svgTextID (Just (textID i)) str { x: 0.0, y: 0.0 } 0.0 style { widthPx: 0.0, heightPx: 0.0 }
|
||||||
|
let fragments = Foldable.foldr (\(Tup.Tuple str style) arr -> Array.cons (frag str style (Array.length arr)) arr) [] strings
|
||||||
|
|
||||||
appendChild (Element.toNode el) bodyNode
|
-- create svg string
|
||||||
|
let svg = ternaryGraphSvg fragments
|
||||||
|
|
||||||
let styleText = (
|
-- add to container
|
||||||
"font" <> style.typeface
|
svgDocMay <- parseSVGFromString svg myDomParser
|
||||||
<> ";font-family: " <> style.typeface
|
svgDoc <- case svgDocMay of
|
||||||
<> ";font-size: " <> (toString style.sizePx) <> "px"
|
Left error -> throw error
|
||||||
<> ";height: " <> "auto"
|
Right doc -> pure doc
|
||||||
<> ";width: " <> "auto"
|
|
||||||
<> ";position: " <> "absolute"
|
|
||||||
<> ";white-space: " <> "nowrap"
|
|
||||||
)
|
|
||||||
|
|
||||||
Element.setAttribute "style" styleText el
|
elMay <- firstElementChild $ toParentNode svgDoc
|
||||||
setTextContent text (Element.toNode el)
|
svgNode <- case elMay of
|
||||||
width <- Element.clientWidth el
|
Nothing -> throw "no child in svg doc"
|
||||||
height <- Element.clientHeight el
|
Just el -> pure $ Element.toNode el
|
||||||
|
|
||||||
removeChild (Element.toNode el) bodyNode
|
newNode <- importNode svgNode true document
|
||||||
|
appendChild newNode svgContainer
|
||||||
|
|
||||||
pure { widthPx: width, heightPx: height }
|
-- get dimensions for all text elements
|
||||||
|
myMap <- Foldable.foldM (\map i -> do
|
||||||
|
let id = textID i
|
||||||
|
textElement <- myGetElementById document id
|
||||||
|
boundingRect <- Element.getBoundingClientRect textElement
|
||||||
|
|
||||||
|
let textNFontMay = Map.lookup id idMap
|
||||||
|
textNFont <- case textNFontMay of
|
||||||
|
Nothing -> throw $ "Missing '" <> id <> "' from map"
|
||||||
|
Just x -> pure x
|
||||||
|
|
||||||
|
log $ id <> ": " <> (toString boundingRect.width) <> ", " <> (toString boundingRect.height)
|
||||||
|
|
||||||
|
pure $ Map.insert textNFont { widthPx: boundingRect.width, heightPx: boundingRect.height } map
|
||||||
|
) Map.empty (Array.range 0 ((Array.length fragments) - 1))
|
||||||
|
|
||||||
converter :: HTMLDoc.HTMLDocument -> (Map.Map (Tup.Tuple String TextStyle) Dimension) -> (Tup.Tuple String TextStyle) -> Effect (Map.Map (Tup.Tuple String TextStyle) Dimension)
|
-- remove the svg
|
||||||
converter doc map textTuple = do
|
containerKids <- (childNodes svgContainer) >>= NodeList.toArray
|
||||||
let text = Tup.fst textTuple
|
Foldable.for_ containerKids \kid -> do
|
||||||
let style = Tup.snd textTuple
|
removeChild kid svgContainer
|
||||||
dimension <- getTextDimensions doc style text
|
|
||||||
pure $ Map.insert textTuple dimension map
|
|
||||||
|
|
||||||
getAllTextDimensions :: forall f. Foldable.Foldable f => HTMLDoc.HTMLDocument -> f (Tup.Tuple String TextStyle) -> Effect (Map.Map (Tup.Tuple String TextStyle) Dimension)
|
pure myMap
|
||||||
getAllTextDimensions doc strings =
|
|
||||||
Foldable.foldM (converter doc) Map.empty strings
|
|
||||||
|
|
||||||
update :: Event -> Effect Unit
|
update :: Event -> Effect Unit
|
||||||
update e = do
|
update e = do
|
||||||
@@ -134,7 +142,11 @@ update e = do
|
|||||||
, (Tup.Tuple graphDef.axis2Label graphDef.axisTitleTextStyle)
|
, (Tup.Tuple graphDef.axis2Label graphDef.axisTitleTextStyle)
|
||||||
, (Tup.Tuple graphDef.axis3Label graphDef.axisTitleTextStyle)
|
, (Tup.Tuple graphDef.axis3Label graphDef.axisTitleTextStyle)
|
||||||
]
|
]
|
||||||
textDimensions <- getAllTextDimensions d textStyles
|
textDimensions <- getAllTextDimensions document svgContainer textStyles
|
||||||
|
|
||||||
|
log $ case Map.lookup (Tup.Tuple "axis 1" graphDef.axisTitleTextStyle) textDimensions of
|
||||||
|
Nothing -> "Not found"
|
||||||
|
Just { widthPx: width, heightPx: height} -> (toString width) <> ", " <> (toString height)
|
||||||
|
|
||||||
let mySVGErr = ternaryGraph 100.0 50.0 50.0 graphDef textDimensions
|
let mySVGErr = ternaryGraph 100.0 50.0 50.0 graphDef textDimensions
|
||||||
mySVG <- case mySVGErr of
|
mySVG <- case mySVGErr of
|
||||||
@@ -191,7 +203,7 @@ main = do
|
|||||||
, (Tup.Tuple graphDef.axis2Label graphDef.axisTitleTextStyle)
|
, (Tup.Tuple graphDef.axis2Label graphDef.axisTitleTextStyle)
|
||||||
, (Tup.Tuple graphDef.axis3Label graphDef.axisTitleTextStyle)
|
, (Tup.Tuple graphDef.axis3Label graphDef.axisTitleTextStyle)
|
||||||
]
|
]
|
||||||
textDimensions <- getAllTextDimensions d textStyles
|
textDimensions <- getAllTextDimensions dd svgContainer textStyles
|
||||||
|
|
||||||
log $ Foldable.foldr (\dim str -> str <> "\n" <> (toString dim.widthPx) <> ", " <> (toString dim.heightPx)) "" $ Map.values textDimensions
|
log $ Foldable.foldr (\dim str -> str <> "\n" <> (toString dim.widthPx) <> ", " <> (toString dim.heightPx)) "" $ Map.values textDimensions
|
||||||
|
|
||||||
|
|||||||
@@ -87,13 +87,19 @@ svgLine { start: {x: x1, y: y1}, end: {x: x2, y: y2} } =
|
|||||||
""" <> "d=\"M " <> (toString x1) <> "," <> (toString y1) <> " " <> (toString x2) <> "," <> (toString y2) <> "\"/>"
|
""" <> "d=\"M " <> (toString x1) <> "," <> (toString y1) <> " " <> (toString x2) <> "," <> (toString y2) <> "\"/>"
|
||||||
|
|
||||||
svgText :: String -> Point -> Number -> TextStyle -> Dimension -> XMLFragment
|
svgText :: String -> Point -> Number -> TextStyle -> Dimension -> XMLFragment
|
||||||
svgText text { x: x, y: y } angle style dimension =
|
svgText = svgTextID Maybe.Nothing
|
||||||
XMLFragment $ "<text xml:space=\"preserve\" style=\"font-size:" <> (toString style.sizePx) <> "px;line-height:131%;font-family:'" <> style.typeface <> "';fill:#000000;stroke:#000000;stroke-width:0.0999998;stroke-linecap:round;stop-color:#000000;fill-opacity:1\" "
|
|
||||||
|
svgTextID :: Maybe.Maybe String -> String -> Point -> Number -> TextStyle -> Dimension -> XMLFragment
|
||||||
|
svgTextID idMaybe text { x: x, y: y } angle style dimension =
|
||||||
|
XMLFragment $ "<text " <> idText <> " xml:space=\"preserve\" style=\"font-size:" <> (toString style.sizePx) <> "px;line-height:131%;font-family:'" <> style.typeface <> "';fill:#000000;stroke:#000000;stroke-width:0.0999998;stroke-linecap:round;stop-color:#000000;fill-opacity:1\" "
|
||||||
<> "transform=\"translate(" <> (toString centerX) <> ", " <> (toString centerY) <> ") rotate(" <> (toString (angle * 180.0 / pi)) <> ")\">" <> text <> "</text>"
|
<> "transform=\"translate(" <> (toString centerX) <> ", " <> (toString centerY) <> ") rotate(" <> (toString (angle * 180.0 / pi)) <> ")\">" <> text <> "</text>"
|
||||||
where
|
where
|
||||||
offset = rotate angle {x: dimension.widthPx, y: dimension.heightPx}
|
offset = rotate angle {x: dimension.widthPx, y: dimension.heightPx}
|
||||||
centerX = x - offset.x / 2.0
|
centerX = x - offset.x / 4.0
|
||||||
centerY = y - offset.y / 2.0
|
centerY = y - offset.y / 4.0
|
||||||
|
idText = case idMaybe of
|
||||||
|
Maybe.Nothing -> ""
|
||||||
|
Maybe.Just id -> "id=\"" <> id <> "\""
|
||||||
|
|
||||||
-- TODO: Make axis tick size a parameter
|
-- TODO: Make axis tick size a parameter
|
||||||
getTick :: Number -> Int -> Int -> Line
|
getTick :: Number -> Int -> Int -> Line
|
||||||
@@ -173,6 +179,7 @@ ternaryGraph scale xOffset yOffset definition textDimensions = result
|
|||||||
axis1TitlePos = {x: 0.0, y: 0.9}
|
axis1TitlePos = {x: 0.0, y: 0.9}
|
||||||
axis2TitlePos = rotate (2.0 * pi / 3.0) axis1TitlePos
|
axis2TitlePos = rotate (2.0 * pi / 3.0) axis1TitlePos
|
||||||
axis3TitlePos = rotate (-2.0 * pi / 3.0) axis1TitlePos
|
axis3TitlePos = rotate (-2.0 * pi / 3.0) axis1TitlePos
|
||||||
|
|
||||||
axisTitleSize = definition.axisTitleTextStyle.sizePx
|
axisTitleSize = definition.axisTitleTextStyle.sizePx
|
||||||
axisTitlesSvg :: Array (Either.Either String XMLFragment)
|
axisTitlesSvg :: Array (Either.Either String XMLFragment)
|
||||||
axisTitlesSvg = [
|
axisTitlesSvg = [
|
||||||
|
|||||||
Reference in New Issue
Block a user