1
0
mirror of https://github.com/Jermolene/TiddlyWiki5 synced 2024-11-27 03:57:21 +00:00

DynaView plugin: Add font "optisizer"

A mechanism to choose the optimum font size of a passage of text to yield a particular numbr of characters per line.

@BurningTreeC I've made some minor consistency tweaks and cleanups to the viewport stuff, too.
This commit is contained in:
Jermolene 2018-03-10 10:33:34 +00:00
parent 7cb54f32c6
commit dbfe28094c
7 changed files with 177 additions and 28 deletions

View File

@ -0,0 +1,5 @@
title: $:/config/DynaView/
Optisizer: no
Optisizer/Text: ABCDEFGHIJKLMnopqrstuvwxyzABCDEFGHIJKLMnopqrstuvwxyz
ViewportDimensions: no

View File

@ -1,4 +1,5 @@
title: $:/plugins/tiddlywiki/dynaview/config
<$checkbox tiddler="$:/config/ViewportDimensions" field="text" checked="yes" unchecked="">&nbsp;&nbsp;enable dynamic saving of the viewport dimensions</$checkbox>
- //the values get stored in // $:/state/viewport/width and $:/state/viewport/height
<$checkbox tiddler="$:/config/DynaView/ViewportDimensions" field="text" checked="yes" unchecked=""> Enable dynamic saving of the viewport [[width|$:/state/DynaView/ViewportDimensions/Width]] and [[height|$:/state/DynaView/ViewportDimensions/Height]]</$checkbox>

View File

@ -7,7 +7,7 @@ The components of this plugin include:
* A background task that:
** performs specified actions when elements are scrolled into view
** updates certain base classes on the `document.body` according to the current zoom level
** if enabled in the dynaview config panel - dynamically stores the viewport dimensions in $:/state/viewport/width and $:/state/viewport/height
** if enabled in the DynaView config panel - dynamically stores the viewport dimensions in $:/state/viewport/width and $:/state/viewport/height
* Pre-configured CSS classes to simplify using those base classes
* Usage examples
@ -15,6 +15,32 @@ The components of this plugin include:
The background task detects when elements with the class `tc-dynaview-set-tiddler-when-visible` scroll into view. The first time that they do, the background task assigns the value in the attribute `data-dynaview-set-value` to the tiddler whose title is in the attribute `data-dynaview-set-tiddler`. This assignment can be tied to a reveal widget to cause content to be displayed when it becomes visible. If the class `tc-dynaview-expand-viewport` is set then the viewport is expanded so that the processing occurs when elements move near the viewport.
! Viewport Size Features
!! Viewport Size Tracking
The background task can optionally dynamically update a pair of state tiddlers with the dimensions of the browser viewport.
* Set the configuration tiddler $:/config/DynaView/ViewportDimensions to the text "yes" to enable this feature
* The viewport dimensions can be found in $:/state/DynaView/ViewportDimensions/Width and $:/state/DynaView/ViewportDimensions/Height
!! Font "Optisizer"
The background task can optionally dynamically optimise the font size of a passage of text to match a desired line length.
* Set the configuration tiddler $:/config/DynaView/Optisizer to the text "yes" to enable this feature
* Optionally, update the configuration tiddler $:/config/DynaView/Optisizer/Text with the "maquette" -- a character string matchng the desired length (this string should not include spaces).
* Assign the following CSS classes to appropriate elements on the page:
** `.tc-dynaview-optisizer-site` for an HTML element whose `offsetWidth` property gives the desired output width
** `.tc-dynaview-optisizer-maquette` for an HTML element that will contain the maquette
* The computed optimum font size can be found in the tiddler $:/state/DynaView/Optisizer/FontSize
The tiddler $:/plugins/tiddlywiki/dynaview/optisizer-maquette contains an example configuration that can be used to adjust the size of tiddler body text. To use it:
* Set $:/config/DynaView/Optisizer to the text "yes"
* Set $:/themes/tiddlywiki/vanilla/metrics/bodyfontsize to `{{$:/state/DynaView/Optisizer/FontSize}}`
* Set $:/themes/tiddlywiki/vanilla/metrics/bodylineheight to `1.5` to ensure that the line height matches the font size
! Zoom Features
!! Document Body Zoom Classes

View File

