initial import

This commit is contained in:
Sascha Nitsch 2024-07-03 03:06:02 +02:00
commit d6aeabcc22
26 changed files with 3019 additions and 0 deletions

24
.eslintrc.js Normal file
View file

@ -0,0 +1,24 @@
import globals from "globals";
import tseslint from "typescript-eslint";
export default [
{
files: ["**/*.{ts}"],
plugins: ['@typescript-eslint/eslint-plugin', 'eslint-plugin-tsdoc'],
parser: '@typescript-eslint/parser',
parserOptions: {
project: './tsconfig.json',
tsconfigRootDir: __dirname,
ecmaVersion: 'ES6',
sourceType: 'module'
},
rules: {
'tsdoc/syntax': 'warn'
},
languageOptions: {
globals: globals.browser
}
},
...tseslint.configs.recommended,
];

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
node_modules
docs
package-lock.json

107
README.md Normal file
View file

@ -0,0 +1,107 @@
# Presentationmaker.js
![PresentationMaker.js logo](public/img/presentationmaker.png)
## What is
A simple(ish) tool to create presentation from XML source.
For those who fight against typical presentation tools.
## Demo
A live demo can be found [here](https://userdata.contentnation.net/a5970e0955da4472b5f84a8dbb740273/presentation/)
## Features
* HTML output for use in browser
* input from XML file (either single file or embedded into HTML)
* transition between pages
* HTML in elements supported
* Custom templates, you define them, combine them and use it
* powerful calculation inside description and templates thanks to [fparser](https://fparser.alexi.ch/)
* presentation can be formatted via normal CSS
## Installation
If you just want to use it, take a look at the [public/index.html](public/index.html) file. It is a good start to use it. Additionally, you need the [public/presentationmaker.js](public/presentationmaker.js) script.
The CSS is optional, but encouraged.
It provides all the needed boilerplate to get you running.
### Development
If you want to help with development or want to see live updates if you change your xml, check out the project and use
```
npm install
npx webpack serve
```
and a browser pointing to localhost:8080
## Usage
The main presentation file is pure XML with a <presentation> root node.
Below this there are
### <defintions>
These are in the form of
```<name>value<name>```
Later "name" can be used via ```${name}``` in the templates/pages
### &lt;modules&gt;
Similar to the definitions, a &lt;module_name&gt;...&lt;/module_name&gt;
Creates a module that can be used later.
The module itself can use other previously defined modules as
```<module_name optional="value">optional inner content</module_name>```
The parameter you add during use will be available to the module as ```${optional}```
Existing internal modules are
#### calc
Calculates a formula and stores the result in a variable for later use.
Parameters:
* ```name``` the name of the variable
inner text is the formular to be used to calculate the value
#### img
Shows an image.
Parameters:
* ```src``` file name of the image
* ```x``` Left position of the image (relative to the page)
* ```y``` Top position of the image (relative to the page)
* ```width``` Image width
* ```height``` Image height
### options
Creates an effect or transformation layer to affect content that is rendered inside.
Parameters:
* ```opacity``` optional opacity value 0: fully transparent, 1: fully visible
* ```blendmode``` optional one the https://developer.mozilla.org/docs/Web/CSS/mix-blend-mode values
* ```flip``` optional flipping of the image (currently only y supported)
* ```rotate``` rotation values in X,Y,Z form
* ```y``` optional y axis to flip at
Inner XML is the content to display
#### text
Show a text in an invisible bounding box.
Parameters:
* ```x0``` left side of the bounding box.
* ```y0``` top side of the bounding box.
* ```x1``` right side of the bounding box (mutally exclusive to width)
* ```y1``` bottom side of the bounding box (mutally exclisve to height)
* ```pos``` shortcut to x0,y0,x1,y1 (mutually exclusive to above values)
* ```halign``` horizontal alignment in the bounding box, possible values: ```left```, ```center```, ```right```, defaults to ```center```
* ```valign``` vertical alignment in the bounding box, possible value: ```top```, ```center```, ```bottom```, default to ```top```
* ```fontsize``` optional font size in pixel
* ```color``` optional color
Inside the XML is the text to display
### page
This is the section for the actual pages to show.
In the pages, modules, variables as well as calulation can be used.
Parameters:
* ```id``` optional id of the page (useful for CSS styling)
* ```width``` page width, default to the ```width``` variable in the definitions section
* ```height``` page height, default to the ```height``` variable in the definitions section
* ```x``` X position of the page in the canvas, defaults to 0
* ```y``` Y position of the page in the canvas, defaults to 0
* ```z``` Z position of the page in the canvas, defaults to 0
* ```rx``` rotation of the page on the X-Axis in °, defaults to 0
* ```ry``` rotation of the page on the Y-Axis in °, defaults to 0
* ```rz``` rotation of the page on the Z-Axis in °, defaults to 0
* ```vx``` viewport position in X, defaults to ```x```
* ```vy``` viewport position in Y, defaults to ```y```
* ```vz``` viewport position in Z, defaults to ```z```
* ```vwidth``` viewport width, defaults to ```width```
* ```vheight``` viewport width, defaults to ```height```
* ```vrx``` rotation of the vieport on the X-Axis in °, defaults to 0
* ```vry``` rotation of the vieport on the Y-Axis in °, defaults to 0
* ```vrz``` rotation of the vieport on the Z-Axis in °, defaults to 0
* ```name``` name of the page (shown in drop down), defaults to page number
## Example
For a fully featured example, take a look at [public/example.xml](public/example.xml) file.
It show multiple modules, some of them nested, many formular and some HTML inside the text.

1
dist/presentationmaker.js vendored Normal file

File diff suppressed because one or more lines are too long

23
package.json Normal file
View file

@ -0,0 +1,23 @@
{
"name": "presentationmake.js",
"version": "0.0.1",
"description": "A tool to create browser based presentations",
"author": "Sascha Nitsch (grumpydeveloper https://contentnation.net/@grumpydevelop)",
"license": "GPL-3.0-or-later",
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^7.15.0",
"@typescript-eslint/parser": "^7.15.0",
"eslint": "^8.56.0",
"eslint-plugin-tsdoc": "^0.3.0",
"globals": "^15.6.0",
"ts-loader": "^9.5.1",
"typedoc": "^0.26.3",
"typescript": "^5.5.2",
"typescript-eslint": "^7.14.1",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^5.0.4"
},
"dependencies": {
"fparser": "^3.0.1"
}
}

143
public/example.xml Normal file
View file

@ -0,0 +1,143 @@
<presentation>
<definitions>
<width>1920</width>
<height>1080</height>
<defaultfontcolor>#ffffff</defaultfontcolor>
<path>img/</path>
<boxwidth>1720</boxwidth>
<boxinnerx>165</boxinnerx>
<boxinnerwidth>1590</boxinnerwidth>
<boxheight>175</boxheight>
<mirrorline>880</mirrorline>
<headerpos>0,35*${scale},1920*${scale},270*${scale}</headerpos>
<headersize>90</headersize>
<boxx>105</boxx>
<box3_1>235</box3_1>
<box3_2>445</box3_2>
<box3_3>655</box3_3>
<listsize>72</listsize>
<transition>transform</transition>
<scale>1</scale>
</definitions>
<modules>
<defaultbg>
<img src="${path}bg.jpg" x="0" y="0" width="${width}" height="${height}"></img>
<img src="${path}logo.svg" x="40*${scale}" y="970*${scale}" width="82*${scale}" height="83*${scale}"></img>
<text x0="0" y0="1000*${scale}" x1="1920*${scale}" y1="1060*${scale}" size="40*${scale}">Introduction to presentationmaker.js</text>
<text x0="1700*${scale}" y0="20*${scale}" x1="1900*${scale}" y1="60*${scale}" size="20*${scale}" halign="right">${page}/${numpages}</text>
</defaultbg>
<boxx3>
<defaultbg />
<img src="${path}box.png" x="${boxx}*${scale}" y="${box3_1}*${scale}" width="${boxwidth}*${scale}" height="${boxheight}*${scale}"></img>
<img src="${path}box.png" x="${boxx}*${scale}" y="${box3_2}*${scale}" width="${boxwidth}*${scale}" height="${boxheight}*${scale}"></img>
<img src="${path}box.png" x="${boxx}*${scale}" y="${box3_3}*${scale}" width="${boxwidth}*${scale}" height="${boxheight}*${scale}"></img>
</boxx3>
<box3>
<boxx3></boxx3>
<text pos="${headerpos}" size="${headersize}" halign="center" valign="center">${headertext}</text>
<text x0="${boxinnerx}*${scale}" y0="${box3_1}*${scale}" w="${boxinnerwidth}*${scale}" h="${boxheight}*${scale}" size="${listsize}*${scale}" halign="left" valign="center">${text1}</text>
<text x0="${boxinnerx}*${scale}" y0="${box3_2}*${scale}" w="${boxinnerwidth}*${scale}" h="${boxheight}*${scale}" size="${listsize}*${scale}" halign="left" valign="center">${text2}</text>
<text x0="${boxinnerx}*${scale}" y0="${box3_3}*${scale}" w="${boxinnerwidth}*${scale}" h="${boxheight}*${scale}" size="${listsize}*${scale}" halign="left" valign="center">${text3}</text>
</box3>
<box3r>
<options rotate="0,0,90">
<boxx3 width="${height}" heigh="${width}"></boxx3>
<text pos="200,35,1080,220" size="${headersize}" halign="center" valign="center">${headertext}</text>
<text x0="${boxinnerx}" y0="${box3_1}" w="${boxinnerwidth}" h="${boxheight}" size="${listsize}" halign="left" valign="center">${text1}</text>
<text x0="${boxinnerx}" y0="${box3_2}" w="${boxinnerwidth}" h="${boxheight}" size="${listsize}" halign="left" valign="center">${text2}</text>
<text x0="${boxinnerx}" y0="${box3_3}" w="${boxinnerwidth}" h="${boxheight}" size="${listsize}" halign="left" valign="center">${text3}</text>
</options>
</box3r>
<mirrorimage>
<calc name="y2">((${mirrorline} - ${y}) +${mirrorline} - ${h})</calc>
<img src="${path}${img}" x="${x}*${scale}" y="${y}*${scale}" width="${w}*${scale}" height="${h}*${scale}"></img>
<options opacity=".44" flip="v" y="${height}">
<img src="${path}${img}" x="${x}*${scale}" y="(${height} - ${mirrorline}*${scale}) - ${scale} * (${mirrorline} - ${y})" width="${w}*${scale}" height="${h}*${scale}" mask-image="linear-gradient(0deg, rgba(0, 0, 0, 1) 0%, rgba(0, 0, 0, 0.1) 40%)"></img>
</options>
</mirrorimage>
</modules>
<pages>
<page name="Welcome">
<defaultbg />
<mirrorimage img="presentationmaker.svg" x="642" y="600" w="634" h="374"></mirrorimage>
<text pos="${headerpos}" size="${headersize}" halign="center" valign="center">Welcome to the presentationmaker.js example</text>
<text x0="100" y0="450" x1="1820" y1="550" size="80" halign="center" valign="top">A quick presentation of the why and how.</text>
</page>
<page x="1920" name="Why">
<box3>
<headertext>Why using presentationmaker.js</headertext>
<text1>Powerpoint / Impress are hard to use.</text1>
<text2>I wanted to concentrate on the content, not the quirks of the tools.</text2>
<text3>I want to make use of modern browser features.</text3>
</box3>
</page>
<page y="1180" vx="-100" vy="980" vwidth="1920*2+200" vheight="2460" width="1920*2" height="2160" name="Features">
<calc name="scale">2</calc>
<box3 headertext="Features" text1="Template based slides/pages." text2="you can create new templates than can even calulate positions or things, this is scaled by 2X." text3="Using those templates is easy."></box3>
</page>
<page x="2020*2" name="Navigation (I)">
<box3 headertext="Navigation (I)" text1="A click/tap shows next page." text2="Swiping left/right works too." text3="Arrow on keyboard of course as well."></box3>
</page>
<page x="2020*2.5" y="1180" rz="-90" vx="2020*2.5" vy="1180" vrz="90" name="Navigation (II)">
<box3 headertext="Navigation (II)" text1="On the top left is a fullscreen icon." text2="Forwards and backwards button and a quick jump." text3="This works in every rotation :)"></box3>
</page>
<page x="2020*3" y="0" name="Creating slides">
<box3 headertext="Creating slides" text1="Presentations are based on easy to understand XML." text2="Basic elements can be combined to templates." text3="Templates can then form pages."></box3>
</page>
<page x="2020*3" y="1180" name="Example">
<defaultbg />
<text pos="${headerpos}" size="${headersize}" halign="center" valign="center">Example</text>
<text pos="100,270,1820,860" size="40" halign="left" valign="top">
This page is made by<br />
<pre><code>
&lt;page x="2020*3" y="1180" name="Example"&gt;
&lt;defaultbg /&gt;
&lt;text pos="\${headerpos}" size="\${headersize}" halign="center"
valign="center">Example&lt;/text&gt;
&lt;text pos="100,270,1820,860" size="40" halign="left"
valign="top"&gt;
This page is made by&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;Recursion is nice&lt;/code&gt;/&lt;/pre&gt;
&lt;/text&gt;
&lt;/page&gt;
</code></pre>
</text>
</page>
<page x="2020*3" y="1180*2" name="Modules / Templates">
<box3 headertext="Used Modules" text1="&lt;strong&gt;page&lt;/strong&gt;: A page defintion." text2="&lt;strong&gt;defaultbg:&lt;/strong&gt; a custom element that show the green background image" text3="&lt;strong&gt;text:&lt;/strong&gt; A text box with given size and text"></box3>
</page>
<page x="2020*4" name="box3">
<box3 headertext="Module box3" text1="This is rendered by using the box3 custom module." text2="It is based on the boxx3 module (background + background images for text)." text3="Plus text areas for the text."></box3>
</page>
<page x="2020*4" y="1180" name="Modules within modules">
<calc name="math">sin(30*PI/180) + sqrt(9)</calc>
<box3 headertext="Modules can include other modules" text1="As seen on last slide." text2="In modules you can calculate things that can be used later." text3="This was calulated by &quot;sin(30*PI/180) + sqrt(9)&quot; = ${math}"></box3>
</page>
<page x="2020*4" y="1180*2" name="Practical use for calc">
<defaultbg />
<mirrorimage img="presentationmaker.svg" x="642" y="600" w="634" h="374"></mirrorimage>
<text pos="${headerpos}" size="${headersize}" halign="center" valign="center">The mirrored image is an example where calc helps.</text>
<text x0="100" y0="450" x1="1820" y1="550" size="80" halign="center" valign="top">Also it uses some image effects.</text>
</page>
<page x="2020*4" y="1180*3" vx="2020*4-100" vy="1180*3-100" vwidth="2120" vheight="1280" name="Page position" rz="3">
<box3 headertext="Page positions" text1="Pages can be positioned anywhere on the canvas." text2="Rotation of the page and the view can be different." text3="This can create nice effects, just don't over do it."></box3>
</page>
<page x="5320" y="1180*3" z="0" rx="55" ry="20" width="1920" height="1080" vx="5320-150" vy="4400" vz="450" vwidth="2120" vheight="1280" vrx="-50" name="3D">
<box3 headertext="Rotation can also be in 3D" text1="Again, use just for rare effects." text2="Don't over do it." text3="Yes, we really mean that."></box3>
</page>
<page x="2020" y="1180*3" name="Get it">
<box3 headertext="Get it an use it." text1="Licensed under GPL-3." text3="We love to get a shout-out if you use it.">
<text2><a href="https://git.contentnation.net/grumpydevelop/presentationmaker.js" target="_blank">git.contentnation.net/presentationmaker</a></text2>
</box3>
</page>
<page x="0" y="1180*3" name="Credits">
<box3 headertext="Credits" text1="My own render engine I made for an old project.">
<text2><a href="https://impress.js.org/" target="_blank">impress.js.org</a><br />(inspired, no code was used from the project.)</text2>
<text3>Built by <a href="https://contentnatin.net/@grumpydevelop">GrumpyDeveloper</a></text3>
</box3>
</page>
<page x="3500" y="1000" z="2000" vx="4000" vy="1800" vz="4000" width="3840" height="2160" vwidth="1920" vheight="1080" name="The end">
<text x0="0" y0="0" w="${width}" h="${height}" size="1000" halign="center" valign="center">The end</text>
</page>
</pages>
</presentation>

BIN
public/img/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
public/img/box.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 KiB

View file

@ -0,0 +1,584 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
sodipodi:docname="contentnation-trans-black.svg"
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
id="svg10485"
version="1.1"
viewBox="0 0 116.87181 29.368581"
height="29.368582mm"
width="116.87183mm"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<defs
id="defs10479">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8566">
<path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8564"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8584">
<path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8582"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8612">
<path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8610"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8624">
<path
d="m 271.674,749.573 v -64.657 l 18.3,-18.426 v 44.013 z"
id="path8622"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-29.309916,29.309916,0,107.56319,51.61644)"
spreadMethod="pad"
id="linearGradient8640">
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8630" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.215824"
id="stop8632" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.75"
id="stop8634" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.76850016"
id="stop8636" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8638" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8650">
<path
d="M 312.701,749.505 V 705.43 l 18.301,-38.937 v 64.659 z"
id="path8648"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-29.284783,29.284783,0,122.03666,51.615502)"
spreadMethod="pad"
id="linearGradient8666">
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8656" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.422802"
id="stop8658" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.972582"
id="stop8660" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.97461095"
id="stop8662" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8664" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8676">
<path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8674"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8684">
<path
d="m 270.701,750.4 h 20.3 v -45.214 h -20.3 z"
id="path8682"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8700">
<path
d="m 311.582,706.377 h 20.301 V 665.35 h -20.301 z"
id="path8698"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8716">
<path
d="m 289.974,666.49 h -59.353 l -18.425,18.425 59.481,0.001 z"
id="path8714"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(19.297539,-16.192559,-16.192559,-19.297539,84.195184,56.472015)"
spreadMethod="pad"
id="linearGradient8732">
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8722" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8724" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8726" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8728" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8730" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8742">
<path
d="m 212.196,731.148 v -46.226 l 18.301,0.002 v 46.224 z"
id="path8740"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-16.307204,16.307204,0,86.58079,45.113934)"
spreadMethod="pad"
id="linearGradient8766">
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0"
id="stop8748" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.25"
id="stop8750" />
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.44050522"
id="stop8752" />
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.5"
id="stop8754" />
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.52936829"
id="stop8756" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.75"
id="stop8758" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.996319"
id="stop8760" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.9965914"
id="stop8762" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8764" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8776">
<path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8774"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8784">
<path
d="m 211.196,687.809 h 20.301 v -3.887 h -20.301 z"
id="path8782"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8800">
<path
d="m 211.196,732.223 h 20.301 v -3.887 h -20.301 z"
id="path8798"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8816">
<path
d="m 267.565,749.573 h -36.944 l -18.425,-18.425 h 37.755 z"
id="path8814"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(13.689206,12.765392,-12.765392,13.689206,83.04661,19.183338)"
spreadMethod="pad"
id="linearGradient8832">
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8822" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8824" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8826" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8828" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8830" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8862">
<path
d="m 331.011,666.473 -39.042,83.1 h -20.312 l 38.993,-83.1 z"
id="path8860"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-16.76835,31.536681,-31.536681,-16.76835,119.95484,21.196219)"
spreadMethod="pad"
id="linearGradient8878">
<stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8868" />
<stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8870" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8872" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8874" />
<stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8876" />
</linearGradient>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2069">
<path
d="M 0,0 H 23.3971 V -14.91 H 0 Z"
clip-rule="evenodd"
id="path2067"
inkscape:connector-curvature="0" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2073">
<path
d="M 0,-14.91 H 209.76378 V 14.91 H 0 Z"
id="path2071"
inkscape:connector-curvature="0" />
</clipPath>
<linearGradient
id="i"
spreadMethod="pad"
gradientTransform="matrix(19.29766,-16.19266,-16.19266,-19.29766,29.9802,59.309292)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
offset="0"
stop-color="#dfbd6a"
id="stop2648" />
<stop
offset=".295"
stop-color="#c78300"
id="stop2650" />
<stop
offset=".662"
stop-color="#6f3200"
id="stop2652" />
<stop
offset=".687"
stop-color="#6f3200"
id="stop2654" />
<stop
offset="1"
stop-color="#6f3200"
id="stop2656" />
</linearGradient>
<clipPath
id="o"
clipPathUnits="userSpaceOnUse">
<path
d="m 267.565,749.573 h -36.944 l -18.425,-18.425 h 37.755 z"
id="path2620" />
</clipPath>
<linearGradient
id="p"
spreadMethod="pad"
gradientTransform="matrix(38.804048,-36.18536,-36.18536,-38.804048,228.9593,749.93786)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0">
<stop
offset="0"
stop-color="#dfbd6a"
id="stop2678" />
<stop
offset=".295"
stop-color="#c78300"
id="stop2680" />
<stop
offset=".662"
stop-color="#6f3200"
id="stop2682" />
<stop
offset=".687"
stop-color="#6f3200"
id="stop2684" />
<stop
offset="1"
stop-color="#6f3200"
id="stop2686" />
</linearGradient>
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
showguides="true"
inkscape:window-maximized="0"
inkscape:window-y="254"
inkscape:window-x="193"
inkscape:window-height="1761"
inkscape:window-width="3631"
fit-margin-bottom="0"
fit-margin-right="0"
fit-margin-left="0"
fit-margin-top="0"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="80.714286"
inkscape:cx="215.35714"
inkscape:zoom="5.6"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<sodipodi:guide
id="guide3015"
orientation="0,-1"
position="36.967617,0.063223318"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata10482">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-22.905362,-22.155916)"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Layer 1">
<g
id="g2277"
transform="matrix(0.35277777,0,0,-0.35277777,65.410913,51.461274)" />
<path
class="cls-2"
d="m 79.101677,34.586067 a 4.0437834,4.0437834 0 0 1 -1.608264,-1.610121 4.9524783,4.9524783 0 0 1 -0.586668,-2.454035 4.9506282,4.9506282 0 0 1 0.582968,-2.450319 4.0437834,4.0437834 0 0 1 1.608262,-1.610118 4.7396478,4.7396478 0 0 1 2.313385,-0.555199 5.4059005,5.4059005 0 0 1 1.56384,0.207263 6.6625271,6.6625271 0 0 1 1.371365,0.592228 0.51634587,0.51634587 0 0 1 0.286856,0.477479 0.48118251,0.48118251 0 0 1 -0.140652,0.342378 0.49783881,0.49783881 0 0 1 -0.370137,0.148065 0.5237487,0.5237487 0 0 1 -0.231337,-0.05156 5.8963364,5.8963364 0 0 0 -1.110426,-0.451571 4.5416229,4.5416229 0 0 0 -1.249219,-0.153609 3.6551366,3.6551366 0 0 0 -1.885864,0.457127 2.9111545,2.9111545 0 0 0 -1.171493,1.249221 3.9753083,3.9753083 0 0 0 -0.394201,1.795181 3.9771578,3.9771578 0 0 0 0.394201,1.797039 2.9111545,2.9111545 0 0 0 1.171493,1.249221 3.6551366,3.6551366 0 0 0 1.884013,0.46637 4.6138002,4.6138002 0 0 0 1.24923,-0.153604 5.8963364,5.8963364 0 0 0 1.110415,-0.451572 0.5237487,0.5237487 0 0 1 0.231337,-0.05155 0.50709238,0.50709238 0 0 1 0.370145,0.142505 0.47377973,0.47377973 0 0 1 0.14065,0.347936 0.51634587,0.51634587 0 0 1 -0.283153,0.48858 6.6625271,6.6625271 0 0 1 -1.371372,0.59223 5.4059005,5.4059005 0 0 1 -1.561994,0.19617 4.7396478,4.7396478 0 0 1 -2.31338,-0.555205 z"
id="path13"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 87.750008,34.556434 a 4.0585894,4.0585894 0 0 1 -1.561992,-1.635997 5.2282335,5.2282335 0 0 1 0,-4.791473 4.0585894,4.0585894 0 0 1 1.569393,-1.636031 5.0265069,5.0265069 0 0 1 4.734096,0 4.1215132,4.1215132 0 0 1 1.571248,1.643433 5.1690107,5.1690107 0 0 1 0,4.776663 4.1215132,4.1215132 0 0 1 -1.582351,1.643405 5.0265069,5.0265069 0 0 1 -4.734097,0 z m 4.160378,-0.966042 a 3.037002,3.037002 0 0 0 1.158545,-1.262184 3.9790099,3.9790099 0 0 0 0.399749,-1.804439 3.9771578,3.9771578 0 0 0 -0.399749,-1.802581 3.037002,3.037002 0 0 0 -1.158545,-1.262173 3.7014043,3.7014043 0 0 0 -3.586661,0 3.0740155,3.0740155 0 0 0 -1.152989,1.262173 3.9771578,3.9771578 0 0 0 -0.397896,1.802581 3.9790099,3.9790099 0 0 0 0.397896,1.804439 3.0740155,3.0740155 0 0 0 1.152989,1.262184 3.7014043,3.7014043 0 0 0 3.586661,0 z"
id="path15"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 96.766628,34.91547 a 0.55521063,0.55521063 0 0 1 -0.168409,-0.410848 v -7.69151 a 0.82541414,0.82541414 0 0 1 0.244291,-0.597784 0.79395199,0.79395199 0 0 1 0.59222,-0.251694 h 0.168416 a 0.87538284,0.87538284 0 0 1 0.708818,0.386804 l 4.958136,7.162215 v -6.954945 a 0.58482187,0.58482187 0 0 1 0.16663,-0.418252 0.55521063,0.55521063 0 0 1 0.41254,-0.173969 0.59407531,0.59407531 0 0 1 0.59207,0.592221 v 7.689681 a 0.79395199,0.79395199 0 0 1 -0.25167,0.592215 0.82541414,0.82541414 0 0 1 -0.60503,0.244291 h -0.15549 a 0.82541414,0.82541414 0 0 1 -0.38671,-0.09625 0.88463599,0.88463599 0 0 1 -0.29446,-0.251668 L 97.76231,27.53673 v 6.96789 a 0.54410636,0.54410636 0 0 1 -0.17397,0.410848 0.57556829,0.57556829 0 0 1 -0.41826,0.168425 0.55521063,0.55521063 0 0 1 -0.403452,-0.168425 z"
id="path17"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 109.19402,34.91547 a 0.55521063,0.55521063 0 0 1 -0.16839,-0.410848 v -7.380587 h -2.6262 a 0.52930072,0.52930072 0 0 1 -0.38681,-0.153613 0.5237487,0.5237487 0 0 1 -0.1555,-0.386789 0.54410636,0.54410636 0 0 1 0.1555,-0.392363 0.51449509,0.51449509 0 0 1 0.38681,-0.161007 h 6.41271 a 0.55521063,0.55521063 0 0 1 0.55561,0.555203 0.51449509,0.51449509 0 0 1 -0.16152,0.386798 0.55521063,0.55521063 0 0 1 -0.39409,0.153608 h -2.61291 v 7.37875 a 0.55521063,0.55521063 0 0 1 -0.17439,0.410848 0.57926969,0.57926969 0 0 1 -0.4201,0.168425 0.55521063,0.55521063 0 0 1 -0.41072,-0.168425 z"
id="path19"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 114.94971,34.852571 a 0.56631481,0.56631481 0 0 1 -0.16631,-0.412727 v -7.811793 a 0.58112041,0.58112041 0 0 1 0.16631,-0.418275 0.55521063,0.55521063 0 0 1 0.41299,-0.173957 h 5.16517 a 0.55521063,0.55521063 0 0 1 0.555,0.555208 0.51449509,0.51449509 0 0 1 -0.16064,0.386792 0.55521063,0.55521063 0 0 1 -0.39265,0.153613 h -4.57495 v 2.838969 h 4.10156 a 0.55521063,0.55521063 0 0 1 0.55502,0.555218 0.51079377,0.51079377 0 0 1 -0.16112,0.386802 0.54225573,0.54225573 0 0 1 -0.3939,0.15731 h -4.10882 v 2.855632 h 4.57285 a 0.55521063,0.55521063 0 0 1 0.55557,0.555204 0.51634587,0.51634587 0 0 1 -0.16131,0.386787 0.55521063,0.55521063 0 0 1 -0.3922,0.153615 h -5.15958 a 0.56631481,0.56631481 0 0 1 -0.41299,-0.168398 z"
id="path21"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 123.16718,34.91547 a 0.55521063,0.55521063 0 0 1 -0.16668,-0.410848 v -7.69151 a 0.82541414,0.82541414 0 0 1 0.24399,-0.597784 0.79395199,0.79395199 0 0 1 0.59244,-0.251694 h 0.16635 a 0.87353062,0.87353062 0 0 1 0.70886,0.386804 l 4.96735,7.162215 v -6.954945 a 0.57741901,0.57741901 0 0 1 0.16839,-0.418252 0.54410636,0.54410636 0 0 1 0.41075,-0.173969 0.59037391,0.59037391 0 0 1 0.59266,0.592221 v 7.689681 a 0.79765285,0.79765285 0 0 1 -0.24992,0.592215 0.83281503,0.83281503 0 0 1 -0.59969,0.244291 h -0.1538 a 0.81986106,0.81986106 0 0 1 -0.3866,-0.09625 0.89018674,0.89018674 0 0 1 -0.29641,-0.251668 l -4.98391,-7.199246 v 6.96789 a 0.54410636,0.54410636 0 0 1 -0.17353,0.410847 0.57741901,0.57741901 0 0 1 -0.41842,0.168425 0.55521063,0.55521063 0 0 1 -0.42183,-0.168425 z"
id="path23"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 135.60159,34.91547 a 0.55521063,0.55521063 0 0 1 -0.16652,-0.410848 v -7.380587 h -2.62775 a 0.5255994,0.5255994 0 0 1 -0.54041,-0.540402 0.55521063,0.55521063 0 0 1 0.15334,-0.392363 0.51634587,0.51634587 0 0 1 0.38707,-0.161007 h 6.41472 a 0.55521063,0.55521063 0 0 1 0.55499,0.555203 0.51449509,0.51449509 0 0 1 -0.16096,0.386798 0.55521063,0.55521063 0 0 1 -0.39232,0.153608 h -2.62461 v 7.37875 a 0.54410636,0.54410636 0 0 1 -0.17362,0.410848 0.57556829,0.57556829 0 0 1 -0.41842,0.168425 0.55521063,0.55521063 0 0 1 -0.40551,-0.168425 z"
id="path25"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 77.615566,47.54096 a 0.55521063,0.55521063 0 0 1 -0.168411,-0.410853 v -7.684111 a 0.81986106,0.81986106 0 0 1 0.246139,-0.603313 0.79025002,0.79025002 0 0 1 0.592227,-0.251708 h 0.166563 a 0.87353062,0.87353062 0 0 1 0.70326,0.392365 l 4.958035,7.160362 v -6.954935 a 0.57741901,0.57741901 0 0 1 0.168413,-0.418268 0.54410636,0.54410636 0 0 1 0.410857,-0.173957 0.59407531,0.59407531 0 0 1 0.592225,0.592225 v 7.689656 a 0.79765285,0.79765285 0 0 1 -0.249847,0.592235 0.83281503,0.83281503 0 0 1 -0.599628,0.244268 h -0.153607 a 0.81986106,0.81986106 0 0 1 -0.386794,-0.09622 0.87353062,0.87353062 0 0 1 -0.296115,-0.251703 l -4.983939,-7.199235 v 6.967918 a 0.55521063,0.55521063 0 0 1 -0.17397,0.410852 0.57926969,0.57926969 0 0 1 -0.420105,0.168392 0.55521063,0.55521063 0 0 1 -0.405303,-0.173966 z"
id="path27"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 87.344703,47.54096 a 0.56816551,0.56816551 0 0 1 -0.16101,-0.410853 0.7032668,0.7032668 0 0 1 0.06459,-0.257229 l 3.28317,-7.754468 a 1.0104838,1.0104838 0 0 1 0.290568,-0.370125 0.71622143,0.71622143 0 0 1 0.457128,-0.14804 h 0.129547 a 0.71992298,0.71992298 0 0 1 0.457124,0.14804 0.9882749,0.9882749 0 0 1 0.288711,0.370125 l 3.286854,7.760013 a 0.7032668,0.7032668 0 0 1 0.06457,0.257259 0.57556829,0.57556829 0 0 1 -0.161013,0.410852 0.55521063,0.55521063 0 0 1 -0.42011,0.168392 0.59592602,0.59592602 0 0 1 -0.327558,-0.09622 0.63108943,0.63108943 0 0 1 -0.225783,-0.264643 l -0.836409,-2.009858 h -4.386163 l -0.830966,2.01169 a 0.63108943,0.63108943 0 0 1 -0.225784,0.264663 0.60703023,0.60703023 0 0 1 -0.329424,0.09624 0.55521063,0.55521063 0 0 1 -0.418261,-0.17584 z m 2.259713,-3.270175 h 3.477465 L 91.34407,40.084508 Z"
id="path29"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="M 98.852371,47.54096 A 0.55521063,0.55521063 0 0 1 98.683954,47.130107 V 39.755064 H 96.05781 a 0.52745008,0.52745008 0 0 1 -0.542258,-0.542239 0.54410636,0.54410636 0 0 1 0.155463,-0.392372 0.51449509,0.51449509 0 0 1 0.386795,-0.161004 h 6.41642 a 0.55521063,0.55521063 0 0 1 0.55528,0.555206 0.51449509,0.51449509 0 0 1 -0.16124,0.38681 0.540405,0.540405 0 0 1 -0.39209,0.153599 h -2.618835 v 7.380618 a 0.55521063,0.55521063 0 0 1 -0.174027,0.410852 0.57926969,0.57926969 0 0 1 -0.4201,0.168392 0.55521063,0.55521063 0 0 1 -0.410847,-0.173966 z"
id="path31"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 104.60795,47.54096 a 0.55521063,0.55521063 0 0 1 -0.16661,-0.410853 v -7.94134 a 0.58482187,0.58482187 0 0 1 0.16661,-0.418268 0.55521063,0.55521063 0 0 1 0.41299,-0.173957 0.59407531,0.59407531 0 0 1 0.59214,0.592225 v 7.946915 a 0.54410636,0.54410636 0 0 1 -0.17782,0.405278 0.57556829,0.57556829 0 0 1 -0.41836,0.168426 0.55521063,0.55521063 0 0 1 -0.40895,-0.168426 z"
id="path33"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 109.72153,47.187498 a 4.0511871,4.0511871 0 0 1 -1.57138,-1.636031 5.2430389,5.2430389 0 0 1 0,-4.791483 4.0511871,4.0511871 0 0 1 1.57138,-1.635995 5.0228053,5.0228053 0 0 1 4.73218,0 4.1085585,4.1085585 0 0 1 1.57138,1.643414 5.1542044,5.1542044 0 0 1 0,4.776648 4.1085585,4.1085585 0 0 1 -1.57138,1.643447 5.0228053,5.0228053 0 0 1 -4.73218,0 z m 4.16046,-0.966083 a 3.0610601,3.0610601 0 0 0 1.15852,-1.262188 4.267719,4.267719 0 0 0 0,-3.607002 3.0610601,3.0610601 0 0 0 -1.15852,-1.262188 3.7014043,3.7014043 0 0 0 -3.58654,0 3.0610601,3.0610601 0 0 0 -1.15298,1.262188 4.267719,4.267719 0 0 0 0,3.607002 3.0610601,3.0610601 0 0 0 1.15298,1.262188 3.7014043,3.7014043 0 0 0 3.58654,0 z"
id="path35"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 118.73656,47.54096 a 0.55521063,0.55521063 0 0 1 -0.16668,-0.410853 v -7.684111 a 0.82541414,0.82541414 0 0 1 0.244,-0.603313 0.79395199,0.79395199 0 0 1 0.59255,-0.251708 h 0.16632 a 0.87353062,0.87353062 0 0 1 0.70887,0.386788 l 4.95608,7.165939 v -6.954935 a 0.57741901,0.57741901 0 0 1 0.16839,-0.418268 0.55521063,0.55521063 0 0 1 0.41306,-0.173957 0.56816551,0.56816551 0 0 1 0.41796,0.173957 0.57556829,0.57556829 0 0 1 0.1742,0.418268 v 7.689656 a 0.79950344,0.79950344 0 0 1 -0.25173,0.592235 0.83096538,0.83096538 0 0 1 -0.59969,0.244268 h -0.1538 a 0.81986106,0.81986106 0 0 1 -0.38661,-0.09622 0.89018674,0.89018674 0 0 1 -0.29631,-0.251703 l -4.98398,-7.199235 v 6.967918 a 0.54410636,0.54410636 0 0 1 -0.17355,0.410852 0.57741901,0.57741901 0 0 1 -0.41841,0.168392 0.55521063,0.55521063 0 0 1 -0.41067,-0.173966 z"
id="path37"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 132.36619,47.662806 a 0.16656329,0.16656329 0 0 1 -0.0526,-0.123236 v -2.305248 a 0.2476239,0.2476239 0 0 1 0.0757,-0.181014 0.23818531,0.23818531 0 0 1 0.17736,-0.0755 h 0.0526 a 0.26205927,0.26205927 0 0 1 0.21265,0.11605 l 1.48691,2.149758 v -2.086452 a 0.17322576,0.17322576 0 0 1 0.053,-0.125508 0.16656329,0.16656329 0 0 1 0.1239,-0.05205 0.17044952,0.17044952 0 0 1 0.12542,0.05205 0.17267036,0.17267036 0 0 1 0.0537,0.125508 v 2.306901 a 0.23985104,0.23985104 0 0 1 -0.0756,0.177669 0.24928962,0.24928962 0 0 1 -0.17993,0.07328 h -0.0471 a 0.24595828,0.24595828 0 0 1 -0.11605,-0.02905 0.26705624,0.26705624 0 0 1 -0.089,-0.0755 l -1.49522,-2.15977 v 2.090368 a 0.16323178,0.16323178 0 0 1 -0.0542,0.123258 0.17322576,0.17322576 0 0 1 -0.12533,0.05061 0.16656329,0.16656329 0 0 1 -0.12329,-0.05205 z"
id="path37-3"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 135.07399,47.664497 a 0.16989438,0.16989438 0 0 1 -0.0525,-0.123816 v -2.343552 a 0.17433613,0.17433613 0 0 1 0.0526,-0.125475 0.16656329,0.16656329 0 0 1 0.12399,-0.05205 h 1.54965 a 0.16656329,0.16656329 0 0 1 0.16636,0.166551 0.15434859,0.15434859 0 0 1 -0.0503,0.116035 0.16656329,0.16656329 0 0 1 -0.11765,0.04614 h -1.37251 v 0.851696 h 1.23043 a 0.16656329,0.16656329 0 0 1 0.16655,0.166554 0.15323809,0.15323809 0 0 1 -0.0503,0.116038 0.16267667,0.16267667 0 0 1 -0.11828,0.04711 h -1.23257 v 0.856687 h 1.37196 a 0.16656329,0.16656329 0 0 1 0.16661,0.166572 0.15490387,0.15490387 0 0 1 -0.0503,0.116017 0.16656329,0.16656329 0 0 1 -0.11768,0.04614 h -1.54784 a 0.16989438,0.16989438 0 0 1 -0.12371,-0.05061 z"
id="path21-6"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<path
class="cls-2"
d="m 138.31938,47.664494 a 0.16656329,0.16656329 0 0 1 -0.0526,-0.12328 V 45.32703 h -0.78834 a 0.15767982,0.15767982 0 0 1 -0.16207,-0.162122 0.16656329,0.16656329 0 0 1 0.0471,-0.117704 0.15490387,0.15490387 0 0 1 0.11604,-0.04838 h 1.92434 a 0.16656329,0.16656329 0 0 1 0.16665,0.166585 0.15434859,0.15434859 0 0 1 -0.0503,0.116026 0.16656329,0.16656329 0 0 1 -0.11765,0.04614 h -0.78728 v 2.213598 a 0.16323178,0.16323178 0 0 1 -0.054,0.12328 0.17267036,0.17267036 0 0 1 -0.12548,0.05061 0.16656329,0.16656329 0 0 1 -0.12163,-0.05061 z"
id="path25-7"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.264583" />
<circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round"
id="path2370"
cx="131.01605"
cy="47.365242"
r="0.34973946" />
<g
fill="#ffffff"
id="g5"
transform="matrix(0.99999435,0,0,0.99999435,22.886461,22.155914)">
<path
d="m 20.983,0 v 22.81 l 6.455,6.5 V 13.783 Z m 14.473,0.024 v 15.549 l 6.456,13.736 V 6.499 Z"
fill-opacity="0.5"
id="path1" />
<path
d="M 27.438,29.31 H 6.5 L 0,22.81 h 20.984 z"
id="path2" />
<path
d="M 0,6.5 V 22.807 H 6.456 V 6.5 Z"
fill-opacity="0.5"
id="path3" />
<path
d="M 19.533,0 H 6.5 L 0,6.5 H 13.32 Z M 41.915,29.316 28.142,0 h -7.165 l 13.755,29.316 z"
id="path4" />
<path
d="m 47.39,2.545 a 2.545,2.545 0 1 0 -5.09,0 2.545,2.545 0 1 0 5.09,0 m -0.33,0 c 0,1.216 -0.999,2.243 -2.215,2.243 -1.216,0 -2.214,-1.027 -2.214,-2.243 0,-1.216 0.998,-2.243 2.214,-2.243 1.216,0 2.214,1.027 2.214,2.243 m -1.173,1.406 -0.71,-1.202 c 0.372,-0.106 0.64,-0.372 0.64,-0.787 0,-0.478 -0.409,-0.83 -0.872,-0.83 h -0.9 v 2.82 H 44.36 V 2.776 h 0.464 L 45.52,3.95 Z m -0.387,-1.99 c 0,0.31 -0.253,0.535 -0.59,0.535 h -0.55 V 1.42 h 0.55 c 0.337,0 0.59,0.232 0.59,0.542"
fill-opacity="0.51"
id="path5" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 28 KiB

