Added minimal navigation breadcrumbs to doctests.

This commit is contained in:
2023-05-09 13:25:39 +02:00
parent 13e0473328
commit 9501264f08
71 changed files with 5700 additions and 5332 deletions
+152 -162
View File
@@ -1,173 +1,163 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Doctests</title>
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css">
<link rel="stylesheet" href="../css/doctest.css">
<script src="./3rdparty/highlight/highlight.pack.js"></script>
<script src="../dist/iwmlib.js"></script>
</head>
<body onload="Doctest.run()">
<main>
<h1>
Utils
</h1>
<p>
Utility functions can be used across modules. To avoid name conflicts most
of them are defined as static class functions (i.e. the class mainly serves
as a namespace). Typically this class name is in the plural, e.g. "Points", "Dates" to ensure that
existing class names like "Point", "Date" are not in conflict with the namespace.
</p>
<h2>
Cycle
</h2>
<p>Cycles simplify to switch between values in a cyclic way.</p>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Doctests</title>
<link rel="stylesheet" href="./3rdparty/highlight/styles/default.css" />
<link rel="stylesheet" href="../css/doctest.css" />
<script src="./3rdparty/highlight/highlight.pack.js"></script>
<script src="../dist/iwmlib.js"></script>
</head>
<body onload="Doctest.run()">
<main>
<h1><a href="index.html">lib.</a>Utils</h1>
<p>
Utility functions can be used across modules. To avoid name conflicts most of them are defined as static
class functions (i.e. the class mainly serves as a namespace). Typically this class name is in the
plural, e.g. "Points", "Dates" to ensure that existing class names like "Point", "Date" are not in
conflict with the namespace.
</p>
<h2>Cycle</h2>
<p>Cycles simplify to switch between values in a cyclic way.</p>
<script class="doctest">
<script class="doctest">
let cycle = new Cycle(1, 2, 3)
Doctest.expect(cycle.next(), 1)
Doctest.expect(cycle.next(), 2)
Doctest.expect(cycle.next(), 3)
Doctest.expect(cycle.next(), 1)
</script>
let cycle = new Cycle(1, 2, 3)
Doctest.expect(cycle.next(), 1)
Doctest.expect(cycle.next(), 2)
Doctest.expect(cycle.next(), 3)
Doctest.expect(cycle.next(), 1)
<h2>Dates</h2>
<script class="doctest">
let feb1900 = new Date(1900, 1, 1)
Doctest.expect(Dates.daysInMonth(feb1900), 28)
// 1900 was no leap year
let feb2000 = new Date(2000, 1, 1)
Doctest.expect(Dates.daysInMonth(feb2000), 29)
// 2000 was a leap year
</script>
let mar1913 = new Date(1913, 2, 1)
Doctest.expect(Dates.daysInMonth(mar1913), 31)
</script>
<h2>
Dates
</h2>
<script class="doctest">
<p>
A tricky problem is to iterate over years, months, and days to label timelines and calendars in a
consistent way. This can lead to problems with standard (CET) and summer time (CEST). To illustrate the
problem look at the following example. Although march has 31 days the formatted UTC string shows "30.3".
Also note that the standard new Date() constructor uses a zero-based month:
</p>
<script class="doctest">
let format = { timeZone: 'UTC' }
let lastMar1913 = new Date(1913, 2, 31)
Doctest.expect(lastMar1913.toLocaleDateString('de', format), '30.3.1913')
</script>
<p>The following iterators guarantee that correct labels are generated:</p>
let feb1900 = new Date(1900, 1, 1)
Doctest.expect(Dates.daysInMonth(feb1900), 28)
// 1900 was no leap year
let feb2000 = new Date(2000, 1, 1)
Doctest.expect(Dates.daysInMonth(feb2000), 29)
// 2000 was a leap year
<script class="doctest">
let lastDay = null
for (let day of Dates.iterDays(mar1913)) {
lastDay = day
}
Doctest.expect(lastDay.toLocaleDateString('de', format), '31.3.1913')
</script>
let mar1913 = new Date(1913, 2, 1)
Doctest.expect(Dates.daysInMonth(mar1913), 31)
</script>
<h2>Sets</h2>
<p>
Unfortunately the common set operations of other languages are missing in JavaScript. Therefore we use a
Sets helper class with static methods:
</p>
<script class="doctest">
let set1 = new Set([1, 2, 3])
let set2 = new Set([2, 3, 4, 5])
let set3 = new Set([2, 3, 6])
<p>
A tricky problem is to iterate over years, months, and days to label timelines
and calendars in a consistent way. This can lead to problems with standard
(CET) and summer time (CEST).
Doctest.expect(Array.from(Sets.intersect(set1, set2, set3)), [2, 3])
Doctest.expect(Array.from(Sets.union(set1, set2, set3)), [1, 2, 3, 4, 5, 6])
Doctest.expect(Array.from(Sets.difference(set2, set1, set3)), [4, 5])
</script>
<h2>Polygon</h2>
<p>
An intersection of polygons is needed to compute the overlap of rotated rectangles. We are using the
library <a href="https://gist.github.com/cwleonard/e124d63238bda7a3cbfa">jspolygon.js</a> but provide a
more convenient API that is compatible with arrays of absolute points.
</p>
<p>
To detect intersection with another Polygon object, the instance method uses the Separating Axis
Theorem. It returns false if there is no intersection, or an object if there is. The object contains 2
fields, overlap and axis. Moving the other polygon by overlap on axis will get the polygons out of
intersection.
</p>
<p>
The following triangles show an overlap. Moving the triangle along the red line would remove the
overlap.
</p>
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
<script class="doctest">
let context = canvas.getContext('2d')
// The jspolygon syntax
let a = Polygon.fromPoints([
{ x: 20, y: 20 },
{ x: 100, y: 100 },
{ x: 150, y: 50 }
])
a.draw(context)
let b = Polygon.fromPoints([
{ x: 70, y: 50 },
{ x: 150, y: 10 },
{ x: 200, y: 70 }
])
b.draw(context)
To illustrate the problem look at the following example. Although march has 31 days
the formatted UTC string shows "30.3". Also note that the standard
new Date() constructor uses a zero-based month:
</p>
<script class="doctest">
let format = { timeZone: 'UTC'}
let lastMar1913 = new Date(1913, 2, 31)
Doctest.expect(lastMar1913.toLocaleDateString("de", format), "30.3.1913")
context.strokeStyle = '#ff0000'
context.beginPath()
let result = a.intersectsWith(b)
if (result != false) {
let { overlap, axis } = result
context.moveTo(b.center.x, b.center.y)
let target = Points.add(b.center, { x: overlap * axis.x, y: overlap * axis.y })
context.lineTo(target.x, target.y)
}
context.stroke()
</script>
<h2>Low Pass Filter</h2>
<p>
Low Pass Filter muffles fast (high-frequency) changes to the signal. For more information visit the
<a href="http://en.wikipedia.org/wiki/Low-pass_filter">wikipedia article</a>.
</p>
<script class="doctest">
let lpf = new LowPassFilter(0.5)
Doctest.expect(
lpf.smoothArray([10, 8, 9, 10, 12, 8, 50, 10, 12, 8]),
[10, 9, 9, 10, 11, 9, 30, 20, 16, 12]
)
</script>
<p>
The following iterators guarantee that correct labels are generated:</p>
Doctest.expect(lpf.next(20), 10.0)
Doctest.expect(lpf.next(20), 12.5)
Doctest.expect(lpf.next(20), 14.375)
Doctest.expect(lpf.next(20), 15.78125)
<script class="doctest">
let lastDay = null
for(let day of Dates.iterDays(mar1913)) {
lastDay = day
}
Doctest.expect(lastDay.toLocaleDateString("de", format), "31.3.1913")
</script>
<h2>
Sets
</h2>
<p>
Unfortunately the common set operations of other languages are missing in JavaScript. Therefore we use
a Sets helper class with static methods:
</p>
<script class="doctest">
let set1 = new Set([1, 2, 3])
let set2 = new Set([2, 3, 4, 5])
let set3 = new Set([2, 3, 6])
Doctest.expect(Array.from(Sets.intersect(set1, set2, set3)), [2, 3])
Doctest.expect(Array.from(Sets.union(set1, set2, set3)), [1, 2, 3, 4, 5, 6])
Doctest.expect(Array.from(Sets.difference(set2, set1, set3)), [4, 5])
</script>
<h2>
Polygon
</h2>
<p>An intersection of polygons is needed to compute the overlap of rotated rectangles.
We are using the library <a href="https://gist.github.com/cwleonard/e124d63238bda7a3cbfa">jspolygon.js</a> but provide a more convenient API that
is compatible with arrays of absolute points.
</p>
<p>To detect intersection with another Polygon object, the instance
method uses the Separating Axis Theorem. It returns false
if there is no intersection, or an object if there is. The object
contains 2 fields, overlap and axis. Moving the other polygon by overlap
on axis will get the polygons out of intersection.
</p>
<p>The following triangles show an overlap. Moving the triangle along the red line would remove the overlap.
</p>
<canvas id="canvas" class="grayBorder interactive">Canvas not supported</canvas>
<script class="doctest">
let context = canvas.getContext("2d")
// The jspolygon syntax
let a = Polygon.fromPoints([{ x: 20, y: 20}, { x: 100, y: 100}, { x: 150, y: 50}])
a.draw(context)
let b = Polygon.fromPoints([{x: 70, y: 50}, {x: 150, y: 10}, {x: 200, y: 70}])
b.draw(context)
context.strokeStyle = '#ff0000'
context.beginPath()
let result = a.intersectsWith(b)
if (result != false) {
let {overlap, axis} = result
context.moveTo(b.center.x, b.center.y)
let target = Points.add(b.center, { x: overlap * axis.x, y: overlap * axis.y })
context.lineTo(target.x, target.y)
}
context.stroke()
</script>
<h2>
Low Pass Filter
</h2>
<p>
Low Pass Filter muffles fast (high-frequency) changes to the signal.
For more information visit the <a href="http://en.wikipedia.org/wiki/Low-pass_filter">wikipedia article</a>.
</p>
<script class="doctest">
let lpf = new LowPassFilter(0.5)
Doctest.expect(lpf.smoothArray([10,8,9,10,12,8,50,10,12,8]), [10,9,9,10,11,9,30,20,16,12])
Doctest.expect(lpf.next(20), 10.0)
Doctest.expect(lpf.next(20), 12.5)
Doctest.expect(lpf.next(20), 14.375)
Doctest.expect(lpf.next(20), 15.78125)
lpf = new LowPassFilter(0.2)
lpf.setup([10,10,10,10,10,10,10,10,10,10])
Doctest.expect(lpf.next(20), 12.0)
Doctest.expect(lpf.next(10), 10.32)
</script>
<h2>
References
</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Circular_buffer">
Circular buffer
</a></li>
<li><a href="http://stackoverflow.com/questions/20867562/create-a-date-object-with-cet-timezone">
Create a Date object with CET timezone
</a></li>
<li> <a href="http://stackoverflow.com/questions/315760/what-is-the-best-way-to-determine-the-number-of-days-in-a-month-with-javascript">
What is the best way to determine the number of days in a month with javascript?
</a></li>
</ul>
</main>
</body>
lpf = new LowPassFilter(0.2)
lpf.setup([10, 10, 10, 10, 10, 10, 10, 10, 10, 10])
Doctest.expect(lpf.next(20), 12.0)
Doctest.expect(lpf.next(10), 10.32)
</script>
<h2>References</h2>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Circular_buffer"> Circular buffer </a></li>
<li>
<a href="http://stackoverflow.com/questions/20867562/create-a-date-object-with-cet-timezone">
Create a Date object with CET timezone
</a>
</li>
<li>
<a
href="http://stackoverflow.com/questions/315760/what-is-the-best-way-to-determine-the-number-of-days-in-a-month-with-javascript"
>
What is the best way to determine the number of days in a month with javascript?
</a>
</li>
</ul>
</main>
</body>
</html>