@ -18,32 +18,100 @@ exports.platforms = ["browser"];
exports.after = ["render"];
exports.synchronous = true;
var isWaitingForAnimationFrame = false;
var isWaitingForAnimationFrame = 0, // Bitmask:
ANIM_FRAME_CAUSED_BY_LOAD = 1, // Animation frame was requested because of page load
ANIM_FRAME_CAUSED_BY_SCROLL = 2, // Animation frame was requested because of page scroll
ANIM_FRAME_CAUSED_BY_RESIZE = 4; // Animation frame was requested because of window resize
exports.startup = function() {
window.addEventListener("load",onScrollOrResize,false);
window.addEventListener("scroll",onScrollOrResize,false);
window.addEventListener("resize",onScrollOrResize,false);
window.addEventListener("load",onLoad,false);
window.addEventListener("scroll",onScroll,false);
window.addEventListener("resize",onResize,false);
$tw.hooks.addHook("th-page-refreshed",function() {
optisizeFonts();
checkVisibility();
if($tw.wiki.getTiddlerText("$:/config/ViewportDimensions") === "yes") {
saveViewportDimensions();
}
saveViewportDimensions();
});
};
function onScrollOrResize(event) {
function onLoad(event) {
if(!isWaitingForAnimationFrame) {
window.requestAnimationFrame(function() {
setZoomClasses();
checkVisibility();
if($tw.wiki.getTiddlerText("$:/config/ViewportDimensions") === "yes") {
saveViewportDimensions();
}
isWaitingForAnimationFrame = false;
});
window.requestAnimationFrame(worker);
}
isWaitingForAnimationFrame |= ANIM_FRAME_CAUSED_BY_LOAD;
}
function onScroll(event) {
if(!isWaitingForAnimationFrame) {
window.requestAnimationFrame(worker);
}
isWaitingForAnimationFrame |= ANIM_FRAME_CAUSED_BY_SCROLL;
}
function onResize(event) {
if(!isWaitingForAnimationFrame) {
window.requestAnimationFrame(worker);
}
isWaitingForAnimationFrame |= ANIM_FRAME_CAUSED_BY_RESIZE;
}
function worker() {
if(isWaitingForAnimationFrame & (ANIM_FRAME_CAUSED_BY_RESIZE | ANIM_FRAME_CAUSED_BY_LOAD)) {
optisizeFonts();
saveViewportDimensions();
}
setZoomClasses();
checkVisibility();
isWaitingForAnimationFrame = 0;
}
var lastSiteWidth, lastMaquetteString;
function optisizeFonts() {
if($tw.wiki.getTiddlerText("$:/config/DynaView/Optisizer") === "yes") {
var domSite = document.querySelector(".tc-dynaview-optisizer-site"),
domMaquette = document.querySelector(".tc-dynaview-optisizer-maquette");
if(domSite && domMaquette) {
// Check that we're not at the same size as last time
if(domSite.offsetWidth === lastSiteWidth && $tw.wiki.getTiddlerText("$:/config/DynaView/Optisizer/Text") === lastMaquetteString) {
return;
}
// Get the current font size
domMaquette.style.fontSize = "";
var initialFontSize = parseInt(window.getComputedStyle(domMaquette).fontSize,10),
minFontSize = 1,
maxFontSize = 100,
adjustFontSize = maxFontSize,
newFontSize = initialFontSize,
maquetteWidth;
lastSiteWidth = domSite.offsetWidth;
lastMaquetteString = $tw.wiki.getTiddlerText("$:/config/DynaView/Optisizer/Text");
while(domMaquette.firstChild) {
domMaquette.removeChild(domMaquette.firstChild);
}
domMaquette.appendChild(document.createTextNode(lastMaquetteString));
// We use a binary search algorithm to find the optimum size
do {
// Apply the size we're considering
domMaquette.style.fontSize = newFontSize + "px";
// Measure the width of the maquette
maquetteWidth = domMaquette.offsetWidth;
// Adjust bigger or smaller
if(maquetteWidth < lastSiteWidth) {
newFontSize += adjustFontSize;
} else {
newFontSize -= adjustFontSize;
}
newFontSize = Math.min(newFontSize,maxFontSize);
newFontSize = Math.max(newFontSize,minFontSize);
adjustFontSize = adjustFontSize / 2;
} while (adjustFontSize > 0.5);
var newFontSizeString = newFontSize + "px";
if($tw.wiki.getTiddlerText("$:/state/DynaView/Optisizer/FontSize") !== newFontSizeString) {
$tw.wiki.setText("$:/state/DynaView/Optisizer/FontSize",undefined,undefined,newFontSizeString,undefined);
}
}
}
isWaitingForAnimationFrame = true;
}
function setZoomClasses() {
@ -91,20 +159,22 @@ function checkVisibility() {
var tiddler = element.getAttribute("data-dynaview-set-tiddler"),
value = element.getAttribute("data-dynaview-set-value") || "";
if(tiddler && $tw.wiki.getTiddlerText(tiddler) !== value) {
$tw.wiki.addTiddler(new $tw.Tiddler({title: tiddler, text: value}));
$tw.wiki.addTiddler(new $tw.Tiddler({title: tiddler, text: value}));
}
}
});
}
function saveViewportDimensions() {
var viewportWidth = window.innerWidth || document.documentElement.clientWidth,
viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if($tw.wiki.getTiddlerText("$:/state/viewport/width") !== viewportWidth.toString()) {
$tw.wiki.setText("$:/state/viewport/width",undefined,undefined,viewportWidth.toString(),undefined);
}
if($tw.wiki.getTiddlerText("$:/state/viewport/height") !== viewportHeight.toString()) {
$tw.wiki.setText("$:/state/viewport/height",undefined,undefined,viewportHeight.toString(),undefined);
if($tw.wiki.getTiddlerText("$:/config/DynaView/ViewportDimensions") === "yes") {
var viewportWidth = window.innerWidth || document.documentElement.clientWidth,
viewportHeight = window.innerHeight || document.documentElement.clientHeight;
if($tw.wiki.getTiddlerText("$:/state/DynaView/ViewportDimensions/Width") !== viewportWidth.toString()) {
$tw.wiki.setText("$:/state/DynaView/ViewportDimensions/Width",undefined,undefined,viewportWidth.toString(),undefined);
}
if($tw.wiki.getTiddlerText("$:/state/DynaView/ViewportDimensions/Height") !== viewportHeight.toString()) {
$tw.wiki.setText("$:/state/DynaView/ViewportDimensions/Height",undefined,undefined,viewportHeight.toString(),undefined);
}
}
}

View File

@ -0,0 +1,17 @@
title: $:/plugins/tiddlywiki/dynaview/examples/font-optisizer
tags: $:/tags/dynaviewExamples
caption: Font Optisizer
<$button>
<$action-setfield $tiddler="$:/config/DynaView/Optisizer" $value="yes"/>
<$action-setfield $tiddler="$:/themes/tiddlywiki/vanilla/metrics/bodyfontsize" $value="{{$:/state/DynaView/Optisizer/FontSize}}"/>
<$action-setfield $tiddler="$:/themes/tiddlywiki/vanilla/metrics/bodylineheight" $value="1.5"/>
Enable font optisizer for tiddler body text
</$button>
<$button>
<$action-setfield $tiddler="$:/config/DynaView/Optisizer" $value="no"/>
<$action-setfield $tiddler="$:/themes/tiddlywiki/vanilla/metrics/bodyfontsize" $value="14px"/>
<$action-setfield $tiddler="$:/themes/tiddlywiki/vanilla/metrics/bodylineheight" $value="20px"/>
Disable font optisizer
</$button>

View File

@ -0,0 +1,24 @@
title: $:/plugins/tiddlywiki/dynaview/optisizer-maquette
tags: $:/tags/AboveStory
<div class="tc-tiddler-frame" style="border: none; background: none; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; margin-top: 0; margin-bottom: 0; padding-top: 0; padding-bottom: 0; ">
<div class="tc-tiddler-body tc-dynaview-optisizer-site" style="margin-top: -3em; visibility: hidden;">
X
</div>
</div>
<div style="position: relative;">
<div style="position: absolute; visibility: hidden;">
<div class="tc-dynaview-optisizer-maquette" style="white-space: nowrap;">
</div>
</div>
</div>

View File

@ -6,11 +6,17 @@ This plugin makes it possible to build user interfaces that dynamically respond
* CSS classes that allow rendering to be deferred until the output is scrolled into view
* CSS classes that allow the opacity of DOM elements to vary according to the current zoom level
* A daemon that can dynamically update a pair of state tiddlers with the current dimensions of the browser viewport
* A daemon that can dynamically adjust the size of text to yield a particular number of characters per line
Some points to note about the zoom features:
<<<
* The zoom level currently only works on Safari, both on Mac OS and on the iPhone/iPad
* The zoom level tracked by the plugin is the pinch-zoom level, and not the text-zoom level
* Rather than being progressively rendered as needed, hidden item are rendered with zero opacity. Which means that they can still be interacted with
This is really just a proof of concept to allow the user experience to be evaluated. A production version would need to work in all browsers, which would mean adopting a polyfill such as [[Hammer.js|http://hammerjs.github.io/]] to give us manual pan and zoom support. It would also allow deeper levels of zoom.
<<<