42
public/img/logo.svg Normal file
View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="8.2602539mm"
height="8.3228693mm"
viewBox="0 0 8.2602539 8.3228693"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<g
id="layer1"
transform="translate(-100.80624,-144.46251)">
<rect
style="fill:none;fill-opacity:1;stroke:#fffdfd;stroke-width:0.396875;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="7.8633785"
height="4.0744472"
x="101.00468"
y="145.71317" />
<g
id="g6"
transform="matrix(0.44901262,0,0,0.30313405,81.948876,138.55801)"
style="stroke:#ffffff;stroke-width:1.07574;stroke-dasharray:none;stroke-opacity:1">
<path
style="fill:none;stroke:#ffffff;stroke-width:1.07574;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 49.030808,37.632967 -2.348149,8.763414 m 6.348149,-8.763414 2.677863,8.763414"
id="path6" />
</g>
<path
style="fill:none;fill-opacity:1;stroke:none;stroke-width:0.661458;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path7"
d="m 105.61076,145.15149 a 0.42403585,0.34019229 0 0 1 -0.21202,0.29461 0.42403585,0.34019229 0 0 1 -0.42404,0 0.42403585,0.34019229 0 0 1 -0.21201,-0.29461 h 0.42403 z" />
<path
style="fill:#fbfbfb;fill-opacity:1;stroke:none;stroke-width:0.661458;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path8"
d="m 103.81304,145.58186 a 1.1233398,1.1193535 0 0 1 1.12334,-1.11935 1.1233398,1.1193535 0 0 1 1.12334,1.11935 h -1.12334 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,423 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 176 48"
version="1.1"
id="svg1"
width="176"
height="48"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1"><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8566"><path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8564" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8584"><path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8582" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8612"><path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8610" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8624"><path
d="m 271.674,749.573 v -64.657 l 18.3,-18.426 v 44.013 z"
id="path8622" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-29.309916,29.309916,0,107.56319,51.61644)"
spreadMethod="pad"
id="linearGradient8640"><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8630" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.215824"
id="stop8632" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.75"
id="stop8634" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.76850016"
id="stop8636" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8638" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8650"><path
d="M 312.701,749.505 V 705.43 l 18.301,-38.937 v 64.659 z"
id="path8648" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-29.284783,29.284783,0,122.03666,51.615502)"
spreadMethod="pad"
id="linearGradient8666"><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8656" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.422802"
id="stop8658" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.972582"
id="stop8660" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.97461095"
id="stop8662" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8664" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8676"><path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8674" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8684"><path
d="m 270.701,750.4 h 20.3 v -45.214 h -20.3 z"
id="path8682" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8700"><path
d="m 311.582,706.377 h 20.301 V 665.35 h -20.301 z"
id="path8698" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8716"><path
d="m 289.974,666.49 h -59.353 l -18.425,18.425 59.481,0.001 z"
id="path8714" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(19.297539,-16.192559,-16.192559,-19.297539,84.195184,56.472015)"
spreadMethod="pad"
id="linearGradient8732"><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8722" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8724" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8726" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8728" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8730" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8742"><path
d="m 212.196,731.148 v -46.226 l 18.301,0.002 v 46.224 z"
id="path8740" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0,-16.307204,16.307204,0,86.58079,45.113934)"
spreadMethod="pad"
id="linearGradient8766"><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0"
id="stop8748" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.25"
id="stop8750" /><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.44050522"
id="stop8752" /><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.5"
id="stop8754" /><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0.52936829"
id="stop8756" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.75"
id="stop8758" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.996319"
id="stop8760" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.9965914"
id="stop8762" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8764" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8776"><path
d="M 0,0 H 1280 V 800 H 0 Z"
id="path8774" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8784"><path
d="m 211.196,687.809 h 20.301 v -3.887 h -20.301 z"
id="path8782" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8800"><path
d="m 211.196,732.223 h 20.301 v -3.887 h -20.301 z"
id="path8798" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8816"><path
d="m 267.565,749.573 h -36.944 l -18.425,-18.425 h 37.755 z"
id="path8814" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(13.689206,12.765392,-12.765392,13.689206,83.04661,19.183338)"
spreadMethod="pad"
id="linearGradient8832"><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8822" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8824" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8826" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8828" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8830" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath8862"><path
d="m 331.011,666.473 -39.042,83.1 h -20.312 l 38.993,-83.1 z"
id="path8860" /></clipPath><linearGradient
x1="0"
y1="0"
x2="1"
y2="0"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-16.76835,31.536681,-31.536681,-16.76835,119.95484,21.196219)"
spreadMethod="pad"
id="linearGradient8878"><stop
style="stop-opacity:1;stop-color:#dfbd6a"
offset="0"
id="stop8868" /><stop
style="stop-opacity:1;stop-color:#c78300"
offset="0.29489"
id="stop8870" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.662088"
id="stop8872" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="0.6870937"
id="stop8874" /><stop
style="stop-opacity:1;stop-color:#6f3200"
offset="1"
id="stop8876" /></linearGradient><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2069"><path
d="M 0,0 H 23.3971 V -14.91 H 0 Z"
clip-rule="evenodd"
id="path2067" /></clipPath><clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath2073"><path
d="M 0,-14.91 H 209.76378 V 14.91 H 0 Z"
id="path2071" /></clipPath><linearGradient
id="i"
spreadMethod="pad"
gradientTransform="matrix(19.29766,-16.19266,-16.19266,-19.29766,29.9802,59.309292)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
offset="0"
stop-color="#dfbd6a"
id="stop2648" /><stop
offset=".295"
stop-color="#c78300"
id="stop2650" /><stop
offset=".662"
stop-color="#6f3200"
id="stop2652" /><stop
offset=".687"
stop-color="#6f3200"
id="stop2654" /><stop
offset="1"
stop-color="#6f3200"
id="stop2656" /></linearGradient><clipPath
id="o"
clipPathUnits="userSpaceOnUse"><path
d="m 267.565,749.573 h -36.944 l -18.425,-18.425 h 37.755 z"
id="path2620" /></clipPath><linearGradient
id="p"
spreadMethod="pad"
gradientTransform="matrix(38.804048,-36.18536,-36.18536,-38.804048,228.9593,749.93786)"
gradientUnits="userSpaceOnUse"
y2="0"
x2="1"
y1="0"
x1="0"><stop
offset="0"
stop-color="#dfbd6a"
id="stop2678" /><stop
offset=".295"
stop-color="#c78300"
id="stop2680" /><stop
offset=".662"
stop-color="#6f3200"
id="stop2682" /><stop
offset=".687"
stop-color="#6f3200"
id="stop2684" /><stop
offset="1"
stop-color="#6f3200"
id="stop2686" /></linearGradient></defs><text
xml:space="preserve"
style="font-weight:bold;font-size:13.3333px;line-height:1.25;font-family:'DejaVu Serif';-inkscape-font-specification:'DejaVu Serif Bold';fill:#ffffff;fill-opacity:1"
x="42.828514"
y="15.528239"
id="text1"><tspan
id="tspan1"
x="42.828514"
y="15.528239"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:Roboto;-inkscape-font-specification:Roboto;fill:#ffffff;fill-opacity:1">PresentationMaker.js</tspan></text><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;line-height:1.25;font-family:Roboto;-inkscape-font-specification:Roboto;fill:#ffffff;fill-opacity:1"
x="53.405025"
y="39.509506"
id="text2"><tspan
id="tspan2"
x="53.405025"
y="39.509506"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:13.3333px;font-family:Roboto;-inkscape-font-specification:Roboto;fill:#ffffff;fill-opacity:1">by</tspan></text><g
id="g2277"
transform="matrix(1.3333333,0,0,-1.3333333,17.273461,90.445105)" /><path
class="cls-2"
d="m 116.17083,31.093495 a 2.7248604,2.7248604 0 0 1 -1.08371,-1.084962 3.3371748,3.3371748 0 0 1 -0.39532,-1.653626 3.3359281,3.3359281 0 0 1 0.39282,-1.651121 2.7248604,2.7248604 0 0 1 1.08371,-1.084961 3.1937612,3.1937612 0 0 1 1.55885,-0.374115 3.6427085,3.6427085 0 0 1 1.05378,0.139662 4.4894729,4.4894729 0 0 1 0.92408,0.399067 0.34793417,0.34793417 0 0 1 0.19329,0.321744 0.32423971,0.32423971 0 0 1 -0.0948,0.230707 0.33546338,0.33546338 0 0 1 -0.24942,0.09977 0.35292248,0.35292248 0 0 1 -0.15588,-0.03474 3.9731835,3.9731835 0 0 0 -0.74825,-0.304286 3.0603242,3.0603242 0 0 0 -0.84177,-0.103508 2.4629749,2.4629749 0 0 0 -1.27077,0.30803 1.9616505,1.9616505 0 0 0 -0.7894,0.841775 2.6787192,2.6787192 0 0 0 -0.26563,1.209663 2.6799654,2.6799654 0 0 0 0.26563,1.210916 1.9616505,1.9616505 0 0 0 0.7894,0.841774 2.4629749,2.4629749 0 0 0 1.26952,0.314259 3.1089601,3.1089601 0 0 0 0.84178,-0.103505 3.9731835,3.9731835 0 0 0 0.74824,-0.304287 0.35292248,0.35292248 0 0 1 0.15589,-0.03474 0.3416988,0.3416988 0 0 1 0.24942,0.09602 0.31925143,0.31925143 0 0 1 0.0948,0.234453 0.34793417,0.34793417 0 0 1 -0.1908,0.329225 4.4894729,4.4894729 0 0 1 -0.92408,0.399067 3.6427085,3.6427085 0 0 1 -1.05254,0.132188 3.1937612,3.1937612 0 0 1 -1.55884,-0.374119 z"
id="path13"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 121.99841,31.073528 a 2.7348372,2.7348372 0 0 1 -1.05253,-1.1024 3.5229895,3.5229895 0 0 1 0,-3.228683 2.7348372,2.7348372 0 0 1 1.05752,-1.102422 3.3870581,3.3870581 0 0 1 3.19002,0 2.7772378,2.7772378 0 0 1 1.05877,1.10741 3.4830828,3.4830828 0 0 1 0,3.218704 2.7772378,2.7772378 0 0 1 -1.06625,1.107391 3.3870581,3.3870581 0 0 1 -3.19002,0 z m 2.80343,-0.650958 a 2.0464515,2.0464515 0 0 0 0.78067,-0.850509 2.6812134,2.6812134 0 0 0 0.26937,-1.215902 2.6799654,2.6799654 0 0 0 -0.26937,-1.21465 2.0464515,2.0464515 0 0 0 -0.78067,-0.850502 2.4941519,2.4941519 0 0 0 -2.41683,0 2.0713926,2.0713926 0 0 0 -0.77693,0.850502 2.6799654,2.6799654 0 0 0 -0.26812,1.21465 2.6812134,2.6812134 0 0 0 0.26812,1.215902 2.0713926,2.0713926 0 0 0 0.77693,0.850509 2.4941519,2.4941519 0 0 0 2.41683,0 z"
id="path15"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 128.07417,31.31546 a 0.37412277,0.37412277 0 0 1 -0.11348,-0.276845 v -5.182843 a 0.55619653,0.55619653 0 0 1 0.16461,-0.40281 0.53499609,0.53499609 0 0 1 0.39906,-0.169601 h 0.11349 a 0.5898674,0.5898674 0 0 1 0.47762,0.260644 l 3.34099,4.826182 v -4.686516 a 0.39407599,0.39407599 0 0 1 0.11228,-0.281834 0.37412277,0.37412277 0 0 1 0.27799,-0.117228 0.40031132,0.40031132 0 0 1 0.39896,0.399062 v 5.18161 a 0.53499609,0.53499609 0 0 1 -0.16959,0.399058 0.55619653,0.55619653 0 0 1 -0.40769,0.164613 h -0.10477 a 0.55619653,0.55619653 0 0 1 -0.26058,-0.06486 0.59610254,0.59610254 0 0 1 -0.19842,-0.169583 l -3.35954,-4.851136 v 4.695238 a 0.36664028,0.36664028 0 0 1 -0.11723,0.276846 0.38784056,0.38784056 0 0 1 -0.28184,0.113491 0.37412277,0.37412277 0 0 1 -0.27186,-0.113491 z"
id="path17"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 136.44823,31.31546 a 0.37412277,0.37412277 0 0 1 -0.11347,-0.276845 v -4.97333 h -1.76963 a 0.35666365,0.35666365 0 0 1 -0.26065,-0.103511 0.35292248,0.35292248 0 0 1 -0.10478,-0.260634 0.36664028,0.36664028 0 0 1 0.10478,-0.264389 0.34668704,0.34668704 0 0 1 0.26065,-0.108493 h 4.32113 a 0.37412277,0.37412277 0 0 1 0.3744,0.374118 0.34668704,0.34668704 0 0 1 -0.10884,0.260639 0.37412277,0.37412277 0 0 1 -0.26556,0.103507 h -1.76068 v 4.972093 a 0.37412277,0.37412277 0 0 1 -0.11751,0.276845 0.39033471,0.39033471 0 0 1 -0.28308,0.113492 0.37412277,0.37412277 0 0 1 -0.27676,-0.113492 z"
id="path19"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 140.32664,31.273076 a 0.3816052,0.3816052 0 0 1 -0.11206,-0.278111 v -5.263894 a 0.3915818,0.3915818 0 0 1 0.11206,-0.28185 0.37412277,0.37412277 0 0 1 0.27829,-0.117219 h 3.4805 a 0.37412277,0.37412277 0 0 1 0.37398,0.374121 0.34668704,0.34668704 0 0 1 -0.10825,0.260636 0.37412277,0.37412277 0 0 1 -0.26458,0.10351 h -3.08278 v 1.913009 h 2.76379 a 0.37412277,0.37412277 0 0 1 0.37399,0.374128 0.34419294,0.34419294 0 0 1 -0.10856,0.260642 0.36539325,0.36539325 0 0 1 -0.26543,0.106002 h -2.76868 v 1.924237 h 3.08136 a 0.37412277,0.37412277 0 0 1 0.37437,0.374118 0.34793417,0.34793417 0 0 1 -0.1087,0.260633 0.37412277,0.37412277 0 0 1 -0.26428,0.103511 h -3.47673 a 0.3816052,0.3816052 0 0 1 -0.27829,-0.113473 z"
id="path21"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 145.8639,31.31546 a 0.37412277,0.37412277 0 0 1 -0.11232,-0.276845 v -5.182843 a 0.55619653,0.55619653 0 0 1 0.16441,-0.40281 0.53499609,0.53499609 0 0 1 0.39921,-0.169601 h 0.11209 a 0.58861931,0.58861931 0 0 1 0.47766,0.260644 l 3.3472,4.826182 v -4.686516 a 0.38908765,0.38908765 0 0 1 0.11347,-0.281834 0.36664028,0.36664028 0 0 1 0.27678,-0.117228 0.39781717,0.39781717 0 0 1 0.39935,0.399062 v 5.18161 a 0.53748988,0.53748988 0 0 1 -0.1684,0.399058 0.56118354,0.56118354 0 0 1 -0.4041,0.164613 h -0.10363 a 0.55245464,0.55245464 0 0 1 -0.26051,-0.06486 0.59984285,0.59984285 0 0 1 -0.19973,-0.169583 l -3.35836,-4.851136 v 4.695239 a 0.36664028,0.36664028 0 0 1 -0.11693,0.276845 0.38908765,0.38908765 0 0 1 -0.28195,0.113491 0.37412277,0.37412277 0 0 1 -0.28424,-0.113491 z"
id="path23"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 154.24269,31.31546 a 0.37412277,0.37412277 0 0 1 -0.11221,-0.276845 v -4.97333 h -1.77068 a 0.35416956,0.35416956 0 0 1 -0.36415,-0.364145 0.37412277,0.37412277 0 0 1 0.10333,-0.264389 0.34793417,0.34793417 0 0 1 0.26082,-0.108493 h 4.32249 a 0.37412277,0.37412277 0 0 1 0.37398,0.374118 0.34668704,0.34668704 0 0 1 -0.10846,0.260639 0.37412277,0.37412277 0 0 1 -0.26436,0.103507 h -1.76857 v 4.972093 a 0.36664028,0.36664028 0 0 1 -0.11699,0.276845 0.38784056,0.38784056 0 0 1 -0.28195,0.113492 0.37412277,0.37412277 0 0 1 -0.27325,-0.113492 z"
id="path25"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 115.16943,39.823012 a 0.37412277,0.37412277 0 0 1 -0.11348,-0.276849 v -5.177856 a 0.55245464,0.55245464 0 0 1 0.16585,-0.406536 0.53250156,0.53250156 0 0 1 0.39907,-0.169611 h 0.11224 a 0.58861931,0.58861931 0 0 1 0.47388,0.264391 l 3.34092,4.824934 v -4.686509 a 0.38908765,0.38908765 0 0 1 0.11348,-0.281846 0.36664028,0.36664028 0 0 1 0.27685,-0.117219 0.40031132,0.40031132 0 0 1 0.39907,0.399065 v 5.181593 a 0.53748988,0.53748988 0 0 1 -0.16836,0.399071 0.56118354,0.56118354 0 0 1 -0.40405,0.164597 h -0.10351 a 0.55245464,0.55245464 0 0 1 -0.26063,-0.06484 0.58861931,0.58861931 0 0 1 -0.19954,-0.169607 l -3.35837,-4.851128 v 4.695258 a 0.37412277,0.37412277 0 0 1 -0.11723,0.276848 0.39033471,0.39033471 0 0 1 -0.28308,0.113469 0.37412277,0.37412277 0 0 1 -0.27311,-0.117225 z"
id="path27"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 121.7253,39.823012 a 0.38285228,0.38285228 0 0 1 -0.10849,-0.276849 0.47388884,0.47388884 0 0 1 0.0435,-0.173331 l 2.21233,-5.225266 a 0.68090375,0.68090375 0 0 1 0.1958,-0.249404 0.48261818,0.48261818 0 0 1 0.30803,-0.09976 h 0.0873 a 0.48511243,0.48511243 0 0 1 0.30803,0.09976 0.66593852,0.66593852 0 0 1 0.19454,0.249404 l 2.21482,5.229003 a 0.47388884,0.47388884 0 0 1 0.0435,0.173351 0.38784056,0.38784056 0 0 1 -0.1085,0.276848 0.37412277,0.37412277 0 0 1 -0.28309,0.113469 0.4015584,0.4015584 0 0 1 -0.22072,-0.06484 0.42525289,0.42525289 0 0 1 -0.15214,-0.178326 l -0.56361,-1.354322 h -2.95557 l -0.55993,1.355556 a 0.42525289,0.42525289 0 0 1 -0.15215,0.17834 0.40904086,0.40904086 0 0 1 -0.22197,0.06485 0.37412277,0.37412277 0 0 1 -0.28184,-0.118488 z m 1.52269,-2.203573 h 2.34325 l -1.17101,-2.820878 z"
id="path29"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 129.47962,39.823012 a 0.37412277,0.37412277 0 0 1 -0.11348,-0.276849 v -4.969594 h -1.7696 a 0.35541662,0.35541662 0 0 1 -0.3654,-0.365382 0.36664028,0.36664028 0 0 1 0.10476,-0.264396 0.34668704,0.34668704 0 0 1 0.26064,-0.108491 h 4.32363 a 0.37412277,0.37412277 0 0 1 0.37417,0.37412 0.34668704,0.34668704 0 0 1 -0.10865,0.260648 0.36414615,0.36414615 0 0 1 -0.2642,0.103501 h -1.76468 v 4.973351 a 0.37412277,0.37412277 0 0 1 -0.11726,0.276848 0.39033471,0.39033471 0 0 1 -0.28308,0.113469 0.37412277,0.37412277 0 0 1 -0.27685,-0.117225 z"
id="path31"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 133.35796,39.823012 a 0.37412277,0.37412277 0 0 1 -0.11227,-0.276849 v -5.351187 a 0.39407599,0.39407599 0 0 1 0.11227,-0.281846 0.37412277,0.37412277 0 0 1 0.27829,-0.117219 0.40031132,0.40031132 0 0 1 0.399,0.399065 v 5.354944 a 0.36664028,0.36664028 0 0 1 -0.11982,0.273092 0.38784056,0.38784056 0 0 1 -0.28191,0.113492 0.37412277,0.37412277 0 0 1 -0.27556,-0.113492 z"
id="path33"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 136.80369,39.584835 a 2.7298493,2.7298493 0 0 1 -1.05886,-1.102422 3.5329659,3.5329659 0 0 1 0,-3.228689 2.7298493,2.7298493 0 0 1 1.05886,-1.102398 3.3845639,3.3845639 0 0 1 3.18873,0 2.7685084,2.7685084 0 0 1 1.05886,1.107397 3.4731057,3.4731057 0 0 1 0,3.218693 2.7685084,2.7685084 0 0 1 -1.05886,1.107419 3.3845639,3.3845639 0 0 1 -3.18873,0 z m 2.80348,-0.650984 a 2.0626627,2.0626627 0 0 0 0.78066,-0.850512 2.875757,2.875757 0 0 0 0,-2.43054 2.0626627,2.0626627 0 0 0 -0.78066,-0.850512 2.4941519,2.4941519 0 0 0 -2.41675,0 2.0626627,2.0626627 0 0 0 -0.77692,0.850512 2.875757,2.875757 0 0 0 0,2.43054 2.0626627,2.0626627 0 0 0 0.77692,0.850512 2.4941519,2.4941519 0 0 0 2.41675,0 z"
id="path35"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 142.87837,39.823012 a 0.37412277,0.37412277 0 0 1 -0.11231,-0.276849 v -5.177856 a 0.55619653,0.55619653 0 0 1 0.16441,-0.406536 0.53499609,0.53499609 0 0 1 0.39929,-0.169611 h 0.11207 a 0.58861931,0.58861931 0 0 1 0.47766,0.260633 l 3.33961,4.828692 v -4.686509 a 0.38908765,0.38908765 0 0 1 0.11346,-0.281846 0.37412277,0.37412277 0 0 1 0.27834,-0.117219 0.38285228,0.38285228 0 0 1 0.28164,0.117219 0.38784056,0.38784056 0 0 1 0.11738,0.281846 v 5.181593 a 0.53873688,0.53873688 0 0 1 -0.16963,0.399071 0.55993717,0.55993717 0 0 1 -0.40409,0.164597 h -0.10364 a 0.55245464,0.55245464 0 0 1 -0.26051,-0.06484 0.59984285,0.59984285 0 0 1 -0.19967,-0.169607 l -3.3584,-4.851128 v 4.695258 a 0.36664028,0.36664028 0 0 1 -0.11694,0.276848 0.38908765,0.38908765 0 0 1 -0.28194,0.113469 0.37412277,0.37412277 0 0 1 -0.27673,-0.117225 z"
id="path37"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 152.06255,39.905117 a 0.1122369,0.1122369 0 0 1 -0.0354,-0.08304 v -1.553366 a 0.16685873,0.16685873 0 0 1 0.051,-0.121975 0.16049863,0.16049863 0 0 1 0.11951,-0.05088 h 0.0354 a 0.17658585,0.17658585 0 0 1 0.1433,0.0782 l 1.00193,1.448592 v -1.405933 a 0.11672633,0.11672633 0 0 1 0.0357,-0.08457 0.1122369,0.1122369 0 0 1 0.0835,-0.03507 0.11485559,0.11485559 0 0 1 0.0845,0.03507 0.11635208,0.11635208 0 0 1 0.0362,0.08457 v 1.55448 a 0.16162107,0.16162107 0 0 1 -0.0509,0.119721 0.16798116,0.16798116 0 0 1 -0.12124,0.04938 h -0.0317 a 0.16573637,0.16573637 0 0 1 -0.0782,-0.01958 0.179953,0.179953 0 0 1 -0.06,-0.05087 l -1.00754,-1.455338 v 1.408572 a 0.109992,0.109992 0 0 1 -0.0365,0.08306 0.11672633,0.11672633 0 0 1 -0.0844,0.0341 0.1122369,0.1122369 0 0 1 -0.0831,-0.03507 z"
id="path37-3"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 153.88717,39.906256 a 0.11448152,0.11448152 0 0 1 -0.0354,-0.08343 v -1.579177 a 0.11747454,0.11747454 0 0 1 0.0354,-0.08455 0.1122369,0.1122369 0 0 1 0.0836,-0.03507 h 1.04422 a 0.1122369,0.1122369 0 0 1 0.1121,0.112229 0.10400615,0.10400615 0 0 1 -0.0339,0.07819 0.1122369,0.1122369 0 0 1 -0.0793,0.03109 h -0.92486 v 0.573906 h 0.82912 a 0.1122369,0.1122369 0 0 1 0.11222,0.112231 0.10325785,0.10325785 0 0 1 -0.0339,0.07819 0.10961794,0.10961794 0 0 1 -0.0797,0.03174 h -0.83056 v 0.57727 h 0.92448 a 0.1122369,0.1122369 0 0 1 0.11227,0.112242 0.10438032,0.10438032 0 0 1 -0.0339,0.07818 0.1122369,0.1122369 0 0 1 -0.0793,0.03109 h -1.04299 a 0.11448152,0.11448152 0 0 1 -0.0834,-0.0341 z"
id="path21-6"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><path
class="cls-2"
d="m 156.07405,39.906254 a 0.1122369,0.1122369 0 0 1 -0.0354,-0.08307 V 38.33118 h -0.53121 a 0.10625087,0.10625087 0 0 1 -0.10921,-0.109244 0.1122369,0.1122369 0 0 1 0.0317,-0.07931 0.10438032,0.10438032 0 0 1 0.0782,-0.0326 h 1.29669 a 0.1122369,0.1122369 0 0 1 0.1123,0.112251 0.10400615,0.10400615 0 0 1 -0.0339,0.07818 0.1122369,0.1122369 0 0 1 -0.0793,0.03109 h -0.5305 v 1.49161 a 0.109992,0.109992 0 0 1 -0.0364,0.08307 0.11635208,0.11635208 0 0 1 -0.0846,0.0341 0.1122369,0.1122369 0 0 1 -0.082,-0.0341 z"
id="path25-7"
style="fill:#ffffff;fill-opacity:1;stroke-width:0.999998" /><circle
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:6.80315;stroke-linecap:round;stroke-linejoin:round"
id="path2370"
cx="151.15277"
cy="39.704605"
r="0.23566821" /><rect
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="rect3"
width="29.719856"
height="15.399486"
x="9.3059111"
y="12.942889" /><g
id="g6"
transform="matrix(1.6970556,0,0,1.1457035,-62.716054,-14.100197)"
style="stroke-width:1.07574;stroke-dasharray:none;stroke:#ffffff;stroke-opacity:1"><path
style="fill:none;stroke:#ffffff;stroke-width:1.07574;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 49.030808,37.632967 -2.348149,8.763414 m 6.348149,-8.763414 2.677863,8.763414"
id="path6" /></g><path
style="fill:none;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path7"
d="m 26.714672,10.820005 a 1.6026552,1.2857661 0 0 1 -0.801328,1.113507 1.6026552,1.2857661 0 0 1 -1.602655,0 1.6026552,1.2857661 0 0 1 -0.801327,-1.113507 h 1.602655 z" /><path
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
id="path8"
d="m 19.920145,12.446616 a 4.2456937,4.2306275 0 0 1 4.245693,-4.2306274 4.2456937,4.2306275 0 0 1 4.245694,4.2306274 h -4.245694 z" /><g
id="g1"
transform="matrix(0,0.13298493,-0.12521031,0,101.95019,26.354144)"
style="stroke-width:7.74957"><path
id="path8642"
class="cls-1"
d="M -30,76.61 H 92.8 l 35,-34.76 H 44.2 Z"
style="fill:#d9e663;stroke-width:7.74957" /><path
id="path8668"
class="cls-1"
d="M -29.87,-1.31 H 53.8 l 74,-34.75 H 4.99 Z"
style="fill:#d9e663;stroke-width:7.74957" /><path
id="path8734"
class="cls-2"
d="m 127.8,41.85 v 112.72 l -35,35 v -113 z"
style="fill:#edfe60;stroke-width:7.74957" /><path
id="path8702"
class="cls-3"
d="m 53.94,-1.08 73.94,-34.76 h 0.17"
style="fill:#371900;stroke-width:7.74957" /><path
id="path8768"
class="cls-1"
d="M 5,189.56 H 92.8 V 154.81 H 5 Z"
style="fill:#d9e663;stroke-width:7.74957" /><path
id="path8834"
class="cls-2"
d="m -30,84.38 v 70.19 l 35,35 v -71.7 z"
style="fill:#edfe60;stroke-width:7.74957" /><path
id="path8880"
class="cls-2"
d="M 127.8,-36.08 -30,38.06 v 38.58 l 157.82,-74 z"
style="fill:#edfe60;stroke-width:7.74957" /><path
id="Pfad_210"
data-name="Pfad 210"
class="cls-1"
d="m -16.55,-66 a 13.07,13.07 0 0 0 -13.07,13.06 v 0 a 13.08,13.08 0 0 0 13.06,13.07 v 0 a 13.06,13.06 0 0 0 13.07,-13.05 v 0 a 13.06,13.06 0 0 0 -13.05,-13.07 v 0 m 0,1.7 a 11.37,11.37 0 1 1 -11.52,11.37 11.54,11.54 0 0 1 11.52,-11.37 m 7.22,6 -6.18,3.67 a 4.11,4.11 0 0 0 -4.05,-3.29 4.37,4.37 0 0 0 -4.26,4.45 v 4.66 h 14.48 v -1.62 h -6 v -2.39 l 6,-3.57 z m -10.21,2 a 2.83,2.83 0 0 1 2.75,2.88 v 3 h -5.54 v -2.82 a 2.84,2.84 0 0 1 2.65,-3 h 0.13"
style="fill:#d9e663;stroke-width:7.74957" /></g></svg>

