From 919efd6fd19c3a7cdadc2480f313a08c12143667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 12:16:19 +0200 Subject: [PATCH 01/13] fix: scaling fixes WIP --- .../config/generators/dhis/singleValue.js | 57 ++++++++++++++++--- 1 file changed, 49 insertions(+), 8 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index bbe3e9e60..b2c00ec92 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -29,6 +29,21 @@ const getTextWidth = (text, font) => { return context.measureText(text).width } +const getTextSize = (formattedValue, containerWidth, containerHeight) => { + let size = containerHeight / 5 + + if (size > 0) { + while ( + getTextWidth(formattedValue, `${size}px Roboto`) > + containerWidth * 0.7 + ) { + size = size - 1 + } + } + + return size +} + const generateValueSVG = ({ formattedValue, subText, @@ -39,25 +54,34 @@ const generateValueSVG = ({ containerWidth, containerHeight, }) => { - const ratio = containerHeight / containerWidth - const iconSize = 300 + // const ratio = containerHeight / containerWidth + // const iconSize = 300 const iconPadding = 50 - const textSize = iconSize * 0.85 + // const textSize = iconSize * 0.85 + const textSize = getTextSize( + formattedValue, + containerWidth, + containerHeight + ) + console.log('textSize', textSize) + const textWidth = getTextWidth(formattedValue, `${textSize}px Roboto`) + console.log('textWidth', textWidth) const subTextSize = 40 + const iconSize = textSize const showIcon = icon && formattedValue !== noData.text - let viewBoxWidth = textWidth + // let viewBoxWidth = textWidth if (showIcon) { - viewBoxWidth += iconSize + iconPadding + // viewBoxWidth += iconSize + iconPadding } - const viewBoxHeight = viewBoxWidth * ratio + // const viewBoxHeight = viewBoxWidth * ratio const svgValue = document.createElementNS(svgNS, 'svg') - svgValue.setAttribute('viewBox', `0 0 ${viewBoxWidth} ${viewBoxHeight}`) + svgValue.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) svgValue.setAttribute('width', '95%') svgValue.setAttribute('height', '95%') svgValue.setAttribute('x', '50%') @@ -97,10 +121,17 @@ const generateValueSVG = ({ svgValue.appendChild(iconSvgNode) } + const letterSpacing = (textSize / 40) * -1 + const textNode = document.createElementNS(svgNS, 'text') + textNode.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) textNode.setAttribute('font-size', textSize) textNode.setAttribute('font-weight', '300') - textNode.setAttribute('letter-spacing', '-5') + // textNode.setAttribute('letter-spacing', '-5') + textNode.setAttribute( + 'letter-spacing', + letterSpacing < -5 ? -5 : letterSpacing > -2 ? -2 : letterSpacing + ) textNode.setAttribute('text-anchor', 'middle') textNode.setAttribute('x', showIcon ? `${(iconSize + iconPadding) / 2}` : 0) // vertical align, "alignment-baseline: central" is not supported by Batik @@ -225,6 +256,16 @@ const generateDVItem = ( icon, } ) => { + console.log('config', config) + console.log('svgContainer', svgContainer) + console.log('width', width) + console.log('height', height) + console.log('valueColor', valueColor) + console.log('backgroundColor', backgroundColor) + console.log('titleColor', titleColor) + console.log('fontStyle', fontStyle) + console.log('icon', icon) + if (backgroundColor) { svgContainer.setAttribute( 'style', From 6b6fd09df41b7d72098da1223e18b8f935d80751 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 15:03:06 +0200 Subject: [PATCH 02/13] fix: avoid collision with title/subtitle WIP --- .../config/generators/dhis/singleValue.js | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index b2c00ec92..503afb5ca 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -26,16 +26,18 @@ const getTextWidth = (text, font) => { const canvas = document.createElement('canvas') const context = canvas.getContext('2d') context.font = font - return context.measureText(text).width + return context.measureText(text).width * 0.9 } +const getTextHeight = (textSize) => textSize * 0.7 + const getTextSize = (formattedValue, containerWidth, containerHeight) => { - let size = containerHeight / 5 + let size = Math.round(containerHeight / 3) if (size > 0) { while ( getTextWidth(formattedValue, `${size}px Roboto`) > - containerWidth * 0.7 + containerWidth * 0.8 ) { size = size - 1 } @@ -53,6 +55,7 @@ const generateValueSVG = ({ noData, containerWidth, containerHeight, + topMargin, }) => { // const ratio = containerHeight / containerWidth // const iconSize = 300 @@ -63,10 +66,12 @@ const generateValueSVG = ({ containerWidth, containerHeight ) + console.log('topMargin', topMargin) console.log('textSize', textSize) const textWidth = getTextWidth(formattedValue, `${textSize}px Roboto`) console.log('textWidth', textWidth) + const subTextSize = 40 const iconSize = textSize @@ -74,9 +79,9 @@ const generateValueSVG = ({ // let viewBoxWidth = textWidth - if (showIcon) { - // viewBoxWidth += iconSize + iconPadding - } + // if (showIcon) { + // viewBoxWidth += iconSize + iconPadding + // } // const viewBoxHeight = viewBoxWidth * ratio @@ -100,10 +105,11 @@ const generateValueSVG = ({ if (showIcon) { // embed icon to allow changing color // (elements with fill need to use "currentColor" for this to work) + const iconSvgNode = document.createElementNS(svgNS, 'svg') + iconSvgNode.setAttribute('viewBox', '0 0 48 48') iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) - iconSvgNode.setAttribute('viewBox', '0 0 48 48') iconSvgNode.setAttribute('y', `-${iconSize / 2}`) iconSvgNode.setAttribute( 'x', @@ -135,7 +141,7 @@ const generateValueSVG = ({ textNode.setAttribute('text-anchor', 'middle') textNode.setAttribute('x', showIcon ? `${(iconSize + iconPadding) / 2}` : 0) // vertical align, "alignment-baseline: central" is not supported by Batik - textNode.setAttribute('y', '.35em') + textNode.setAttribute('y', topMargin / 2 + getTextHeight(textSize) / 2) textNode.setAttribute('fill', fillColor) textNode.setAttribute('data-test', 'visualization-primary-value') @@ -394,7 +400,15 @@ const generateDVItem = ( } svgContainer.appendChild(svgWrapper) - + console.log('title size', parseInt(title.getAttribute('font-size'))) + console.log('subtitle size', parseInt(subtitle.getAttribute('font-size'))) + console.log( + 'top margin', + getTextHeight( + (title ? parseInt(title.getAttribute('font-size')) : 0) + + (subtitle ? parseInt(subtitle.getAttribute('font-size')) : 0) + ) + ) svgContainer.appendChild( generateValueSVG({ formattedValue: config.formattedValue, @@ -405,6 +419,13 @@ const generateDVItem = ( icon, containerWidth: width, containerHeight: height, + topMargin: + getTextHeight( + (title ? parseInt(title.getAttribute('font-size')) : 0) + + (subtitle + ? parseInt(subtitle.getAttribute('font-size')) + : 0) + ) * 1.9, }) ) From 2e2bf5b20e00f304042d6d0cbd2678d5f43cedf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 16:18:27 +0200 Subject: [PATCH 03/13] fix: adjust title position WIP --- .../config/generators/dhis/singleValue.js | 167 ++++++++---------- 1 file changed, 71 insertions(+), 96 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 503afb5ca..31e060895 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -29,7 +29,7 @@ const getTextWidth = (text, font) => { return context.measureText(text).width * 0.9 } -const getTextHeight = (textSize) => textSize * 0.7 +const getTextHeightForNumbers = (textSize) => textSize * 0.7 const getTextSize = (formattedValue, containerWidth, containerHeight) => { let size = Math.round(containerHeight / 3) @@ -127,7 +127,7 @@ const generateValueSVG = ({ svgValue.appendChild(iconSvgNode) } - const letterSpacing = (textSize / 40) * -1 + const letterSpacing = Math.round((textSize / 35) * -1) const textNode = document.createElementNS(svgNS, 'text') textNode.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) @@ -136,12 +136,15 @@ const generateValueSVG = ({ // textNode.setAttribute('letter-spacing', '-5') textNode.setAttribute( 'letter-spacing', - letterSpacing < -5 ? -5 : letterSpacing > -2 ? -2 : letterSpacing + letterSpacing < -6 ? -6 : letterSpacing > -1 ? -1 : letterSpacing ) textNode.setAttribute('text-anchor', 'middle') textNode.setAttribute('x', showIcon ? `${(iconSize + iconPadding) / 2}` : 0) // vertical align, "alignment-baseline: central" is not supported by Batik - textNode.setAttribute('y', topMargin / 2 + getTextHeight(textSize) / 2) + textNode.setAttribute( + 'y', + topMargin / 2 + getTextHeightForNumbers(textSize) / 2 + ) textNode.setAttribute('fill', fillColor) textNode.setAttribute('data-test', 'visualization-primary-value') @@ -287,115 +290,89 @@ const generateDVItem = ( const svgWrapper = document.createElementNS(svgNS, 'svg') + // title const title = document.createElementNS(svgNS, 'text') + const titleFontStyle = mergeFontStyleWithDefault( fontStyle && fontStyle[FONT_STYLE_VISUALIZATION_TITLE], FONT_STYLE_VISUALIZATION_TITLE ) - const titleYPosition = titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE] - - title.setAttribute( - 'x', - getXFromTextAlign(titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]) - ) - title.setAttribute('y', titleYPosition) - title.setAttribute( - 'text-anchor', - getTextAnchorFromTextAlign(titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]) - ) - title.setAttribute( - 'font-size', - `${titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]}px` - ) - title.setAttribute( - 'font-weight', - titleFontStyle[FONT_STYLE_OPTION_BOLD] + console.log('titleFontStyle', titleFontStyle) + const titleYPosition = + 16 + parseInt(titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]) + 'px' + + const titleAttributes = { + x: getXFromTextAlign(titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]), + y: titleYPosition, + 'text-anchor': getTextAnchorFromTextAlign( + titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN] + ), + 'font-size': `${titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]}px`, + 'font-weight': titleFontStyle[FONT_STYLE_OPTION_BOLD] ? FONT_STYLE_OPTION_BOLD - : 'normal' - ) - title.setAttribute( - 'font-style', - titleFontStyle[FONT_STYLE_OPTION_ITALIC] + : 'normal', + 'font-style': titleFontStyle[FONT_STYLE_OPTION_ITALIC] ? FONT_STYLE_OPTION_ITALIC - : 'normal' - ) - if ( - titleColor && - titleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR] === - defaultFontStyle[FONT_STYLE_VISUALIZATION_TITLE][ - FONT_STYLE_OPTION_TEXT_COLOR - ] - ) { - title.setAttribute('fill', titleColor) - } else { - title.setAttribute('fill', titleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR]) + : 'normal', + 'data-test': 'visualization-title', + fill: + titleColor && + titleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR] === + defaultFontStyle[FONT_STYLE_VISUALIZATION_TITLE][ + FONT_STYLE_OPTION_TEXT_COLOR + ] + ? titleColor + : titleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR], } - title.setAttribute('data-test', 'visualization-title') + Object.entries(titleAttributes).forEach(([key, value]) => + title.setAttribute(key, value) + ) if (config.title) { title.appendChild(document.createTextNode(config.title)) - svgWrapper.appendChild(title) } + // subtitle + const subtitle = document.createElementNS(svgNS, 'text') + const subtitleFontStyle = mergeFontStyleWithDefault( fontStyle && fontStyle[FONT_STYLE_VISUALIZATION_SUBTITLE], FONT_STYLE_VISUALIZATION_SUBTITLE ) - const subtitle = document.createElementNS(svgNS, 'text') - subtitle.setAttribute( - 'x', - getXFromTextAlign(subtitleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]) - ) - subtitle.setAttribute('y', titleYPosition) - subtitle.setAttribute( - 'dy', - `${subtitleFontStyle[FONT_STYLE_OPTION_FONT_SIZE] + 10}` - ) - subtitle.setAttribute( - 'text-anchor', - getTextAnchorFromTextAlign( + + const subtitleAttributes = { + x: getXFromTextAlign(subtitleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]), + y: titleYPosition, + dy: `${subtitleFontStyle[FONT_STYLE_OPTION_FONT_SIZE] + 10}`, + 'text-anchor': getTextAnchorFromTextAlign( subtitleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN] - ) - ) - subtitle.setAttribute( - 'font-size', - `${subtitleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]}px` - ) - subtitle.setAttribute( - 'font-weight', - subtitleFontStyle[FONT_STYLE_OPTION_BOLD] + ), + 'font-size': `${subtitleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]}px`, + 'font-weight': subtitleFontStyle[FONT_STYLE_OPTION_BOLD] ? FONT_STYLE_OPTION_BOLD - : 'normal' - ) - subtitle.setAttribute( - 'font-style', - subtitleFontStyle[FONT_STYLE_OPTION_ITALIC] + : 'normal', + 'font-style': subtitleFontStyle[FONT_STYLE_OPTION_ITALIC] ? FONT_STYLE_OPTION_ITALIC - : 'normal' - ) - - if ( - titleColor && - subtitleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR] === - defaultFontStyle[FONT_STYLE_VISUALIZATION_SUBTITLE][ - FONT_STYLE_OPTION_TEXT_COLOR - ] - ) { - subtitle.setAttribute('fill', titleColor) - } else { - subtitle.setAttribute( - 'fill', - subtitleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR] - ) + : 'normal', + fill: + titleColor && + subtitleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR] === + defaultFontStyle[FONT_STYLE_VISUALIZATION_SUBTITLE][ + FONT_STYLE_OPTION_TEXT_COLOR + ] + ? titleColor + : subtitleFontStyle[FONT_STYLE_OPTION_TEXT_COLOR], + 'data-test': 'visualization-subtitle', } - subtitle.setAttribute('data-test', 'visualization-subtitle') + Object.entries(subtitleAttributes).forEach(([key, value]) => + subtitle.setAttribute(key, value) + ) if (config.subtitle) { subtitle.appendChild(document.createTextNode(config.subtitle)) - svgWrapper.appendChild(subtitle) } @@ -404,10 +381,8 @@ const generateDVItem = ( console.log('subtitle size', parseInt(subtitle.getAttribute('font-size'))) console.log( 'top margin', - getTextHeight( - (title ? parseInt(title.getAttribute('font-size')) : 0) + - (subtitle ? parseInt(subtitle.getAttribute('font-size')) : 0) - ) + (title ? parseInt(title.getAttribute('font-size')) : 0) + + (subtitle ? parseInt(subtitle.getAttribute('font-size')) : 0) ) svgContainer.appendChild( generateValueSVG({ @@ -420,12 +395,12 @@ const generateDVItem = ( containerWidth: width, containerHeight: height, topMargin: - getTextHeight( - (title ? parseInt(title.getAttribute('font-size')) : 0) + - (subtitle - ? parseInt(subtitle.getAttribute('font-size')) - : 0) - ) * 1.9, + 16 + + (config.title ? parseInt(title.getAttribute('font-size')) : 0) + + (config.subtitle + ? parseInt(subtitle.getAttribute('font-size')) + : 0) * + 1.8, }) ) From 0b3f1ae733c59ee9066850ff40b58a76f3b0da43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 16:53:12 +0200 Subject: [PATCH 04/13] fix: icon position WIP --- .../config/generators/dhis/singleValue.js | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 31e060895..92e0e687a 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -31,13 +31,20 @@ const getTextWidth = (text, font) => { const getTextHeightForNumbers = (textSize) => textSize * 0.7 -const getTextSize = (formattedValue, containerWidth, containerHeight) => { +const getTextSize = ( + formattedValue, + containerWidth, + containerHeight, + showIcon +) => { let size = Math.round(containerHeight / 3) + const threshold = containerWidth * 0.8 if (size > 0) { while ( - getTextWidth(formattedValue, `${size}px Roboto`) > - containerWidth * 0.8 + getTextWidth(formattedValue, `${size}px Roboto`) + + (showIcon ? size + 50 : 0) > + threshold ) { size = size - 1 } @@ -60,6 +67,7 @@ const generateValueSVG = ({ // const ratio = containerHeight / containerWidth // const iconSize = 300 const iconPadding = 50 + const showIcon = icon && formattedValue !== noData.text // const textSize = iconSize * 0.85 const textSize = getTextSize( formattedValue, @@ -75,7 +83,6 @@ const generateValueSVG = ({ const subTextSize = 40 const iconSize = textSize - const showIcon = icon && formattedValue !== noData.text // let viewBoxWidth = textWidth @@ -110,7 +117,12 @@ const generateValueSVG = ({ iconSvgNode.setAttribute('viewBox', '0 0 48 48') iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) - iconSvgNode.setAttribute('y', `-${iconSize / 2}`) + iconSvgNode.setAttribute('y', `-${iconSize / 2 - topMargin / 2}`) + // iconSvgNode.setAttribute( + // 'y', + // topMargin / 2 + getTextHeightForNumbers(textSize) / 2 + // ) + iconSvgNode.setAttribute( 'x', `-${(iconSize + iconPadding + textWidth) / 2}` From 7bd25ff16edf41ceba4eb682b14c1bdd44317c26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 19:24:05 +0200 Subject: [PATCH 05/13] fix: icon position WIP --- .../config/generators/dhis/singleValue.js | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 92e0e687a..53a0df915 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -38,13 +38,13 @@ const getTextSize = ( showIcon ) => { let size = Math.round(containerHeight / 3) - const threshold = containerWidth * 0.8 + const widthThreshold = containerWidth * 0.8 if (size > 0) { while ( getTextWidth(formattedValue, `${size}px Roboto`) + (showIcon ? size + 50 : 0) > - threshold + widthThreshold ) { size = size - 1 } @@ -72,7 +72,8 @@ const generateValueSVG = ({ const textSize = getTextSize( formattedValue, containerWidth, - containerHeight + containerHeight, + showIcon ) console.log('topMargin', topMargin) console.log('textSize', textSize) @@ -94,8 +95,8 @@ const generateValueSVG = ({ const svgValue = document.createElementNS(svgNS, 'svg') svgValue.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) - svgValue.setAttribute('width', '95%') - svgValue.setAttribute('height', '95%') + svgValue.setAttribute('width', '50%') + svgValue.setAttribute('height', '50%') svgValue.setAttribute('x', '50%') svgValue.setAttribute('y', '50%') svgValue.setAttribute('style', 'overflow: visible') @@ -118,11 +119,6 @@ const generateValueSVG = ({ iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) iconSvgNode.setAttribute('y', `-${iconSize / 2 - topMargin / 2}`) - // iconSvgNode.setAttribute( - // 'y', - // topMargin / 2 + getTextHeightForNumbers(textSize) / 2 - // ) - iconSvgNode.setAttribute( 'x', `-${(iconSize + iconPadding + textWidth) / 2}` @@ -142,7 +138,7 @@ const generateValueSVG = ({ const letterSpacing = Math.round((textSize / 35) * -1) const textNode = document.createElementNS(svgNS, 'text') - textNode.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) + // textNode.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) textNode.setAttribute('font-size', textSize) textNode.setAttribute('font-weight', '300') // textNode.setAttribute('letter-spacing', '-5') From b58b9749d6ba79b59adc01f41b182c4bd4c3e4f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 19:46:34 +0200 Subject: [PATCH 06/13] fix: icon position WIP --- .../config/generators/dhis/singleValue.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 53a0df915..8861e30b9 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -118,7 +118,7 @@ const generateValueSVG = ({ iconSvgNode.setAttribute('viewBox', '0 0 48 48') iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) - iconSvgNode.setAttribute('y', `-${iconSize / 2 - topMargin / 2}`) + iconSvgNode.setAttribute('y', (iconSize / 2 - topMargin / 2) * -1) iconSvgNode.setAttribute( 'x', `-${(iconSize + iconPadding + textWidth) / 2}` @@ -392,6 +392,10 @@ const generateDVItem = ( (title ? parseInt(title.getAttribute('font-size')) : 0) + (subtitle ? parseInt(subtitle.getAttribute('font-size')) : 0) ) + + console.log('config.title', !!config.title) + console.log('config.subtitle', !!config.subtitle) + svgContainer.appendChild( generateValueSVG({ formattedValue: config.formattedValue, @@ -404,11 +408,13 @@ const generateDVItem = ( containerHeight: height, topMargin: 16 + - (config.title ? parseInt(title.getAttribute('font-size')) : 0) + - (config.subtitle - ? parseInt(subtitle.getAttribute('font-size')) - : 0) * - 1.8, + ((config.title + ? parseInt(title.getAttribute('font-size')) + : 0) + + (config.subtitle + ? parseInt(subtitle.getAttribute('font-size')) + : 0)) * + 2.5, }) ) From 074a12f28c3ba25b6bed729a2b67de1f567f805f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 23 May 2023 19:55:02 +0200 Subject: [PATCH 07/13] fix: width threshold WIP --- src/visualizations/config/generators/dhis/singleValue.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 8861e30b9..3a9cda4bc 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -38,7 +38,7 @@ const getTextSize = ( showIcon ) => { let size = Math.round(containerHeight / 3) - const widthThreshold = containerWidth * 0.8 + const widthThreshold = containerWidth * 0.9 if (size > 0) { while ( From bfd4982f8dc74577693b667e25001d2ae2c2cbfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 24 May 2023 14:34:35 +0200 Subject: [PATCH 08/13] fix: use constants --- .../config/generators/dhis/singleValue.js | 72 +++++++++++++++---- 1 file changed, 57 insertions(+), 15 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 3a9cda4bc..a04be8dcf 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -20,16 +20,46 @@ import { const svgNS = 'http://www.w3.org/2000/svg' +// multiply text width with this factor +// to get very close to actual text width +const ACTUAL_TEXT_WIDTH_FACTOR = 0.9 + +// multiply value text size with this factor +// to get very close to the actual number height +const ACTUAL_NUMBER_HEIGHT_FACTOR = 0.7 + +// do not allow text width to exceed this threshold +const TEXT_WIDTH_CONTAINER_WIDTH_THRESHOLD = 0.9 + +// do not allow text size to exceed this threshold +const TEXT_SIZE_CONTAINER_HEIGHT_THRESHOLD = 0.4 + +// multiply text size with this factor +// to get an appropriate letter spacing +const LETTER_SPACING_TEXT_SIZE_FACTOR = (1 / 35) * -1 +const LETTER_SPACING_MIN_THRESHOLD = -6 +const LETTER_SPACING_MAX_THRESHOLD = -1 + +// fixed top margin above title/subtitle +const TOP_MARGIN_FIXED = 16 + +// multiply text size with this factor +// to get an appropriate sub text size +const SUB_TEXT_SIZE_FACTOR = 1 / 6 +const SUB_TEXT_SIZE_MIN_THRESHOLD = 24 +const SUB_TEXT_SIZE_MAX_THRESHOLD = 40 + // Compute text width before rendering // Not exactly precise but close enough const getTextWidth = (text, font) => { const canvas = document.createElement('canvas') const context = canvas.getContext('2d') context.font = font - return context.measureText(text).width * 0.9 + return context.measureText(text).width * ACTUAL_TEXT_WIDTH_FACTOR } -const getTextHeightForNumbers = (textSize) => textSize * 0.7 +const getTextHeightForNumbers = (textSize) => + textSize * ACTUAL_NUMBER_HEIGHT_FACTOR const getTextSize = ( formattedValue, @@ -37,8 +67,10 @@ const getTextSize = ( containerHeight, showIcon ) => { - let size = Math.round(containerHeight / 3) - const widthThreshold = containerWidth * 0.9 + let size = Math.round( + containerHeight * TEXT_SIZE_CONTAINER_HEIGHT_THRESHOLD + ) + const widthThreshold = containerWidth * TEXT_WIDTH_CONTAINER_WIDTH_THRESHOLD if (size > 0) { while ( @@ -81,9 +113,14 @@ const generateValueSVG = ({ const textWidth = getTextWidth(formattedValue, `${textSize}px Roboto`) console.log('textWidth', textWidth) - const subTextSize = 40 - + // const subTextSize = 40 const iconSize = textSize + const subTextSize = + textSize * SUB_TEXT_SIZE_FACTOR > SUB_TEXT_SIZE_MAX_THRESHOLD + ? SUB_TEXT_SIZE_MAX_THRESHOLD + : textSize * SUB_TEXT_SIZE_FACTOR < SUB_TEXT_SIZE_MIN_THRESHOLD + ? SUB_TEXT_SIZE_MIN_THRESHOLD + : textSize * SUB_TEXT_SIZE_FACTOR // let viewBoxWidth = textWidth @@ -135,16 +172,18 @@ const generateValueSVG = ({ svgValue.appendChild(iconSvgNode) } - const letterSpacing = Math.round((textSize / 35) * -1) + const letterSpacing = Math.round(textSize * LETTER_SPACING_TEXT_SIZE_FACTOR) const textNode = document.createElementNS(svgNS, 'text') - // textNode.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) textNode.setAttribute('font-size', textSize) textNode.setAttribute('font-weight', '300') - // textNode.setAttribute('letter-spacing', '-5') textNode.setAttribute( 'letter-spacing', - letterSpacing < -6 ? -6 : letterSpacing > -1 ? -1 : letterSpacing + letterSpacing < LETTER_SPACING_MIN_THRESHOLD + ? LETTER_SPACING_MIN_THRESHOLD + : letterSpacing > LETTER_SPACING_MAX_THRESHOLD + ? LETTER_SPACING_MAX_THRESHOLD + : letterSpacing ) textNode.setAttribute('text-anchor', 'middle') textNode.setAttribute('x', showIcon ? `${(iconSize + iconPadding) / 2}` : 0) @@ -164,9 +203,10 @@ const generateValueSVG = ({ const subTextNode = document.createElementNS(svgNS, 'text') subTextNode.setAttribute('text-anchor', 'middle') subTextNode.setAttribute('font-size', subTextSize) - subTextNode.setAttribute('y', iconSize / 2) - subTextNode.setAttribute('dy', subTextSize) - subTextNode.setAttribute('fill', textColor) + subTextNode.setAttribute('y', iconSize / 2 + topMargin / 2) + subTextNode.setAttribute('dy', subTextSize * 1.7) + // subTextNode.setAttribute('fill', textColor) + subTextNode.setAttribute('fill', fillColor) subTextNode.appendChild(document.createTextNode(subText)) svgValue.appendChild(subTextNode) @@ -307,7 +347,9 @@ const generateDVItem = ( ) console.log('titleFontStyle', titleFontStyle) const titleYPosition = - 16 + parseInt(titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]) + 'px' + TOP_MARGIN_FIXED + + parseInt(titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]) + + 'px' const titleAttributes = { x: getXFromTextAlign(titleFontStyle[FONT_STYLE_OPTION_TEXT_ALIGN]), @@ -407,7 +449,7 @@ const generateDVItem = ( containerWidth: width, containerHeight: height, topMargin: - 16 + + TOP_MARGIN_FIXED + ((config.title ? parseInt(title.getAttribute('font-size')) : 0) + From 4dfd205cdfba3a5a27f689b879ce2d3076a3121e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Wed, 24 May 2023 18:24:38 +0200 Subject: [PATCH 09/13] fix: icon padding --- .../config/generators/dhis/singleValue.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index a04be8dcf..5a0510417 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -49,6 +49,8 @@ const SUB_TEXT_SIZE_FACTOR = 1 / 6 const SUB_TEXT_SIZE_MIN_THRESHOLD = 24 const SUB_TEXT_SIZE_MAX_THRESHOLD = 40 +const ICON_PADDING_FACTOR = 0.4 + // Compute text width before rendering // Not exactly precise but close enough const getTextWidth = (text, font) => { @@ -61,6 +63,8 @@ const getTextWidth = (text, font) => { const getTextHeightForNumbers = (textSize) => textSize * ACTUAL_NUMBER_HEIGHT_FACTOR +const getIconPadding = (textSize) => textSize * ICON_PADDING_FACTOR + const getTextSize = ( formattedValue, containerWidth, @@ -75,7 +79,7 @@ const getTextSize = ( if (size > 0) { while ( getTextWidth(formattedValue, `${size}px Roboto`) + - (showIcon ? size + 50 : 0) > + (showIcon ? getIconPadding(size) : 0) > widthThreshold ) { size = size - 1 @@ -98,7 +102,7 @@ const generateValueSVG = ({ }) => { // const ratio = containerHeight / containerWidth // const iconSize = 300 - const iconPadding = 50 + // const iconPadding = 50 const showIcon = icon && formattedValue !== noData.text // const textSize = iconSize * 0.85 const textSize = getTextSize( @@ -158,7 +162,7 @@ const generateValueSVG = ({ iconSvgNode.setAttribute('y', (iconSize / 2 - topMargin / 2) * -1) iconSvgNode.setAttribute( 'x', - `-${(iconSize + iconPadding + textWidth) / 2}` + `-${(iconSize + getIconPadding(textSize) + textWidth) / 2}` ) iconSvgNode.setAttribute('style', `color: ${fillColor}`) @@ -186,7 +190,10 @@ const generateValueSVG = ({ : letterSpacing ) textNode.setAttribute('text-anchor', 'middle') - textNode.setAttribute('x', showIcon ? `${(iconSize + iconPadding) / 2}` : 0) + textNode.setAttribute( + 'x', + showIcon ? `${(iconSize + getIconPadding(textSize)) / 2}` : 0 + ) // vertical align, "alignment-baseline: central" is not supported by Batik textNode.setAttribute( 'y', @@ -205,8 +212,7 @@ const generateValueSVG = ({ subTextNode.setAttribute('font-size', subTextSize) subTextNode.setAttribute('y', iconSize / 2 + topMargin / 2) subTextNode.setAttribute('dy', subTextSize * 1.7) - // subTextNode.setAttribute('fill', textColor) - subTextNode.setAttribute('fill', fillColor) + subTextNode.setAttribute('fill', textColor) subTextNode.appendChild(document.createTextNode(subText)) svgValue.appendChild(subTextNode) From fc83911fd10b4f37b0d25dca9b7a9f4540b7444d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Fri, 26 May 2023 09:31:09 +0200 Subject: [PATCH 10/13] fix: adjust const values --- .../config/generators/dhis/singleValue.js | 88 +++++++++---------- 1 file changed, 40 insertions(+), 48 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 5a0510417..cef5af50a 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -29,10 +29,13 @@ const ACTUAL_TEXT_WIDTH_FACTOR = 0.9 const ACTUAL_NUMBER_HEIGHT_FACTOR = 0.7 // do not allow text width to exceed this threshold -const TEXT_WIDTH_CONTAINER_WIDTH_THRESHOLD = 0.9 +// todo: text width vs viewbox = complicated +const TEXT_WIDTH_CONTAINER_WIDTH_FACTOR = 1.5 -// do not allow text size to exceed this threshold -const TEXT_SIZE_CONTAINER_HEIGHT_THRESHOLD = 0.4 +// do not allow text size to exceed these thresholds +const TEXT_SIZE_CONTAINER_HEIGHT_FACTOR = 0.6 +const TEXT_SIZE_MAX_THRESHOLD = 400 +// const TEXT_SIZE_MIN_THRESHOLD = 100 // multiply text size with this factor // to get an appropriate letter spacing @@ -45,11 +48,11 @@ const TOP_MARGIN_FIXED = 16 // multiply text size with this factor // to get an appropriate sub text size -const SUB_TEXT_SIZE_FACTOR = 1 / 6 -const SUB_TEXT_SIZE_MIN_THRESHOLD = 24 +const SUB_TEXT_SIZE_FACTOR = 0.5 +const SUB_TEXT_SIZE_MIN_THRESHOLD = 26 const SUB_TEXT_SIZE_MAX_THRESHOLD = 40 -const ICON_PADDING_FACTOR = 0.4 +const ICON_PADDING_FACTOR = 0.3 // Compute text width before rendering // Not exactly precise but close enough @@ -57,13 +60,15 @@ const getTextWidth = (text, font) => { const canvas = document.createElement('canvas') const context = canvas.getContext('2d') context.font = font - return context.measureText(text).width * ACTUAL_TEXT_WIDTH_FACTOR + return Math.round( + context.measureText(text).width * ACTUAL_TEXT_WIDTH_FACTOR + ) } const getTextHeightForNumbers = (textSize) => textSize * ACTUAL_NUMBER_HEIGHT_FACTOR -const getIconPadding = (textSize) => textSize * ICON_PADDING_FACTOR +const getIconPadding = (textSize) => Math.round(textSize * ICON_PADDING_FACTOR) const getTextSize = ( formattedValue, @@ -71,19 +76,21 @@ const getTextSize = ( containerHeight, showIcon ) => { - let size = Math.round( - containerHeight * TEXT_SIZE_CONTAINER_HEIGHT_THRESHOLD + let size = Math.min( + Math.round(containerHeight * TEXT_SIZE_CONTAINER_HEIGHT_FACTOR), + TEXT_SIZE_MAX_THRESHOLD ) - const widthThreshold = containerWidth * TEXT_WIDTH_CONTAINER_WIDTH_THRESHOLD - - if (size > 0) { - while ( - getTextWidth(formattedValue, `${size}px Roboto`) + - (showIcon ? getIconPadding(size) : 0) > - widthThreshold - ) { - size = size - 1 - } + + const widthThreshold = Math.round( + containerWidth * TEXT_WIDTH_CONTAINER_WIDTH_FACTOR + ) + + const textWidth = + getTextWidth(formattedValue, `${size}px Roboto`) + + (showIcon ? getIconPadding(size) : 0) + + if (textWidth > widthThreshold) { + size = Math.round(size * (widthThreshold / textWidth)) } return size @@ -98,27 +105,21 @@ const generateValueSVG = ({ noData, containerWidth, containerHeight, - topMargin, + topMargin = 0, }) => { - // const ratio = containerHeight / containerWidth - // const iconSize = 300 - // const iconPadding = 50 const showIcon = icon && formattedValue !== noData.text - // const textSize = iconSize * 0.85 + const textSize = getTextSize( formattedValue, containerWidth, containerHeight, showIcon ) - console.log('topMargin', topMargin) - console.log('textSize', textSize) const textWidth = getTextWidth(formattedValue, `${textSize}px Roboto`) - console.log('textWidth', textWidth) - // const subTextSize = 40 const iconSize = textSize + console.log('SUB_TEXT_SIZE_FACTOR', SUB_TEXT_SIZE_FACTOR) const subTextSize = textSize * SUB_TEXT_SIZE_FACTOR > SUB_TEXT_SIZE_MAX_THRESHOLD ? SUB_TEXT_SIZE_MAX_THRESHOLD @@ -126,14 +127,6 @@ const generateValueSVG = ({ ? SUB_TEXT_SIZE_MIN_THRESHOLD : textSize * SUB_TEXT_SIZE_FACTOR - // let viewBoxWidth = textWidth - - // if (showIcon) { - // viewBoxWidth += iconSize + iconPadding - // } - - // const viewBoxHeight = viewBoxWidth * ratio - const svgValue = document.createElementNS(svgNS, 'svg') svgValue.setAttribute('viewBox', `0 0 ${containerWidth} ${containerHeight}`) svgValue.setAttribute('width', '50%') @@ -154,12 +147,21 @@ const generateValueSVG = ({ if (showIcon) { // embed icon to allow changing color // (elements with fill need to use "currentColor" for this to work) - const iconSvgNode = document.createElementNS(svgNS, 'svg') iconSvgNode.setAttribute('viewBox', '0 0 48 48') iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) iconSvgNode.setAttribute('y', (iconSize / 2 - topMargin / 2) * -1) + console.log( + 'iconSize', + iconSize, + 'iconPadding', + getIconPadding(textSize), + 'textWidth', + textWidth, + 'TOTAL', + iconSize + getIconPadding(textSize) + textWidth + ) iconSvgNode.setAttribute( 'x', `-${(iconSize + getIconPadding(textSize) + textWidth) / 2}` @@ -319,16 +321,6 @@ const generateDVItem = ( icon, } ) => { - console.log('config', config) - console.log('svgContainer', svgContainer) - console.log('width', width) - console.log('height', height) - console.log('valueColor', valueColor) - console.log('backgroundColor', backgroundColor) - console.log('titleColor', titleColor) - console.log('fontStyle', fontStyle) - console.log('icon', icon) - if (backgroundColor) { svgContainer.setAttribute( 'style', From 0de3c439f98b6a75278ea6823d10cfb747866f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Fri, 26 May 2023 11:47:53 +0200 Subject: [PATCH 11/13] chore: remove logs --- .../config/generators/dhis/singleValue.js | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index cef5af50a..07c087365 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -119,7 +119,7 @@ const generateValueSVG = ({ const textWidth = getTextWidth(formattedValue, `${textSize}px Roboto`) const iconSize = textSize - console.log('SUB_TEXT_SIZE_FACTOR', SUB_TEXT_SIZE_FACTOR) + const subTextSize = textSize * SUB_TEXT_SIZE_FACTOR > SUB_TEXT_SIZE_MAX_THRESHOLD ? SUB_TEXT_SIZE_MAX_THRESHOLD @@ -152,16 +152,6 @@ const generateValueSVG = ({ iconSvgNode.setAttribute('width', iconSize) iconSvgNode.setAttribute('height', iconSize) iconSvgNode.setAttribute('y', (iconSize / 2 - topMargin / 2) * -1) - console.log( - 'iconSize', - iconSize, - 'iconPadding', - getIconPadding(textSize), - 'textWidth', - textWidth, - 'TOTAL', - iconSize + getIconPadding(textSize) + textWidth - ) iconSvgNode.setAttribute( 'x', `-${(iconSize + getIconPadding(textSize) + textWidth) / 2}` @@ -343,7 +333,7 @@ const generateDVItem = ( fontStyle && fontStyle[FONT_STYLE_VISUALIZATION_TITLE], FONT_STYLE_VISUALIZATION_TITLE ) - console.log('titleFontStyle', titleFontStyle) + const titleYPosition = TOP_MARGIN_FIXED + parseInt(titleFontStyle[FONT_STYLE_OPTION_FONT_SIZE]) + @@ -425,16 +415,6 @@ const generateDVItem = ( } svgContainer.appendChild(svgWrapper) - console.log('title size', parseInt(title.getAttribute('font-size'))) - console.log('subtitle size', parseInt(subtitle.getAttribute('font-size'))) - console.log( - 'top margin', - (title ? parseInt(title.getAttribute('font-size')) : 0) + - (subtitle ? parseInt(subtitle.getAttribute('font-size')) : 0) - ) - - console.log('config.title', !!config.title) - console.log('config.subtitle', !!config.subtitle) svgContainer.appendChild( generateValueSVG({ From 314c99b64479a9b01cd4f528185c3156358b36e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Fri, 26 May 2023 14:35:57 +0200 Subject: [PATCH 12/13] chore: comments and cleanup --- .../config/generators/dhis/singleValue.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 07c087365..76b176e0c 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -22,20 +22,21 @@ const svgNS = 'http://www.w3.org/2000/svg' // multiply text width with this factor // to get very close to actual text width +// nb: dependent on viewbox etc const ACTUAL_TEXT_WIDTH_FACTOR = 0.9 // multiply value text size with this factor // to get very close to the actual number height -const ACTUAL_NUMBER_HEIGHT_FACTOR = 0.7 +// as numbers don't go below the baseline like e.g. "j" and "g" +const ACTUAL_NUMBER_HEIGHT_FACTOR = 0.67 // do not allow text width to exceed this threshold -// todo: text width vs viewbox = complicated +// a threshold >1 does not really make sense but text width vs viewbox is complicated const TEXT_WIDTH_CONTAINER_WIDTH_FACTOR = 1.5 -// do not allow text size to exceed these thresholds +// do not allow text size to exceed this const TEXT_SIZE_CONTAINER_HEIGHT_FACTOR = 0.6 const TEXT_SIZE_MAX_THRESHOLD = 400 -// const TEXT_SIZE_MIN_THRESHOLD = 100 // multiply text size with this factor // to get an appropriate letter spacing @@ -52,6 +53,8 @@ const SUB_TEXT_SIZE_FACTOR = 0.5 const SUB_TEXT_SIZE_MIN_THRESHOLD = 26 const SUB_TEXT_SIZE_MAX_THRESHOLD = 40 +// multiply text size with this factor +// to get an appropriate icon padding const ICON_PADDING_FACTOR = 0.3 // Compute text width before rendering @@ -186,7 +189,6 @@ const generateValueSVG = ({ 'x', showIcon ? `${(iconSize + getIconPadding(textSize)) / 2}` : 0 ) - // vertical align, "alignment-baseline: central" is not supported by Batik textNode.setAttribute( 'y', topMargin / 2 + getTextHeightForNumbers(textSize) / 2 From ebe1ea60ed6a09abd03186d64fa69bd790e09b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Henrik=20=C3=98verland?= Date: Tue, 30 May 2023 11:57:24 +0200 Subject: [PATCH 13/13] fix: adjust width const --- src/visualizations/config/generators/dhis/singleValue.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/visualizations/config/generators/dhis/singleValue.js b/src/visualizations/config/generators/dhis/singleValue.js index 76b176e0c..199765800 100644 --- a/src/visualizations/config/generators/dhis/singleValue.js +++ b/src/visualizations/config/generators/dhis/singleValue.js @@ -32,7 +32,7 @@ const ACTUAL_NUMBER_HEIGHT_FACTOR = 0.67 // do not allow text width to exceed this threshold // a threshold >1 does not really make sense but text width vs viewbox is complicated -const TEXT_WIDTH_CONTAINER_WIDTH_FACTOR = 1.5 +const TEXT_WIDTH_CONTAINER_WIDTH_FACTOR = 1.3 // do not allow text size to exceed this const TEXT_SIZE_CONTAINER_HEIGHT_FACTOR = 0.6