After

Width:  |  Height:  |  Size: 27 KiB

34
public/index.html Normal file
View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta name="viewport" content="width=device-width, minimum-scale=1, initial-scale=1,maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div id="ar">
<div id="render">
<div class="ui">
<a href="#" data-action="fullscreen">&#x26F6;</a>
<a href="#" data-action="prev">🠈</a>
<select data-id="pages"></select>
<a href="#" data-action="next">🠊</a>
</div>
</div>
</div>
<script src="presentationmaker.js" type="text/javascript"></script>
<script type="text/javascript">
document.addEventListener("DOMContentLoaded", async () => {
const config = {
targetSelector: '#render',
sourceURI: 'example.xml',
transitionType: 'transform',
};
const pm = new PresentationMaker(config);
await pm.generate();
pm.present();
// custom script logic
});
</script>
</body>
</html>

BIN
public/roboto.woff2 Normal file

Binary file not shown.

106
public/style.css Normal file
View file

@ -0,0 +1,106 @@
@font-face {
font-family:'Roboto';
font-style:bold;
font-weight:600;
src:url(roboto.woff2) format('woff2');
font-display:swap
}
html,
body {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background-color: #000000;
font-size: min(1vw, 1.778vh);
overflow:clip;
font-family: Roboto, sans-serif;
}
#ar {
width: 100em;
height: 56.25em;
}
#render {
font-size: 1em;
a {
color: #BBBBff;
img {
vertical-align: bottom;
}
}
.ui {
position: fixed;
z-index: 999999;
color: #ffffff;
top: 20px;
left: 20px;
text-shadow: #000000 2px 0 0;
opacity: 0;
transition: opacity 1s ease-in-out;
font-size:2em;
&.visible {
opacity: 0.75;
}
a {
color: inherit;
text-decoration: none;
font-size: 1.0em;
}
a.disabled {
color: transparent;
cursor: default;
}
select {
margin: 0 5px;
outline: none;
}
}
}
#fullscreen {
font-weight: bold;
}
#fs {
margin-left:10px;
}
.page {
position: absolute;
transform-origin: top left 0px;
transition: opacity .5s ease-in-out;
}
.page.inactive {
opacity: 0.5;
transition: opacity .5s ease-in-out;
}
[data-action] {
height: 2em;
vertical-align: middle;
cursor: pointer;
}
#viewport {
transition: all 1s ease-in-out;
transform-style: preserve-3d;
transform-origin: top left 0px;
}
#render {
overflow: clip;
height:100vh;
perspective: 1000px;
}
.option {
width:100%;
height:100%;
}

432
src/presentationmaker.ts Normal file
View file

@ -0,0 +1,432 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
**/
import { RenderTree } from './rendertree/rendertree';
import { RTPage, RTTransformation } from './rendertree/rtpage';
/**
* configuration options for PresentationMaker
*/
export interface initialConfig {
/** selector for source tree inside a &lt;script type="presentationmaker"&gt;...&lt;/script&gt; */
sourceSelector?: string,
/** alternative URL instead of script tag */
sourceURI?: string,
/** position to attach generated tree to */
targetSelector: string,
/** optional transition type, defaults to flip */
transitionType?: string
/** option ui selector string */
uiSelector?: string;
}
/**
* main class
*/
export class PresentationMaker {
/** generated render tree */
private tree: RenderTree;
/** definitions for variable replacements */
private definitions: Array<Map<string, string>>;
/** custom modules defined by the import document */
private modules: Map<string, RenderTree>;
/** current page index */
private currentPage: number;
/** number of slide */
private numPages: number;
/** our viewport (window to the presentation) */
private viewportElement: HTMLDivElement;
/** transition type [flip / transition] */
private transition: string;
/** time for autohiding of UI */
private timer: number;
/** ui root node */
private ui: HTMLDivElement;
/** page selector */
private select: HTMLSelectElement;
/** X start position to detect slide left/right */
private touchStartX: number;
/** initial config from caller */
private config: initialConfig;
/**
* change slide to given number
* @param slideNum slide number 0-based
*/
private changeSlide(slideNum: number) {
if (slideNum < 0 && slideNum >= this.numPages) {
return;
}
const newPage = this.tree.getElement(slideNum);
const page = <RTPage>newPage;
const pages = this.viewportElement.querySelectorAll('.page');
if (this.currentPage >= 0 && this.currentPage < this.numPages) {
(<HTMLElement>pages[this.currentPage]).classList.add('inactive');
}
switch (this.transition) {
case 'transform':
// this.transform = page.getView();
this.currentPage = slideNum;
this.moveViewpoint();
break;
default:
if (this.currentPage >= 0 && this.currentPage < this.numPages) {
(<HTMLElement>pages[this.currentPage]).style.display = 'none';
}
this.currentPage = slideNum;
const newPage = <HTMLElement>pages[this.currentPage];
newPage.style.display = 'block'
break;
}
if (this.currentPage >= 0 && this.currentPage < this.numPages) {
(<HTMLElement>pages[this.currentPage]).classList.remove('inactive');
}
document.location.hash = (this.currentPage + 1).toString();
this.select.value = this.currentPage.toString();
const prev = document.querySelector('[data-action="prev"]');
if (this.currentPage == 0) {
prev.classList.add('disabled');
} else {
prev.classList.remove('disabled');
}
const next = document.querySelector('[data-action="next"]');
if (this.currentPage + 1 >= this.numPages) {
next.classList.add('disabled');
} else {
next.classList.remove('disabled');
}
}
/**
* constructor
*/
constructor(config: initialConfig) {
if (config === undefined) {
throw('please supply a configuration');
}
this.definitions = [];
this.modules = new Map<string, RenderTree>();
this.currentPage = 0;
this.numPages = 0;
this.transition = config.transitionType || 'flip';
this.tree = new RenderTree(this, null);
this.ui = document.querySelector(config.uiSelector || '.ui');
this.select = this.ui.querySelector('select[data-id=pages]');
if (document.location.hash) {
this.currentPage = parseInt(document.location.hash.substring(1)) - 1;
}
this.config = config;
}
/**
* create definitions from element tree
* @param elem &lt;definition&gt;...&lt;/definition&gt; node tree
*/
private createDefinitions(elem: HTMLElement): void {
const definitions: Map<string, string> = new Map<string, string>();
elem.childNodes.forEach((def) => {
if (def.nodeType == 1) {
const definitionElement = <HTMLElement>def;
definitions.set(definitionElement.localName, definitionElement.innerHTML);
}
});
this.definitions.push(definitions);
}
/**
* create a custom module from input
* @param elem &lt;module&gt;...&lt;/module&gt; node tree
*/
private createModules(elem: HTMLElement): void {
elem.childNodes.forEach((module) => {
if (module.nodeType == 1) {
const moduleElement = <HTMLElement>module;
const tree = new RenderTree(this);
tree.createFromElem(moduleElement);
this.modules.set(moduleElement.localName, tree);
}
});
}
/**
* create pages from input
* @param elem &lt;slides&gt;...&lt;/slides&gt; node tree
*/
private createPages(elem: HTMLElement): void {
const pageElement = <HTMLElement>elem;
this.tree.createFromElem(pageElement);
this.numPages = this.tree.getElementCount();
this.definitions[0].set('numpages', this.numPages.toString());
this.definitions[0].set('page', '0');
for (let i = 0; i < this.numPages; ++i) {
const newPage = this.tree.getElement(i);
const page = <RTPage>newPage;
const option = document.createElement('option');
option.value = i.toString();
option.innerText = page.getName();
this.select.append(option);
}
}
/**
* generate HTML tree from input XML
*/
async generate(): Promise<void> {
let root;
const parser = new DOMParser();
if (this.config.sourceSelector !== undefined) {
const source = document.querySelector(this.config.sourceSelector);
root = <HTMLElement>parser.parseFromString(source.outerHTML, 'application/xml').querySelector('script');
} else {
const response = await fetch(this.config.sourceURI);
const data = await response.blob();
root = <HTMLElement>parser.parseFromString(await data.text(), 'application/xml').querySelector('presentation');
}
// iterate over the elements
root.childNodes.forEach((node) => {
const elem = <HTMLElement>node;
switch (elem.localName) {
case 'definitions':
this.createDefinitions(elem);
break;
case 'modules':
this.createModules(elem);
break;
case 'pages':
this.createPages(elem);
break;
}
node = node.nextSibling;
});
// render pages
this.viewportElement = <HTMLDivElement>document.createElement('div');
this.viewportElement.id = 'viewport';
this.tree.render(this.viewportElement);
const renderTarget = <HTMLDivElement>document.querySelector(this.config.targetSelector);
renderTarget.append(this.viewportElement);
}
/**
* get a definition (value) for given name
* @param name name to look up
* @returns value or '' if not found
* @internal
*/
getDefinition(name: string): string {
let ret = '';
this.definitions.forEach((definitions) => {
const i = definitions.get(name);
if (i !== undefined) {
ret = i;
}
});
if (ret === '') {
console.log('failed to get definition for', name);
}
return ret;
}
/**
* create a new module (copy) with given name
* @param name name of module
* @return copy of module or null if not found
* @internal
*/
getNewModule(name: string): RenderTree {
const i = this.modules.get(name);
if (i !== undefined) {
return (new RenderTree(this, i));
}
console.log('unknown render element', name);
return null;
}
/**
* handle mouse click or tap events
* @param ev brower event
*/
private handleClick = (ev?: MouseEvent) => {
const target = <HTMLElement>ev.target;
let action = target.getAttribute('data-action');
if (action === null) {
action = target.getAttribute("data-id");
}
let slideNum;
switch (action) {
case 'fullscreen':
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen();
} else {
document.exitFullscreen();
}
ev.stopPropagation();
ev.preventDefault();
break;
case 'prev':
slideNum = Math.max(this.currentPage - 1, 0);
break;
case 'next':
case null:
slideNum = Math.min(this.currentPage + 1, this.numPages - 1);
break;
}
if (slideNum !== undefined) {
this.changeSlide(slideNum);
}
if (target.closest('.ui')) {
ev.stopPropagation();
ev.preventDefault();
}
return false;
}
/**
* handle a change of the page dropdown
*/
private handleDropdown = (ev?: Event) => {
ev.stopPropagation();
ev.preventDefault();
this.changeSlide(parseInt(this.select.value));
return false;
}
/**
* handle key presses
* @param ev pressed key
*/
private handleKey = (ev?: KeyboardEvent) => {
switch (ev.key) {
case 'ArrowLeft':
this.changeSlide(Math.max(this.currentPage - 1, 0));
break;
case 'ArrowRight':
this.changeSlide(Math.min(this.currentPage + 1, this.numPages - 1));
break;
}
}
/**
* handle mouse move and show ui
*/
private handleMouseMove = () => {
if (this.timer) {
window.clearTimeout(this.timer);
}
this.ui.classList.add('visible');
document.body.style.cursor = 'auto';
this.timer = window.setTimeout(this.hideUI, 2000);
}
/**
* handle end of touch event
* creates slide left or right if swipe was long enough
* @param ev browser touch event
*/
private handleTouchEnd = (ev: TouchEvent) => {
const touchEndX = ev.changedTouches[0].screenX;
if (Math.abs(this.touchStartX - touchEndX) > 100) {
let slideNum;
if (this.touchStartX < touchEndX) {
slideNum = Math.max(this.currentPage - 1, 0);
} else {
slideNum = Math.min(this.currentPage + 1, this.numPages - 1);
}
this.changeSlide(slideNum);
} else {
this.handleMouseMove();
}
}
/**
* handle start of touch
* saves position to detect swipes
*/
private handleTouchStart = (ev: TouchEvent) => {
this.touchStartX = ev.changedTouches[0].screenX;
}
/**
* hide ui
* called by timer function
*/
private hideUI = () => {
this.ui.classList.remove('visible');
document.body.style.cursor = 'none';
}
/**
* move viewpoint to area defined by current page
*/
private moveViewpoint = () => {
const view = (<RTPage>this.tree.getElement(this.currentPage)).getView();
let transform = '';
if (view.viewRotation.x) {
transform += ' rotateX(' + (-view.viewRotation.x) + 'deg) ' + transform;
}
if (view.viewRotation.y) {
transform += ' rotateY(' + (-view.viewRotation.y) + 'deg) ' + transform;
}
if (view.viewRotation.z) {
transform += ' rotateZ(' + (-view.viewRotation.z) + 'deg) ' + transform;
}
transform += ' translate3d(' + (-view.position.x) + 'px,' + (-view.position.y) + 'px, ' + (-view.position.z) + 'px)';
// calculate zoom
const wc = parseInt(this.getDefinition('width')) / view.size.w;
const hc = parseInt(this.getDefinition('height')) / view.size.h;
const scale = Math.min(wc, hc);
const zoom = this.viewportElement.parentElement.clientHeight / parseFloat(this.getDefinition('height')) * scale;
if (zoom != 1) {
transform = 'scale(' + zoom + ')' + transform;
}
this.viewportElement.style.transform = transform;
}
/**
* pop defintion list to remove last definition from stack
* @internal
*/
pop() {
this.definitions.pop();
}
/**
* add handles for presentation and start it
*/
present() {
window.addEventListener('resize', this.moveViewpoint);
const list = document.querySelectorAll('body, [data-action]');
list.forEach((e) => {
e.addEventListener('click', this.handleClick);
});
window.addEventListener('keydown', this.handleKey);
this.select.addEventListener('change', this.handleDropdown);
window.addEventListener('mousemove', this.handleMouseMove);
document.body.addEventListener('touchstart', this.handleTouchStart);
document.body.addEventListener('touchend', this.handleTouchEnd);
this.moveViewpoint();
this.changeSlide(this.currentPage);
}
/**
* push a new empty definition list to stack
* @internal
*/
push(): void {
this.definitions.push(new Map());
}
/**
* set a value to current definition list on stack
* @internal
*/
set(key: string, value: string): void {
const definition = this.definitions.at(-1);
definition.set(key, value);
}
}

View file

@ -0,0 +1,178 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
**/
import { PresentationMaker } from '../presentationmaker';
import { RTModule } from './rtmodule';
import { RTNode } from './rtnode';
import { RTImg } from './rtimg';
import { RTCalc } from './rtcalc';
import { RTText } from './rttext';
import { RTOptions } from './rtoptions';
import { RTPage } from './rtpage';
/**
* the root of render tree
* @internal
*/
export class RenderTree {
/** handle to main instance */
private main: PresentationMaker;
/** our child elements */
private elements: RTNode[];
/** definitions from input */
private definitions: Map<string, string>;
/**
* constructor
* @param pm handle to main instance
* @param other optional other tree to copy data from
*/
constructor(pm: PresentationMaker, other: RenderTree = null) {
this.main = pm;
this.elements = [];
this.definitions = new Map<string, string>();
if (other !== null) {
other.elements.forEach((e) => {
this.elements.push(e.clone());
});
}
}
/**
* create elements from given parent
* @param baseElem root element to create new render tree nodes
*/
createFromElem(baseElem: HTMLElement) {
const nodes = baseElem.childNodes;
nodes.forEach((node) => {
if (node.nodeType === 1) {
const newNode = this.createNodeFromElem(<HTMLElement>node);
if (newNode !== null) {
this.elements.push(newNode);
}
}
});
}
/**
* create a new node from given element
*
* currently supports 'calc', 'img', 'options', 'page', 'text'
* @param elem to create from
*/
createNodeFromElem(elem: HTMLElement): RTNode {
const name = elem.localName;
// final types
switch (name) {
case 'calc':
return RTCalc.fromElem(this, elem);
case 'img':
return RTImg.fromElem(this, elem);
case 'options':
return RTOptions.fromElem(this.main, this, elem);
case 'page':
return RTPage.fromElem(this.main, this, elem);
case 'text':
return RTText.fromElem(this, elem);
}
// still here, probably a module
const tree = this.main.getNewModule(name);
if (tree === null) {
console.log('unknown module', name);
return null;
}
tree.definitions.clear();
// add attributes to node
for (let i = 0; i < elem.attributes.length; ++i) {
const attr = elem.attributes[i];
tree.definitions.set(attr.localName, attr.textContent);
}
elem.childNodes.forEach((child) => {
if (child.nodeType === 1) {
const childElem = <HTMLElement>child;
tree.definitions.set(childElem.localName, childElem.innerHTML);
}
});
return new RTModule(this, tree);
}
/**
* get current definition for given name
* @param name name to look up
* @returns value or ''
*/
getDefinition(name: string): string {
return this.main.getDefinition(name);
}
/**
* get node with given index
* @param num index
* @return node or null if invalid index
*/
getElement(num: number): RTNode {
if (num >= 0 && num <= this.elements.length) {
return this.elements[num];
}
return null;
}
/**
* return the number of elements in the root tree
*/
getElementCount(): number {
return this.elements.length;
}
/**
* get main instance
* @returns main instance
*/
getMain(): PresentationMaker {
return this.main;
}
/**
* pop defintion list to remove last definition from stack
*/
pop() {
this.main.pop();
}
/**
* push a new empty definition list to stack
*/
push(): void {
this.main.push();
}
/**
* render tree to given target
* @param target target to render into
*/
render(target: HTMLElement) {
this.main.push();
// save current definitions on the stack
this.definitions.forEach((v, k) => {
this.main.set(k, v);
});
this.elements.forEach((element) => {
element.render(target);
});
this.main.pop();
}
/**
* set definition
* @param key key name
* @param value value data
*/
set(key: string, value: string) {
this.main.set(key, value);
}
};

67
src/rendertree/rtcalc.ts Normal file
View file

@ -0,0 +1,67 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
import Formula from 'fparser';
/**
* calculate new defintions based on formula
*/
export class RTCalc extends RTNode {
/** name of the definition */
private target: string;
/** expression to calculate */
private expression: string;
/**
* clone function
* @return a copy of us
*/
clone(): RTCalc {
return new RTCalc(this.root, this.target, this.expression);
}
/**
* constructor
* @param root our parent RenderTree
* @param target name of the new definition
* @param expression expression to calculate
*/
constructor(root: RenderTree, target: string, expression: string) {
super(root);
this.target = target;
this.expression = expression;
}
/**
* create RTCalc from given node into given RenderTree
* @param root render tree to insert to
* @param node input node
* @returns new RTCalc node
*/
static fromElem(root: RenderTree, node: HTMLElement): RTCalc {
return new RTCalc(
root,
node.getAttribute('name') || '',
node.innerHTML
);
}
/**
* render our element into target
* @param target target to render into
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
render(target: HTMLElement): void {
const exp = this.resolveString(this.expression);
const fObj = new Formula(exp);
const result = fObj.evaluate({});
this.root.set(this.target, result.toString());
}
}

99
src/rendertree/rtimg.ts Normal file
View file

@ -0,0 +1,99 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
/**
* renders an image from <img> tag
*/
export class RTImg extends RTNode {
/** src URI */
private src: string;
/** x position */
private x: string;
/** y position */
private y: string;
/** width */
private width: string;
/** height */
private height: string;
/** mask-image css string */
private maskImage: string;
/**
* clone function
* @return a copy of us
*/
clone(): RTImg {
return new RTImg(
this.root,
this.src,
this.x,
this.y,
this.width,
this.height,
this.maskImage
);
}
/**
* constructor
* @param root our parent RenderTree
* @param src source URI
* @param x x position
* @param y y position
* @param width image width
* @param height image height
* @param maskImage optional css for mask-image
*/
constructor(root: RenderTree, src: string, x: string, y: string, width: string, height: string, maskImage: string) {
super(root);
this.src = src;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.maskImage = maskImage;
}
/**
* create RTImg from given node into given RenderTree
* @param root render tree to insert to
* @param node input node
* @returns new RTImg node
*/
static fromElem(root: RenderTree, node: HTMLElement): RTImg {
return new RTImg(
root,
this.getField(node, 'src'),
this.getField(node, 'x'),
this.getField(node, 'y'),
this.getField(node, 'width'),
this.getField(node, 'height'),
this.getField(node, 'mask-image')
);
}
/**
* render image to HTML target
* @param target target to render to
*/
render(target: HTMLElement): void {
const img = document.createElement('img');
img.style.position = 'absolute';
img.style.top = this.calc(this.resolveString(this.y)) + 'px';
img.style.left = this.calc(this.resolveString(this.x)) + 'px';
img.setAttribute('width', this.calc(this.resolveString(this.width)).toString());
img.setAttribute('height', this.calc(this.resolveString(this.height)).toString());
img.setAttribute('src', this.resolveString(this.src));
if (this.maskImage) {
img.style.maskImage = this.maskImage;
}
target.append(img);
}
}

View file

@ -0,0 +1,43 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
**/
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
/**
* custom user declared module
*/
export class RTModule extends RTNode {
/** render tree for our children */
private tree: RenderTree;
/**
* clone function
* @return a copy of us
*/
clone(): RTModule {
const tree = new RenderTree(this.root.getMain(), this.tree);
return new RTModule(this.root, tree);
}
/**
* constructor
* @param root parent RenderTree
* @param tree child renderTree
*/
constructor(root: RenderTree, tree: RenderTree) {
super(root);
this.tree = tree;
}
/**
* render module content to given target
* @param target target to render to
*/
render(target: HTMLElement): void {
this.tree.render(target);
}
}

105
src/rendertree/rtnode.ts Normal file
View file

@ -0,0 +1,105 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { RenderTree } from './rendertree';
import Formula from 'fparser';
/**
* base class for all RenderTree nodes
*/
export abstract class RTNode {
/** root render tree */
protected root: RenderTree;
/**
* calculate given expression
* @param exp expression string
* @returns result as number or 0 in case of error
*/
calc(exp: string): number {
if (exp === '') {
return 0;
}
try {
const fObj = new Formula(exp);
return <number>fObj.evaluate({});
} catch(e) {
}
return 0;
}
/**
* abstract function to clone the node
* must be implemented by every sub class
*/
abstract clone(): RTNode;
/**
* constructor
* @param root parent RenderTree
*/
constructor(root: RenderTree) {
this.root = root;
}
/**
* helper function to get value from attribute or from named child node
* @param node current HTML element
* @param name name of element to fetch
* @return value or '' in case of error
*/
static getField(node: HTMLElement, name: string): string {
// try attribute
let field = node.getAttribute(name);
// try child nodes
node.childNodes.forEach((child) => {
if (child.nodeType === 1) {
const childElem = <HTMLElement>child;
if (childElem.localName === name) {
field = childElem.innerHTML;
}
}
});
return field;
}
/**
* abstract function to render the node
* must be implemented by every sub class
* @param target target to render into
*/
abstract render(target: HTMLElement): void;
/**
* resolve a string using variable replacements
* @param input input string
* @returns input strings with replaced variables
*/
resolveString(input: string): string {
if (!input || input.indexOf('$') < 0) {
return input;
}
let str = input;
let dollar;
let lastDollar = 0;
while ((dollar = str.indexOf('${', lastDollar)) >= 0) {
if (str.at(dollar - 1) == '\\') {
str = str.substring(0, dollar - 1) + str.substring(dollar);
lastDollar = dollar + 1;
continue;
}
const end = str.indexOf('}', dollar);
if (end < 0) break;
const search = str.substring(dollar + 2, end);
const replace = this.root.getDefinition(search);
str = str.replace(str.substring(dollar, end + 1), replace);
}
return (str);
}
}

125
src/rendertree/rtoptions.ts Normal file
View file

@ -0,0 +1,125 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { PresentationMaker } from '../presentationmaker';
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
/**
* transform subtree by given options
*/
export class RTOptions extends RTNode {
/** blend mode */
private blendmode: string;
/** flip axis */
private flip: string;
/** opactity */
private opacity: string;
/** rotate */
private rotate: string;
/** subtee to transform */
private subtree: RenderTree;
/** y position when flipping */
private y: string;
/**
* clone function
* @return a copy of us
*/
clone(): RTOptions {
return new RTOptions(
this.root,
this.subtree,
this.opacity,
this.blendmode,
this.flip,
this.rotate,
this.y
);
}
/**
* constructor
* @param root parent RenderTree
* @param subtree child sub tree
* @param opacity opacity value
* @param blendmode blend mode
* @param flip flip axis
* @param rotate rotation in degree X, Y, Z
* @param y y position when flipping
*/
constructor(root: RenderTree, subtree: RenderTree, opacity: string, blendmode: string, flip: string, rotate: string, y: string) {
super(root);
this.subtree = subtree;
this.opacity = opacity;
this.blendmode = blendmode;
this.flip = flip;
this.rotate = rotate;
this.y = y;
}
/**
* create RTOptions from given node into given RenderTree
* @param root render tree to insert to
* @param node input node
* @returns new RTOptions node
*/
static fromElem(main: PresentationMaker, root: RenderTree, node: HTMLElement): RTOptions {
const subtree = new RenderTree(main);
subtree.createFromElem(node);
return new RTOptions(
root,
subtree,
this.getField(node, 'opacity') || '',
this.getField(node, 'blend') || '',
this.getField(node, 'flip') || '',
this.getField(node, 'rotate') || '',
this.getField(node, 'y') || ''
);
}
/**
* render our element into target
* @param target target to render into
*/
render(target: HTMLElement): void {
const div = document.createElement('div');
div.classList.add('option');
if (this.opacity !== '') {
div.style.opacity = this.opacity;
}
if (this.blendmode !== '') {
div.style.mixBlendMode = this.blendmode;
}
if (this.flip !== '') {
if (this.flip == 'v') {
div.style.transform = 'scaleY(-1)';
}
}
if (this.y) {
div.style.position = 'absolute';
div.style.bottom = '0px';
}
if (this.rotate !== '') {
const r = this.rotate.split(',');
let transform = '';
if (r[0]) {
transform += 'rotateX(' + (this.calc(this.resolveString(r[0]))) + 'deg)';
}
if (r[1]) {
transform += 'rotateY(' + (this.calc(this.resolveString(r[1]))) + 'deg)';
}
if (r[2]) {
transform += 'rotateZ(' + (this.calc(this.resolveString(r[2]))) + 'deg)';
}
div.style.transform = transform;
div.style.transformOrigin = 'top left';
}
this.subtree.render(div);
target.append(div);
}
}

257
src/rendertree/rtpage.ts Normal file
View file

@ -0,0 +1,257 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
import { PresentationMaker } from '../presentationmaker';
/**
* view transformations as strings
*/
export interface TransformationS {
/** position on HTML space */
position: {x: string, y: string, z: string};
/** rotation in HTML space */
rotation: {x: string, y: string, z: string};
/** page size in pixels */
size: {w: string, h: string};
/** view position in HTML space */
viewpos: {x: string, y: string, z: string};
/** view size in pixels */
viewSize: {w: string, h: string};
/** view rotation in degree */
viewRotation: {x: string, y: string, z: string};
}
/**
* view transformation as numbers
*/
export interface RTTransformation {
/** view position */
position: {x: number, y: number, z: number};
/** view size */
size: {w: number, h: number};
/** view rotation in degrees */
viewRotation: {x: number, y: number, z: number};
}
/**
* page node
*/
export class RTPage extends RTNode {
/** page id */
private id: string;
/** page name */
private name: string;
/** tree to render on page */
private subtree: RenderTree;
/** tranform informations */
private transformation: TransformationS;
/**
* clone function
* @return a copy of us
*/
clone(): RTPage {
return new RTPage(
this.root,
this.subtree,
this.id,
this.transformation.size.w,
this.transformation.size.h,
this.transformation.position.x,
this.transformation.position.y,
this.transformation.position.z,
this.transformation.rotation.y,
this.transformation.rotation.y,
this.transformation.rotation.z,
this.transformation.viewpos.x,
this.transformation.viewpos.y,
this.transformation.viewpos.z,
this.transformation.viewSize.w,
this.transformation.viewSize.h,
this.transformation.viewRotation.x,
this.transformation.viewRotation.y,
this.transformation.viewRotation.z,
this.name
)
}
/**
* constructor
* @param root parent RenderTree
* @param subtree RenderTree for page content
* @param id page id
* @param width page width
* @param height page height
* @param x x position
* @param y y position
* @param z z position
* @param rx rotation on X-axis
* @param ry rotation on Y-axis
* @param rz rotation on Z-axis
* @param vx view position on X-axis
* @param vy view position on Y-axis
* @param vz view position on Z-axis
* @param vrx view rotation on X-axis
* @param vry view rotation on Y-axis
* @param vrz view rotation on Z-axis
*/
constructor(root: RenderTree, subtree: RenderTree, id: string, width: string, height: string, x: string, y: string, z: string, rx: string, ry: string, rz:string, vx: string, vy: string, vz: string, vw: string, vh: string, vrx: string, vry: string, vrz: string, name: string) {
super(root);
this.subtree = subtree;
this.id = id;
this.transformation = {
size: { w: width, h: height},
position: {x: x, y: y, z: z},
rotation: {x: rx, y: ry, z: rz},
viewpos: {x: vx, y: vy, z: vz},
viewSize: {w: vw, h: vh},
viewRotation: {x: vrx, y: vry, z: vrz}
};
this.name = name;
}
/**
* create RTPage from given node into given RenderTree
* @param root render tree to insert to
* @param node input node
* @returns new RTOptions node
*/
static fromElem(main:PresentationMaker, root: RenderTree, node: HTMLElement): RTPage {
const subtree = new RenderTree(main);
subtree.createFromElem(node);
return new RTPage(
root,
subtree,
node.getAttribute('id') || '',
node.getAttribute('width') || '${width}',
node.getAttribute('height') || '${height}',
node.getAttribute('x') || '0',
node.getAttribute('y') || '0',
node.getAttribute('z') || '0',
node.getAttribute('rx') || '0',
node.getAttribute('ry') || '0',
node.getAttribute('rz') || '0',
node.getAttribute('vx') || '',
node.getAttribute('vy') || '',
node.getAttribute('vz') || '',
node.getAttribute('vwidth') || '',
node.getAttribute('vheight') || '',
node.getAttribute('vrx') || '',
node.getAttribute('vry') || '',
node.getAttribute('vrz') || '',
node.getAttribute('name') || '${page}',
);
}
/**
* get page name
* @returns page name
*/
getName(): string {
return this.name;
}
/**
* get view transformation
* @return RTTransformation
*/
getView(): RTTransformation {
let position;
if (this.transformation.viewpos.x !== '' || this.transformation.viewpos.y !== '' || this.transformation.viewpos.z !=='') {
position = {
x: this.calc(this.resolveString(this.transformation.viewpos.x)),
y: this.calc(this.resolveString(this.transformation.viewpos.y)),
z: this.calc(this.resolveString(this.transformation.viewpos.z))
};
} else {
position = {
x: this.calc(this.resolveString(this.transformation.position.x)),
y: this.calc(this.resolveString(this.transformation.position.y)),
z: this.calc(this.resolveString(this.transformation.position.z))
}
}
let size;
if (this.transformation.viewSize.w !== '' || this.transformation.viewSize.h !== '') {
size = {
w: this.calc(this.resolveString(this.transformation.viewSize.w)),
h: this.calc(this.resolveString(this.transformation.viewSize.h))
};
} else {
size = {
w: this.calc(this.resolveString(this.transformation.size.w)),
h: this.calc(this.resolveString(this.transformation.size.h))
}
}
let viewRotation;
if (this.transformation.viewRotation.x !== '' || this.transformation.viewRotation.y !== '' || this.transformation.viewRotation.z !== '') {
viewRotation = {
x: this.calc(this.resolveString(this.transformation.viewRotation.x)),
y: this.calc(this.resolveString(this.transformation.viewRotation.y)),
z: this.calc(this.resolveString(this.transformation.viewRotation.z))
}
} else {
viewRotation = {
x: 0,
y: 0,
z: 0
}
}
return {
position: position,
size: size,
viewRotation: viewRotation
};
}
/**
* render our element into target
* @param target target to render into
*/
render(target: HTMLElement): void {
this.root.set('page', (parseInt(this.root.getDefinition('page')) + 1).toString());
const pageDiv = document.createElement('article');
pageDiv.classList.add('page');
pageDiv.classList.add('inactive');
let transform = '';
const x = this.calc(this.resolveString(this.transformation.position.x));
const y = this.calc(this.resolveString(this.transformation.position.y));
const z = this.calc(this.resolveString(this.transformation.position.z));
if (x || y || z) {
transform += 'translate3d(' + x + 'px, ' + y + 'px, ' + z + 'px)';
}
const rx = -this.calc(this.resolveString(this.transformation.rotation.x));
const ry = -this.calc(this.resolveString(this.transformation.rotation.y));
const rz = -this.calc(this.resolveString(this.transformation.rotation.z));
if (rx) {
transform += 'rotateX(' + rx + 'deg)';
}
if (ry) {
transform += 'rotateY(' + ry + 'deg)';
}
if (rz) {
transform += 'rotateZ(' + rz + 'deg)';
}
if (transform !== '') {
pageDiv.style.transform = transform;
}
const width = this.calc(this.resolveString(this.transformation.size.w)).toString();
const height = this.calc(this.resolveString(this.transformation.size.h)).toString();
pageDiv.style.width = width + 'px';
pageDiv.style.height = height + 'px';
if (this.id) {
pageDiv.id = this.id;
}
target.append(pageDiv);
this.root.push()
this.subtree.set('width', width);
this.subtree.set('height', height);
this.subtree.render(pageDiv);
this.root.pop()
}
}

179
src/rendertree/rttext.ts Normal file
View file

@ -0,0 +1,179 @@
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
* @author Author: Sascha Nitsch (grumpydeveloper)
* @internal
**/
import { RTNode } from './rtnode';
import { RenderTree } from './rendertree';
/**
* Text node
*/
export class RTText extends RTNode {
/** left position of text box */
private x0: string;
/** top position of text box */
private y0: string;
/** rigth position of text box */
private x1: string;
/** left bottom of text box */
private y1: string;
/** width of text box */
private width: string;
/** height of text box */
private height: string;
/** compact list of [left, top, right, bottom] */
private pos: string;
/** horizontal alignment of text in box */
private halign: string;
/** vertical alignment of text in box */
private valign: string;
/** font size */
private fontSize: string;
/** actual text */
private text: string;
/** text color */
private color: string;
/**
* clone function
* @return a copy of us
*/
clone(): RTText {
return new RTText(
this.root,
this.x0,
this.y0,
this.x1,
this.y1,
this.width,
this.height,
this.pos,
this.halign,
this.valign,
this.fontSize,
this.text,
this.color
);
}
/**
* create Node from HTMLElement
* @internal
* */
static fromElem(root: RenderTree, node: HTMLElement): RTText {
return new RTText(
root,
node.getAttribute('x0'),
node.getAttribute('y0'),
node.getAttribute('x1'),
node.getAttribute('y1'),
node.getAttribute('w'),
node.getAttribute('h'),
node.getAttribute('pos'),
node.getAttribute('halign') || 'center',
node.getAttribute('valign'),
node.getAttribute('size'),
node.innerHTML,
node.getAttribute('color') || root.getDefinition('defaultfontcolor')
);
}
/**
* constructor
* @param root parent RenderTree
* @param x0 left position of text box
* @param y0 top position of text box
* @param width width of text box
* @param height heightof text box
* @param pos short version of [left, top, right, bottom]
* @param halign horizontal alignment in text box
* @param valign vertical alignment in text box
* @param fontSize font size
* @param text actural text
* @param color text color
*/
constructor(root: RenderTree, x0: string, y0: string, x1: string, y1: string, width: string, height: string, pos: string, halign: string, valign: string, fontSize: string, text: string, color: string) {
super(root);
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
this.width = width;
this.height = height;
this.pos = pos;
this.halign = halign;
this.valign = valign;
this.fontSize = fontSize;
this.text = text;
this.color = color;
}
/**
* render image to HTML target
* @param target target to render to
*/
render(target: HTMLElement): void {
let x0: number;
let y0: number;
let x1: number;
let y1: number;
if (this.pos) {
const posLookup = this.resolveString(this.pos);
const tokens = posLookup.split(',');
if (tokens.length != 4) {
return;
}
x0 = this.calc(this.resolveString(tokens[0]));
y0 = this.calc(this.resolveString(tokens[1]));
x1 = this.calc(this.resolveString(tokens[2]));
y1 = this.calc(this.resolveString(tokens[3]));
} else {
x0 = this.calc(this.resolveString(this.x0));
y0 = this.calc(this.resolveString(this.y0));
if (this.x1) {
x1 = this.calc(this.resolveString(this.x1));
y1 = this.calc(this.resolveString(this.y1));
} else {
x1 = x0 + this.calc(this.resolveString(this.width));
y1 = y0 + this.calc(this.resolveString(this.height));
}
}
const halign = this.resolveString(this.halign);
const valign = this.resolveString(this.valign);
const text = this.resolveString(this.text);
const div = document.createElement('div');
if (this.color) {
div.style.color = this.resolveString(this.color);
}
div.style.position = 'absolute';
if (this.fontSize) {
div.style.fontSize = this.calc(this.resolveString(this.fontSize)) + 'px';
}
div.style.left = x0 + 'px';
div.style.top = y0 + 'px';
div.style.width = (x1 - x0) + 'px';
div.style.height = (y1 - y0) + 'px';
div.style.overflow = 'clip';
switch (halign) {
case 'center':
div.style.textAlign = 'center';
break;
case 'right':
div.style.textAlign = 'right';
break;
}
switch (valign) {
case 'center':
div.style.alignContent = 'center';
break;
case 'bottom':
div.style.alignContent = 'end';
break;
}
div.insertAdjacentHTML('afterbegin', text);
target.append(div);
}
}

21
tsconfig.json Normal file
View file

@ -0,0 +1,21 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "ES6",
"target": "ES6",
"allowJs": true,
"moduleResolution": "Bundler",
},
"typedocOptions": {
"entryPoints": ["./src", "./src/rendertree"],
"entryPointStrategy": "expand",
"out": "docs",
"excludePrivate": false,
},
"visibilityFilters": {
"protected": true,
"private": true,
"inherited": true,
}
}

23
webpack.config.js Normal file
View file

@ -0,0 +1,23 @@
const path = require('path');
module.exports = {
entry: './src/presentationmaker.ts',
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'presentationmaker.js',
libraryTarget: 'global',
},
};