31 Commits

Author SHA1 Message Date
77a83f6a4e Some ideas on API
probably not going to continue, as there is nowhere near enough need for
it
2025-10-24 14:29:51 +02:00
ef80cf45dc some progress on util 2024-07-21 08:50:00 +02:00
janis
1d185e05a7 some small tweaks to init function 2024-02-26 17:00:56 +01:00
janis
667cca709e small updates 2024-02-26 16:10:11 +01:00
janis
33386d6247 go back to js 2024-02-26 15:50:12 +01:00
Janis Hutz
d0b9bca5d4 Update README.md 2024-01-30 22:00:32 +01:00
janis
2f99906932 some more progress 2024-01-22 17:09:34 +01:00
b0eb35bae4 check if all impress features are available 2024-01-17 14:52:37 +01:00
janis
b07199bc16 remove unnecessary function 2024-01-16 11:05:04 +01:00
janis
587be5ee61 Some more progress on comments 2024-01-16 10:25:35 +01:00
janis
2efd14b392 progress on implementing core functionality 2024-01-15 17:02:41 +01:00
janis
328cf3b8e8 add / remove elements 2024-01-15 16:24:18 +01:00
janis
6761ff8dfe some more docs 2024-01-15 15:43:37 +01:00
fd49cd4fb4 some small fixes 2024-01-11 18:00:00 +01:00
2d9c48d375 update jsdocs 2024-01-10 16:21:23 +01:00
Janis Hutz
6a74c4e237 Merge branch 'impress:master' into v3 2024-01-10 08:30:14 +01:00
472e6d0f19 some small progress 2024-01-09 20:22:02 +01:00
janis
e326b2635f some more restructuring 2024-01-09 09:32:41 +01:00
a1fa8bea3d make eslint default linter 2024-01-08 21:26:02 +01:00
4199e99d81 massive readme update 2024-01-08 21:21:10 +01:00
b4cc35084c some more TS config 2024-01-08 20:53:24 +01:00
90653fa34e restructure, move to TS 2024-01-08 20:37:18 +01:00
janis
125ab80766 add some docs 2024-01-08 16:58:10 +01:00
janis
ad27645c39 Some more work on refactoring 2024-01-08 16:16:45 +01:00
Janis Hutz
e0ebff6b0c Update README.md 2023-11-06 10:23:22 +01:00
Janis Hutz
80d496f2bd add logo with correct name 2023-11-06 10:20:22 +01:00
Janis Hutz
42af5452ae Delete logo.jpg.JPG 2023-11-06 10:19:27 +01:00
Janis Hutz
2b88f378b2 Update README.md 2023-11-06 10:19:01 +01:00
Janis Hutz
78bdf4050b add impress logo 2023-11-06 10:18:12 +01:00
Janis Hutz
fa87b43aab Update README.md
remove commit activity
2023-11-06 10:15:36 +01:00
Janis Hutz
698558254f Update README.md 2023-11-06 10:10:41 +01:00
29 changed files with 8029 additions and 5128 deletions

View File

@@ -1,296 +1,300 @@
module.exports = {
"env": {
"browser": true,
"es6": true
'env': {
'browser': true,
'es6': true
},
"extends": "eslint:recommended",
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
'globals': {
'Atomics': 'readonly',
'SharedArrayBuffer': 'readonly'
},
"parserOptions": {
"ecmaVersion": 2018
'parserOptions': {
'ecmaVersion': 2022
},
"rules": {
"accessor-pairs": "error",
"array-bracket-newline": "error",
"array-bracket-spacing": "error",
"array-callback-return": "error",
"array-element-newline": "error",
"arrow-body-style": "error",
"arrow-parens": "error",
"arrow-spacing": "error",
"block-scoped-var": "off",
"block-spacing": [
"error",
"always"
'parser': '@typescript-eslint/parser',
'plugins': ['@typescript-eslint'],
'rules': {
'accessor-pairs': 'error',
'array-bracket-newline': 'error',
'array-bracket-spacing': 'error',
'array-callback-return': 'error',
'array-element-newline': 'error',
'arrow-body-style': 'error',
'arrow-parens': 'error',
'arrow-spacing': 'error',
'block-scoped-var': 'off',
'block-spacing': [
'error',
'always'
],
"brace-style": [
"error",
"1tbs",
'brace-style': [
'error',
'1tbs',
{
"allowSingleLine": true
'allowSingleLine': true
}
],
"callback-return": "error",
"camelcase": "error",
"capitalized-comments": "off",
"class-methods-use-this": "error",
"comma-dangle": "error",
"comma-spacing": [
"error",
'callback-return': 'error',
'camelcase': 'error',
'capitalized-comments': 'off',
'class-methods-use-this': 'off',
'comma-dangle': 'error',
'comma-spacing': [
'error',
{
"after": true,
"before": false
'after': true,
'before': false
}
],
"comma-style": [
"error",
"last"
'comma-style': [
'error',
'last'
],
"complexity": "error",
"computed-property-spacing": [
"error",
"always"
'complexity': 'error',
'computed-property-spacing': [
'error',
'always'
],
"consistent-return": "error",
"consistent-this": "off",
"curly": "error",
"default-case": "error",
"dot-location": "error",
"dot-notation": "error",
"eol-last": "error",
"eqeqeq": "error",
"func-call-spacing": "error",
"func-name-matching": "error",
"func-names": "off",
"func-style": [
"error",
"expression"
'consistent-return': 'error',
'consistent-this': 'off',
'curly': 'error',
'default-case': 'error',
'dot-location': 'error',
'dot-notation': 'error',
'eol-last': 'error',
'eqeqeq': 'error',
'func-call-spacing': 'error',
'func-name-matching': 'error',
'func-names': 'off',
'func-style': [
'error',
'expression'
],
"function-paren-newline": "error",
"generator-star-spacing": "error",
"global-require": "error",
"guard-for-in": "error",
"handle-callback-err": "error",
"id-blacklist": "error",
"id-length": "off",
"id-match": "error",
"implicit-arrow-linebreak": "error",
"indent": "error",
"indent-legacy": "error",
"init-declarations": "off",
"jsx-quotes": "error",
"key-spacing": "off",
"keyword-spacing": [
"error",
'function-paren-newline': 'error',
'generator-star-spacing': 'error',
'global-require': 'error',
'guard-for-in': 'error',
'handle-callback-err': 'error',
'id-blacklist': 'error',
'id-length': 'off',
'id-match': 'error',
'implicit-arrow-linebreak': 'error',
'indent': 'error',
'indent-legacy': 'error',
'init-declarations': 'off',
'jsx-quotes': 'error',
'key-spacing': 'off',
'keyword-spacing': [
'error',
{
"after": true,
"before": true
'after': true,
'before': true
}
],
"line-comment-position": "off",
"linebreak-style": [
"error",
"unix"
'line-comment-position': 'off',
'linebreak-style': [
'error',
'unix'
],
"lines-around-comment": "error",
"lines-around-directive": "off",
"lines-between-class-members": "error",
"max-classes-per-file": "error",
"max-depth": "error",
"max-len": "off",
"max-lines": "error",
"max-lines-per-function": "off",
"max-nested-callbacks": "error",
"max-params": "error",
"max-statements": "off",
"max-statements-per-line": "off",
"multiline-comment-style": [
"error",
"separate-lines"
'lines-around-comment': 'error',
'lines-around-directive': 'off',
'lines-between-class-members': 'error',
'max-depth': 'error',
'max-len': 'off',
'max-lines': 'error',
'max-lines-per-function': 'off',
'max-nested-callbacks': 'error',
'max-params': 'error',
'max-statements': 'off',
'max-statements-per-line': 'off',
'multiline-comment-style': [
'error',
'separate-lines'
],
"new-cap": "error",
"new-parens": "error",
"newline-after-var": "off",
"newline-before-return": "off",
"newline-per-chained-call": "error",
"no-alert": "error",
"no-array-constructor": "error",
"no-async-promise-executor": "error",
"no-await-in-loop": "error",
"no-bitwise": "error",
"no-buffer-constructor": "error",
"no-caller": "error",
"no-catch-shadow": "error",
"no-confusing-arrow": "error",
"no-continue": "error",
"no-div-regex": "error",
"no-duplicate-imports": "error",
"no-else-return": "error",
"no-empty-function": "error",
"no-eq-null": "error",
"no-eval": "error",
"no-extend-native": "error",
"no-extra-bind": "error",
"no-extra-label": "error",
"no-extra-parens": "off",
"no-floating-decimal": "error",
"no-implicit-coercion": "error",
"no-implicit-globals": "error",
"no-implied-eval": "error",
"no-inline-comments": "off",
"no-inner-declarations": [
"error",
"functions"
'new-cap': 'error',
'new-parens': 'error',
'newline-after-var': 'off',
'newline-before-return': 'off',
'newline-per-chained-call': 'error',
'no-alert': 'error',
'no-array-constructor': 'error',
'no-async-promise-executor': 'error',
'no-await-in-loop': 'error',
'no-bitwise': 'error',
'no-buffer-constructor': 'error',
'no-caller': 'error',
'no-catch-shadow': 'error',
'no-confusing-arrow': 'error',
'no-continue': 'error',
'no-div-regex': 'error',
'no-duplicate-imports': 'error',
'no-else-return': 'error',
'no-empty-function': 'error',
'no-eq-null': 'error',
'no-eval': 'error',
'no-extend-native': 'error',
'no-extra-bind': 'error',
'no-extra-label': 'error',
'no-extra-parens': 'off',
'no-floating-decimal': 'error',
'no-implicit-coercion': 'error',
'no-implicit-globals': 'error',
'no-implied-eval': 'error',
'no-inline-comments': 'off',
'no-inner-declarations': [
'error',
'functions'
],
"no-invalid-this": "off",
"no-iterator": "error",
"no-label-var": "error",
"no-labels": "error",
"no-lone-blocks": "error",
"no-lonely-if": "error",
"no-loop-func": "error",
"no-magic-numbers": "off",
"no-misleading-character-class": "error",
"no-mixed-operators": "error",
"no-mixed-requires": "error",
"no-multi-assign": "error",
"no-multi-spaces": "off",
"no-multi-str": "error",
"no-multiple-empty-lines": "error",
"no-native-reassign": "error",
"no-negated-condition": "off",
"no-negated-in-lhs": "error",
"no-nested-ternary": "error",
"no-new": "error",
"no-new-func": "error",
"no-new-object": "error",
"no-new-require": "error",
"no-new-wrappers": "error",
"no-octal-escape": "error",
"no-param-reassign": "off",
"no-path-concat": "error",
"no-plusplus": "off",
"no-process-env": "error",
"no-process-exit": "error",
"no-proto": "error",
"no-prototype-builtins": "error",
"no-restricted-globals": "error",
"no-restricted-imports": "error",
"no-restricted-modules": "error",
"no-restricted-properties": "error",
"no-restricted-syntax": "error",
"no-return-assign": "error",
"no-return-await": "error",
"no-script-url": "error",
"no-self-compare": "error",
"no-sequences": "error",
"no-shadow": "off",
"no-shadow-restricted-names": "error",
"no-spaced-func": "error",
"no-sync": "error",
"no-tabs": "error",
"no-template-curly-in-string": "error",
"no-ternary": "off",
"no-throw-literal": "error",
"no-trailing-spaces": "error",
"no-undef-init": "error",
"no-undefined": "off",
"no-underscore-dangle": "error",
"no-unmodified-loop-condition": "error",
"no-unneeded-ternary": "error",
"no-unused-expressions": "error",
"no-use-before-define": "off",
"no-useless-call": "error",
"no-useless-catch": "error",
"no-useless-computed-key": "error",
"no-useless-concat": "error",
"no-useless-constructor": "error",
"no-useless-rename": "error",
"no-useless-return": "error",
"no-var": "off",
"no-void": "error",
"no-warning-comments": "error",
"no-whitespace-before-property": "error",
"no-with": "error",
"nonblock-statement-body-position": "error",
"object-curly-newline": "error",
"object-curly-spacing": [
"error",
"always"
'no-invalid-this': 'off',
'no-iterator': 'error',
'no-label-var': 'error',
'no-labels': 'error',
'no-lone-blocks': 'error',
'no-lonely-if': 'error',
'no-loop-func': 'error',
'no-magic-numbers': 'off',
'no-misleading-character-class': 'error',
'no-mixed-operators': 'error',
'no-mixed-requires': 'error',
'no-multi-assign': 'error',
'no-multi-spaces': 'off',
'no-multi-str': 'error',
'no-multiple-empty-lines': 'error',
'no-native-reassign': 'error',
'no-negated-condition': 'off',
'no-negated-in-lhs': 'error',
'no-nested-ternary': 'error',
'no-new': 'error',
'no-new-func': 'error',
'no-new-object': 'error',
'no-new-require': 'error',
'no-new-wrappers': 'error',
'no-octal-escape': 'error',
'no-param-reassign': 'off',
'no-path-concat': 'error',
'no-plusplus': 'off',
'no-process-env': 'error',
'no-process-exit': 'error',
'no-proto': 'error',
'no-prototype-builtins': 'error',
'no-restricted-globals': 'error',
'no-restricted-imports': 'error',
'no-restricted-modules': 'error',
'no-restricted-properties': 'error',
'no-restricted-syntax': 'error',
'no-return-assign': 'error',
'no-return-await': 'error',
'no-script-url': 'error',
'no-self-compare': 'error',
'no-sequences': 'error',
'no-shadow': 'off',
'no-shadow-restricted-names': 'error',
'no-spaced-func': 'error',
'no-sync': 'error',
'no-tabs': 'error',
'no-template-curly-in-string': 'error',
'no-ternary': 'off',
'no-throw-literal': 'error',
'no-trailing-spaces': 'error',
'no-undef-init': 'error',
'no-undefined': 'off',
'no-underscore-dangle': 'error',
'no-unmodified-loop-condition': 'error',
'no-unneeded-ternary': 'error',
'no-unused-expressions': 'error',
'no-use-before-define': 'off',
'no-useless-call': 'error',
'no-useless-catch': 'error',
'no-useless-computed-key': 'error',
'no-useless-concat': 'error',
'no-useless-constructor': 'error',
'no-useless-rename': 'error',
'no-useless-return': 'error',
'no-var': 'off',
'no-void': 'error',
'no-warning-comments': 'error',
'no-whitespace-before-property': 'error',
'no-with': 'error',
'nonblock-statement-body-position': 'error',
'object-curly-newline': 'error',
'object-curly-spacing': [
'error',
'always'
],
"object-shorthand": "off",
"one-var": "off",
"one-var-declaration-per-line": "off",
"operator-assignment": "error",
"operator-linebreak": "error",
"padded-blocks": "off",
"padding-line-between-statements": "error",
"prefer-arrow-callback": "off",
"prefer-const": "error",
"prefer-destructuring": "off",
"prefer-numeric-literals": "error",
"prefer-object-spread": "error",
"prefer-promise-reject-errors": "error",
"prefer-reflect": "off",
"prefer-rest-params": "off",
"prefer-spread": "error",
"prefer-template": "off",
"quote-props": "off",
"quotes": [
"error",
"double"
'object-shorthand': 'off',
'one-var': 'off',
'one-var-declaration-per-line': 'off',
'operator-assignment': 'error',
'operator-linebreak': 'error',
'padded-blocks': 'off',
'padding-line-between-statements': 'error',
'prefer-arrow-callback': 'off',
'prefer-const': 'error',
'prefer-destructuring': 'off',
'prefer-numeric-literals': 'error',
'prefer-object-spread': 'error',
'prefer-promise-reject-errors': 'error',
'prefer-reflect': 'off',
'prefer-rest-params': 'off',
'prefer-spread': 'error',
'prefer-template': 'off',
'quote-props': 'off',
'quotes': [
'error',
'single'
],
"radix": "error",
"require-atomic-updates": "error",
"require-await": "error",
"require-jsdoc": "error",
"require-unicode-regexp": "off",
"rest-spread-spacing": "error",
"semi": "error",
"semi-spacing": [
"error",
'radix': 'error',
'require-atomic-updates': 'error',
'require-await': 'error',
'require-jsdoc': 'error',
'require-unicode-regexp': 'off',
'rest-spread-spacing': 'error',
'semi': 'error',
'semi-spacing': [
'error',
{
"after": true,
"before": false
'after': true,
'before': false
}
],
"semi-style": [
"error",
"last"
'semi-style': [
'error',
'last'
],
"sort-imports": "error",
"sort-keys": "off",
"sort-vars": "off",
"space-before-blocks": "error",
"space-before-function-paren": "off",
"space-in-parens": [
"error",
"always"
'sort-imports': 'error',
'sort-keys': 'off',
'sort-vars': 'off',
'space-before-blocks': 'error',
'space-before-function-paren': 'off',
'space-in-parens': [
'error',
'always'
],
"space-infix-ops": "error",
"space-unary-ops": "error",
"spaced-comment": [
"error",
"always"
'space-infix-ops': 'error',
'space-unary-ops': 'error',
'spaced-comment': [
'error',
'always'
],
"strict": "error",
"switch-colon-spacing": "error",
"symbol-description": "error",
"template-curly-spacing": "error",
"template-tag-spacing": "error",
"unicode-bom": [
"error",
"never"
'strict': 'error',
'switch-colon-spacing': 'error',
'symbol-description': 'error',
'template-curly-spacing': 'error',
'template-tag-spacing': 'error',
'unicode-bom': [
'error',
'never'
],
"valid-jsdoc": "error",
"vars-on-top": "off",
"wrap-regex": "error",
"yield-star-spacing": "error",
"yoda": [
"error",
"never"
'valid-jsdoc': 'error',
'vars-on-top': 'off',
'wrap-regex': 'error',
'yield-star-spacing': 'error',
'yoda': [
'error',
'never'
]
}
};

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@
/node_modules
/npm-debug.log
/*.tgz
/built
# Files for editors and other tools
/.brackets.json

View File

@@ -1,5 +0,0 @@
{
"preset": "jquery",
// Since we check quotemarks already in jshint, this can be turned off
"validateQuoteMarks": false
}

View File

@@ -1,17 +0,0 @@
{
"globals": {
"module": true
},
"boss": true,
"browser": true,
"curly": true,
"esversion": 6,
"eqeqeq": true,
"eqnull": true,
"expr": true,
"immed": true,
"noarg": true,
"quotmark": "double",
"undef": true,
"unused": true
}

14
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,14 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "typescript",
"tsconfig": "tsconfig.json",
"problemMatcher": [
"$tsc"
],
"group": "build",
"label": "tsc: build - tsconfig.json"
}
]
}

View File

@@ -1,6 +1,6 @@
The MIT License (MIT)
Copyright (c) 2011-2016 Bartek Szopka
Copyright (c) 2011-2016 Bartek Szopka, 2016-2024 Henrik Ingo, 2024 Janis Hutz
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

214
README.md
View File

@@ -1,74 +1,128 @@
impress.js
============
<div id="title" align="center">
<img src="./logo.jpg" width="300">
<h1>impress.js</h1>
</div>
[![CircleCI](https://circleci.com/gh/impress/impress.js.svg?style=svg)](https://circleci.com/gh/impress/impress.js)
<div id="badges" align="center">
<img alt="Project License" src="https://img.shields.io/github/license/impress/impress.js.svg">
<img alt="GitHub Repo size" src="https://img.shields.io/github/repo-size/impress/impress.js.svg">
<img alt="GitHub Repo issues" src="https://img.shields.io/github/issues-pr-raw/impress/impress.js">
<a href="https://circleci.com/gh/impress/impress.js"><img alt="CircleCI" src="https://circleci.com/gh/impress/impress.js.svg?style=svg"></a>
<br>
<img alt="GitHub Repo stars" src="https://img.shields.io/github/stars/impress/impress.js">
<img alt="GitHub watchers" src="https://img.shields.io/github/watchers/impress/impress.js">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/impress/impress.js">
<br>
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/impress/impress.js/total?label=Downloads (total)">
<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/downloads/impress/impress.js/latest/total?label=Downloads (latest)">
<img alt="Latest release" src="https://img.shields.io/github/release/impress/impress.js.svg">
</div>
It's a presentation framework based on the power of CSS3 transforms and
transitions in modern browsers and inspired by the idea behind prezi.com.
impress.js is a presentation framework written in JavaScript that uses the power of CSS3 transitions and transforms. It is inspired by the idea behind prezi.com
**WARNING**
impress.js may not help you if you have nothing interesting to say ;)
HOW TO USE IT
---------------
### Getting Started Guide
Check out our new [Getting Started](GettingStarted.md) guide if you want a quick introduction to the project!
***THIS VERSION IS UNSTABLE AND INCOMPLETE. Please use the [upstream version](https://github.com/impress/impress.js) (V2.0.0)!***
### Direct download link to only impress.js
You can include this link directly inside of your HTML file in its header. If you want to learn how to do this, you can find a how-to in the [Getting Started](GettingStarted.md) guide.
- V2.0.0: https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js
- V1.1.0: https://cdn.jsdelivr.net/gh/impress/impress.js@1.1.0/js/impress.js
- Source: https://cdn.jsdelivr.net/gh/impress/impress.js/js/impress.js
We are switching to TS as the main impress development language, but you can still develop plugins in JS, if you wish!
### Checking out and initializing the git repository
# Getting Started with impress.js
Welcome to impress.js, the impressive JavaScript framework, that allows you to build presentations for web browsers.
## Browser support
Since impress.js is designed to show off the power of modern CSS, we cannot guarantee that it will run in older browser. Whilst we try not to intentionally break support for certain browsers, some features might not work well on all browsers, especially with V3.x. For example, Internet Explorer is known to not work with V3.x, so if you really NEED to use that browser, please use V2.x. impress.js works best with the latest versions of Chrome, Firefox and most likely also with the latest versions of Safari.
## Quick Start
You can visit our website at [https://impress.js.org](https://impress.js.org) to learn more about the project, where you can also find helpful resources for getting started, like the [Getting Started Guide](/docs/GettingStarted.md) and [Documentation](/docs/DOCUMENTATION.md), but rendered as HTML instead of MarkDown, as it is here on GitHub.
## A very quick "quick start"
Copy one of the code snippets below to the header of your impress.js presentation's HTML file.
- V3.0.0:
```
<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@3.0.0/dist/impress.min.js"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/impress/impress.js@3.0.0/dist/impress.min.css">
```
- V2.0.0:
```
<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js"/>
```
- V1.1.0:
```
<script src="https://cdn.jsdelivr.net/gh/impress/impress.js@1.1.0/js/impress.js"/>
```
- Upstream:
```
<script src="https://cdn.jsdelivr.net/gh/impress/impress.js/dist/impress.min.js"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/impress/impress.js/dist/impress.min.css">
```
We do not recommend using the Upstream version, as there might be breaking changes coming or features might be temporarily broken due to only partially finished feature updates. Whilst this shouldn't happen normally, please be aware of that risk when using Upstream.
### Using a self-hosted version of impress.js
You can download impress.js from the releases tab. Some older versions might not have the `impress.js` file in the releases, you will be required to extract it from the source code archive. You can find the file in the `js` folder. New versions include the `impress.js`, `impress.min.js`, `impress.css` and `impress.min.css` files in the assets.
# Documentation
You can find the entire documentation of impress.js on our [website](https://impress.js.org/docs) or in the [DOCUMENTATION.md](/docs/DOCUMENTATION.md) file
The [HTML source code](index.html) of the official [impress.js demo](https://impress.js.org/) serves as a good example usage and contains comments explaining various features of impress.js. For more information about styling you can look into [CSS code](css/impress-demo.css) which shows how classes provided by impress.js can be used. Last but not least [JavaScript code of impress.js](js/impress.js) has some useful comments if you are interested in how everything works. Feel free to explore!
# Official demo
[impress.js demo](https://impress.js.org/) by [@bartaz](https://twitter.com/bartaz)
## Examples and demos
The [Classic Slides](https://impress.js.org/examples/classic-slides/) demo is targeted towards beginners, or can be used as a template for presentations that look like the traditional PowerPoint slide deck. Over time, it also grew into the example presentation that uses most of the features and addons available.
More examples and demos can be found on [Examples and demos wiki page](https://github.com/impress/impress.js/wiki/Examples-and-demos).
Feel free to add your own example presentations (or websites) there.
## Other tutorials and learning resources
If you want to learn even more there is a [list of tutorials and other learning resources](https://github.com/impress/impress.js/wiki/impress.js-tutorials-and-other-learning-resources)
on the wiki, too.
There is also a book available about [Building impressive presentations with impress.js](https://www.packtpub.com/building-impressive-presentations-with-impressjs/book) by Rakhitha Nimesh Ratnayake.
You may want to check out the sibling project [Impressionist](https://github.com/henrikingo/impressionist): a 3D GUI editor that can help you in creating impress.js presentations.
## Mailing list
You're welcome to ask impress.js related questions on the [impressionist-presentations](https://groups.google.com/forum/#!forum/impressionist-presentations) mailing list.
TODO: We should migrate to a different kind of mailing list
# Contributing
## Cloning impress.js locally
git clone --recursive https://github.com/impress/impress.js.git
cd impress.js
Note: For a minimal checkout, omit the `--recursive` option. This will leave out extra plugins.
**Stable releases**
## Details
For developers, once you've made changes to the code, you should run these commands for testing:
New features and fixes are continuously merged into the master branch, which is what the above command will check out. For the latest stable release, see the [Github Releases page](https://github.com/impress/impress.js/releases).
npm install
npm run all
Note that running `firefox qunit_test_runner.html` is usually more informative than running `karma` with `npm run test`. They both run the same tests.
### Documentation
More info about the [src/](src/) directory can be found in [src/plugins/README.md](src/plugins/README.md).
## Requirements
TODO: Check that these requirements are still ok
* &gt;= node 7.6
* npm
Reference documentation of core impress.js features and API you can find it in [DOCUMENTATION.md](DOCUMENTATION.md).
The [HTML source code](index.html) of the official [impress.js demo](http://impress.github.io/impress.js/) serves as a good example usage and contains comments explaining various features of impress.js. For more information about styling you can look into [CSS code](css/impress-demo.css) which shows how classes provided by impress.js can be used. Last but not least [JavaScript code of impress.js](js/impress.js) has some useful comments if you are interested in how everything works. Feel free to explore!
### Official demo
[impress.js demo](http://impress.github.io/impress.js/) by [@bartaz](http://twitter.com/bartaz)
### Examples and demos
The [Classic Slides](http://impress.github.io/impress.js/examples/classic-slides/) demo is targeted towards beginners, or can be used as a template for presentations that look like the traditional PowerPoint slide deck. Over time, it also grew into the example presentation that uses most of the features and addons available.
More examples and demos can be found on [Examples and demos wiki page](http://github.com/impress/impress.js/wiki/Examples-and-demos).
Feel free to add your own example presentations (or websites) there.
### Other tutorials and learning resources
If you want to learn even more there is a [list of tutorials and other learning resources](https://github.com/impress/impress.js/wiki/impress.js-tutorials-and-other-learning-resources)
on the wiki, too.
There is also a book available about [Building impressive presentations with impress.js](http://www.packtpub.com/building-impressive-presentations-with-impressjs/book) by Rakhitha Nimesh Ratnayake.
You may want to check out the sibling project [Impressionist](https://github.com/henrikingo/impressionist): a 3D GUI editor that can help you in creating impress.js presentations.
### Mailing list
You're welcome to ask impress.js related questions on the [impressionist-presentations](https://groups.google.com/forum/#!forum/impressionist-presentations) mailing list.
REPOSITORY STRUCTURE
--------------------
# REPOSITORY STRUCTURE
* [index.html](index.html): This is the official impress.js demo, showcasing all of the features of the original impress.js, as well as some new plugins as we add them.
* As already mentioned, this file is well commented and acts as the official tutorial.
@@ -83,53 +137,35 @@ REPOSITORY STRUCTURE
* [build.js](build.js): Simple build file that creates `js/impress.js`. It also creates a minified version `impress.min.js`, but that one is not included in the github repository.
* [package.json](build.js): An NPM package specification. This was mainly added so you can easily install [buildify](https://www.npmjs.com/package/buildify) and run `node build.js`. Other than the build process, which is really just doing roughly `cat src/impress.js src/plugins/*/*.js > js/impress.js`, and testing, `impress.js` itself doesn't depend on Node or any NPM modules.
WANT TO CONTRIBUTE?
---------------------
TODO: Update repo structure once updating is complete
For developers, once you've made changes to the code, you should run these commands for testing:
# About impress.js
## ABOUT THE NAME
npm install
npm run all
impress.js name is [courtesy of @skuzniak](https://twitter.com/skuzniak/status/143627215165333504).
Note that running `firefox qunit_test_runner.html` is usually more informative than running `karma` with `npm run test`. They both run the same tests.
It's an (un)fortunate coincidence that an Open/LibreOffice presentation tool is called Impress ;)
More info about the [src/](src/) directory can be found in [src/plugins/README.md](src/plugins/README.md).
## Reference API
### Requirements
See the [Reference API](/docs/DOCUMENTATION.md)
* &gt;= node 7.6
* npm
TODO: Will be updated once full release of V3 is ready
## Browser support (again, but for devs)
impress.js uses the following CSS and JavaScript features
TODO: Update list below
* [DataSet API](https://caniuse.com/#search=dataset)
* [ClassList API](https://caniuse.com/#search=classlist)
* [CSS 3D Transforms](https://caniuse.com/#search=css%203d)
* [CSS Transitions](https://caniuse.com/#search=css%20transition)
ABOUT THE NAME
----------------
# Copyright and License
impress.js name is [courtesy of @skuzniak](http://twitter.com/skuzniak/status/143627215165333504).
It's an (un)fortunate coincidence that a Open/LibreOffice presentation tool is called Impress ;)
Reference API
--------------
See the [Reference API](DOCUMENTATION.md)
BROWSER SUPPORT
-----------------
The design goal for impress.js has been to showcase awesome CSS3 features as found in modern browser versions. We also use some new DOM functionality, and specifically do not use jQuery or any other JavaScript libraries, nor our own functions, to support older browsers. In general, recent versions of Firefox and Chrome are known to work well. Reportedly IE now works too.
The typical use case for impress.js is to create presentations that you present from your own laptop, with a browser version you know works well. Some people also use impress.js successfully to embed animations or presentations in a web page, however, be aware that in this some of your visitors may not see the presentation correctly, or at all.
In particular, impress.js makes use of the following JS and CSS features:
* [DataSet API](http://caniuse.com/#search=dataset)
* [ClassList API](http://caniuse.com/#search=classlist)
* [CSS 3D Transforms](http://caniuse.com/#search=css%203d)
* [CSS Transitions](http://caniuse.com/#search=css%20transition)
COPYRIGHT AND LICENSE
---------------------
Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-2023 Henrik Ingo (@henrikingo) and [70+ other contributors](https://github.com/impress/impress.js/graphs/contributors)
Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-2023 Henrik Ingo (@henrikingo) and [85+ other contributors](https://github.com/impress/impress.js/graphs/contributors)
Released under the MIT [License](LICENSE)

View File

@@ -1,75 +0,0 @@
const fs = require('fs');
var ls = require('ls');
var path = require('path');
var Terser = require("terser");
var files = ['src/impress.js'];
// Libraries from src/lib
files.push('src/lib/gc.js', 'src/lib/util.js', 'src/lib/rotation.js')
// Plugins from src/plugins
files.push('src/plugins/autoplay/autoplay.js',
'src/plugins/blackout/blackout.js',
'src/plugins/extras/extras.js',
'src/plugins/form/form.js',
'src/plugins/fullscreen/fullscreen.js',
'src/plugins/goto/goto.js',
'src/plugins/bookmark/bookmark.js',
'src/plugins/help/help.js',
'src/plugins/impressConsole/impressConsole.js',
'src/plugins/media/media.js',
'src/plugins/mobile/mobile.js',
'src/plugins/mouse-timeout/mouse-timeout.js',
'src/plugins/navigation/navigation.js',
'src/plugins/navigation-ui/navigation-ui.js',
'src/plugins/progress/progress.js',
'src/plugins/rel/rel.js',
'src/plugins/resize/resize.js',
'src/plugins/skip/skip.js',
'src/plugins/stop/stop.js',
'src/plugins/substep/substep.js',
'src/plugins/touch/touch.js',
'src/plugins/toolbar/toolbar.js')
var output = files.map((f)=>{
return fs.readFileSync(f).toString();
}).join('\n')
var filename = 'js/impress.js';
fs.writeFileSync(filename, '// This file was automatically generated from files in src/ directory.\n\n' + output)
console.log(filename);
// terser --compress --mangle --comments '/^!/' --source-map --output js/impress.min.js js/impress.js
var code = fs.readFileSync('js/impress.js').toString();
var options = {
sourceMap: {
filename: 'js/impress.js',
url: 'js/impress.min.js.map'
},
output: {
comments: /^!/
}
};
var result = Terser.minify({'js/impress.js': code}, options);
filename = 'js/impress.min.js';
fs.writeFileSync(filename, result.code);
console.log(filename);
filename = 'js/impress.min.js.map';
fs.writeFileSync(filename, result.map);
console.log(filename);
/* Auto generate an index.html that lists all the directories under examples/
* This is useful for gh-pages, so you can link to http://impress.github.io/impress.js/examples
*/
var html_list = '<ul><br />\n'
ls( 'examples/*', { type: 'dir' }).forEach(function(dir) {
html_list += ' <li><a href="' + dir['file'] + '/">' + dir['name'] + '</a></li>\n';
});
html_list += '</ul>\n'
var html = '<html>\n<head>\n<title>Example presentations</title>\n</head>\n<body>'
html += '<h1>Example presentations</h1>\n' + html_list
html += '</body>\n</html>'
filename = path.resolve(__dirname, 'examples', 'index.html');
fs.writeFileSync(filename, html);
console.log(filename);

View File

@@ -50,7 +50,7 @@ Now, create a new file called *index.html* and create the basic HTML structure:
</html>
```
Now, head into a file-manager, navigate to the file you just created (*index.html*) and open it. You should end up in a browser where you should see "My first Slide" plus (in case you omitted the *impress-common.css* file) the fallback message displayed. As this is not really exciting, we are not gonna change anything about that and are gonna look at what you just typed. What do these lines mean?
Now, head into a file-manager, navigate to the file you just created (*index.html*) and open it. You should end up in a browser where you should see "My first Slide" displayed. As this is not really exciting, we are not gonna change anything about that and are gonna look at what you just typed. What do these lines mean?
Well, first things first, you should probably give your presentation a title. You may do this in normal HTML fashion by changing the *title* HTML tag.
@@ -62,23 +62,7 @@ Finally, we load the ```impress.js``` script from your local copy (if you have o
```
impress().init()
```
to initialize impress.js.
If you have omitted the *impress-common.css* file, you might want to hide the fallback message. This can be done by creating a CSS file called *style.css* in the same folder you've created the *index.html* file in. In the *index.html* add the following line inside of the *<head>* tag:
```
<link rel="stylesheet" href="style.css">
```
This will load the *style.css* file in the HTML.
Now open up the *style.css* file using any text editor. To hide the fallback message, you should add the following lines to the CSS file:
```
.impress-supported .fallback-message {
display: none;
}
```
Now, let's continue on to explore more and more features of this amazing tool!
to initialize impress.js. Now, let's continue on to explore more and more features of this amazing tool!
## Creating slides
Creating slides is fairly easy. You create a *div* that belongs to the class ```step``` and you are off to the races! Let me give you an example:

2
docs/core/addElements.md Normal file
View File

@@ -0,0 +1,2 @@
# Adding Elements to impress
You can add elements to impress by calling the `impress.addElement` function.

BIN
logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

8934
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "impress.js",
"version": "1.1.0",
"version": "3.0.0",
"description": "It's a presentation framework based on the power of CSS3 transforms and transitions in modern browsers and inspired by the idea behind prezi.com.",
"main": "js/impress.js",
"repository": {
@@ -24,15 +24,16 @@
"scripts": {
"all": "npm run build && npm run test && npm run lint",
"build": "node build.js",
"lint": "npm exec -- jshint src test/*.js && npm exec -- jscs src test/*.js",
"new-lint": "npm exec -- eslint src test",
"lint": "npm exec -- eslint src test",
"test": "npm exec -- karma start --log-level debug --single-run=true"
},
"devDependencies": {
"eslint": "^6.8.0",
"jscs": "^3.0.7",
"@typescript-eslint/eslint-plugin": "^6.18.0",
"@typescript-eslint/parser": "^6.18.0",
"eslint": "^8.56.0",
"jscs": "^2.1.1",
"jshint": "^2.11.0",
"karma": "^4.4.1",
"karma": "^6.4.2",
"karma-chrome-launcher": "^3.1.0",
"karma-firefox-launcher": "^1.3.0",
"karma-qunit": "^4.0.0",
@@ -41,6 +42,7 @@
"qunit": "^2.9.3",
"qunit-assert-close": "^2.1.2",
"syn": "^0.14.1",
"terser": "^4.6.7"
"terser": "^4.6.7",
"typescript": "^5.3.3"
}
}

75
src/build.js Normal file
View File

@@ -0,0 +1,75 @@
const fs = require( 'fs' );
var ls = require( 'ls' );
var path = require( 'path' );
var Terser = require( 'terser' );
var files = ['src/impress.js'];
// Libraries from src/lib
files.push( 'src/lib/gc.js', 'src/lib/util.js', 'src/lib/rotation.js' );
// Plugins from src/plugins
files.push(
'src/plugins/autoplay/autoplay.js',
'src/plugins/blackout/blackout.js',
'src/plugins/extras/extras.js',
'src/plugins/form/form.js',
'src/plugins/fullscreen/fullscreen.js',
'src/plugins/goto/goto.js',
'src/plugins/bookmark/bookmark.js',
'src/plugins/help/help.js',
'src/plugins/impressConsole/impressConsole.js',
'src/plugins/media/media.js',
'src/plugins/mobile/mobile.js',
'src/plugins/mouse-timeout/mouse-timeout.js',
'src/plugins/navigation/navigation.js',
'src/plugins/navigation-ui/navigation-ui.js',
'src/plugins/progress/progress.js',
'src/plugins/rel/rel.js',
'src/plugins/resize/resize.js',
'src/plugins/skip/skip.js',
'src/plugins/stop/stop.js',
'src/plugins/substep/substep.js',
'src/plugins/touch/touch.js',
'src/plugins/toolbar/toolbar.js'
);
var output = files.map( ( f ) => fs.readFileSync( f ).toString() ).join( '\n' );
var filename = 'js/impress.js';
fs.writeFileSync( filename, '// This file was automatically generated from files in src/ directory.\n\n' + output );
console.log( filename );
// terser --compress --mangle --comments '/^!/' --source-map --output js/impress.min.js js/impress.js
var code = fs.readFileSync( 'js/impress.js' ).toString();
var options = {
sourceMap: {
filename: 'js/impress.js',
url: 'js/impress.min.js.map'
},
output: {
comments: /^!/
}
};
var result = Terser.minify( { 'js/impress.js': code }, options );
filename = 'js/impress.min.js';
fs.writeFileSync( filename, result.code );
console.log( filename );
filename = 'js/impress.min.js.map';
fs.writeFileSync( filename, result.map );
console.log( filename );
// Auto generate an index.html that lists all the directories under examples/
// This is useful for gh-pages, so you can link to http://impress.github.io/impress.js/examples
//
var html_list = '<ul><br />\n';
ls( 'examples/*', { type: 'dir' } ).forEach( function( dir ) {
html_list += ' <li><a href="' + dir.file + '/">' + dir.name + '</a></li>\n';
} );
html_list += '</ul>\n';
var html = '<html>\n<head>\n<title>Example presentations</title>\n</head>\n<body>';
html += '<h1>Example presentations</h1>\n' + html_list;
html += '</body>\n</html>';
filename = path.resolve( __dirname, 'examples', 'index.html' );
fs.writeFileSync( filename, html );
console.log( filename );

File diff suppressed because it is too large Load Diff

925
src/impress.old.js Normal file
View File

@@ -0,0 +1,925 @@
/*! Licensed under MIT License - http://github.com/impress/impress.js */
/**
* impress.js
*
* impress.js is a presentation tool based on the power of CSS3 transforms and transitions
* in modern browsers and inspired by the idea behind prezi.com.
*
*
* Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-2023 Henrik Ingo (@henrikingo)
* and 70+ other contributors
*
* Released under the MIT License.
*
* ------------------------------------------------
* author: Bartek Szopka, Henrik Ingo
* version: 2.0.0
* url: http://impress.js.org
* source: http://github.com/impress/impress.js/
*/
// You are one of those who like to know how things work inside?
// Let me show you the cogs that make impress.js run...
( function( document, window ) {
"use strict";
var lib;
// HELPER FUNCTIONS
// `pfx` is a function that takes a standard CSS property name as a parameter
// and returns it's prefixed version valid for current browser it runs in.
// The code is heavily inspired by Modernizr http://www.modernizr.com/
var pfx = ( function() {
var style = document.createElement( "dummy" ).style,
prefixes = "Webkit Moz O ms Khtml".split( " " ),
memory = {};
return function( prop ) {
if ( typeof memory[ prop ] === "undefined" ) {
var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
props = ( prop + " " + prefixes.join( ucProp + " " ) + ucProp ).split( " " );
memory[ prop ] = null;
for ( var i in props ) {
if ( style[ props[ i ] ] !== undefined ) {
memory[ prop ] = props[ i ];
break;
}
}
}
return memory[ prop ];
};
} )();
var validateOrder = function( order, fallback ) {
var validChars = "xyz";
var returnStr = "";
if ( typeof order === "string" ) {
for ( var i in order.split( "" ) ) {
if ( validChars.indexOf( order[ i ] ) >= 0 ) {
returnStr += order[ i ];
// Each of x,y,z can be used only once.
validChars = validChars.split( order[ i ] ).join( "" );
}
}
}
if ( returnStr ) {
return returnStr;
} else if ( fallback !== undefined ) {
return fallback;
} else {
return "xyz";
}
};
// `css` function applies the styles given in `props` object to the element
// given as `el`. It runs all property names through `pfx` function to make
// sure proper prefixed version of the property is used.
var css = function( el, props ) {
var key, pkey;
for ( key in props ) {
if ( props.hasOwnProperty( key ) ) {
pkey = pfx( key );
if ( pkey !== null ) {
el.style[ pkey ] = props[ key ];
}
}
}
return el;
};
// `translate` builds a translate transform string for given data.
var translate = function( t ) {
return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
};
// `rotate` builds a rotate transform string for given data.
// By default the rotations are in X Y Z order that can be reverted by passing `true`
// as second parameter.
var rotate = function( r, revert ) {
var order = r.order ? r.order : "xyz";
var css = "";
var axes = order.split( "" );
if ( revert ) {
axes = axes.reverse();
}
for ( var i = 0; i < axes.length; i++ ) {
css += " rotate" + axes[ i ].toUpperCase() + "(" + r[ axes[ i ] ] + "deg)";
}
return css;
};
// `scale` builds a scale transform string for given data.
var scale = function( s ) {
return " scale(" + s + ") ";
};
// `computeWindowScale` counts the scale factor between window size and size
// defined for the presentation in the config.
var computeWindowScale = function( config ) {
var hScale = window.innerHeight / config.height,
wScale = window.innerWidth / config.width,
scale = hScale > wScale ? wScale : hScale;
if ( config.maxScale && scale > config.maxScale ) {
scale = config.maxScale;
}
if ( config.minScale && scale < config.minScale ) {
scale = config.minScale;
}
return scale;
};
// CHECK SUPPORT
var body = document.body;
var impressSupported =
// Browser should support CSS 3D transtorms
( pfx( "perspective" ) !== null ) &&
// And `classList` and `dataset` APIs
( body.classList ) &&
( body.dataset );
if ( !impressSupported ) {
// We can't be sure that `classList` is supported
body.className += " impress-not-supported ";
}
// GLOBALS AND DEFAULTS
// This is where the root elements of all impress.js instances will be kept.
// Yes, this means you can have more than one instance on a page, but I'm not
// sure if it makes any sense in practice ;)
var roots = {};
var preInitPlugins = [];
var preStepLeavePlugins = [];
// Some default config values.
var defaults = {
width: 1920,
height: 1080,
maxScale: 3,
minScale: 0,
perspective: 1000,
transitionDuration: 1000
};
// Configuration options
var config = null;
// It's just an empty function ... and a useless comment.
var empty = function() { return false; };
// IMPRESS.JS API
// And that's where interesting things will start to happen.
// It's the core `impress` function that returns the impress.js API
// for a presentation based on the element with given id ("impress"
// by default).
var impress = window.impress = function( rootId ) {
// If impress.js is not supported by the browser return a dummy API
// it may not be a perfect solution but we return early and avoid
// running code that may use features not implemented in the browser.
if ( !impressSupported ) {
return {
init: empty,
goto: empty,
prev: empty,
next: empty,
swipe: empty,
tear: empty,
lib: {}
};
}
rootId = rootId || "impress";
// If given root is already initialized just return the API
if ( roots[ "impress-root-" + rootId ] ) {
return roots[ "impress-root-" + rootId ];
}
// The gc library depends on being initialized before we do any changes to DOM.
lib = initLibraries( rootId );
body.classList.remove( "impress-not-supported" );
body.classList.add( "impress-supported" );
// Data of all presentation steps
var stepsData = {};
// Element of currently active step
var activeStep = null;
// Current state (position, rotation and scale) of the presentation
var currentState = null;
// Array of step elements
var steps = null;
// Scale factor of the browser window
var windowScale = null;
// Root presentation elements
var root = lib.util.byId( rootId );
var canvas = document.createElement( "div" );
var initialized = false;
// STEP EVENTS
//
// There are currently two step events triggered by impress.js
// `impress:stepenter` is triggered when the step is shown on the
// screen (the transition from the previous one is finished) and
// `impress:stepleave` is triggered when the step is left (the
// transition to next step just starts).
// Reference to last entered step
var lastEntered = null;
// `onStepEnter` is called whenever the step element is entered
// but the event is triggered only if the step is different than
// last entered step.
// We sometimes call `goto`, and therefore `onStepEnter`, just to redraw a step, such as
// after screen resize. In this case - more precisely, in any case - we trigger a
// `impress:steprefresh` event.
var onStepEnter = function( step ) {
if ( lastEntered !== step ) {
lib.util.triggerEvent( step, "impress:stepenter" );
lastEntered = step;
}
lib.util.triggerEvent( step, "impress:steprefresh" );
};
// `onStepLeave` is called whenever the currentStep element is left
// but the event is triggered only if the currentStep is the same as
// lastEntered step.
var onStepLeave = function( currentStep, nextStep ) {
if ( lastEntered === currentStep ) {
lib.util.triggerEvent( currentStep, "impress:stepleave", { next: nextStep } );
lastEntered = null;
}
};
// `initStep` initializes given step element by reading data from its
// data attributes and setting correct styles.
var initStep = function( el, idx ) {
var data = el.dataset,
step = {
translate: {
x: lib.util.toNumberAdvanced( data.x ),
y: lib.util.toNumberAdvanced( data.y ),
z: lib.util.toNumberAdvanced( data.z )
},
rotate: {
x: lib.util.toNumber( data.rotateX ),
y: lib.util.toNumber( data.rotateY ),
z: lib.util.toNumber( data.rotateZ || data.rotate ),
order: validateOrder( data.rotateOrder )
},
scale: lib.util.toNumber( data.scale, 1 ),
transitionDuration: lib.util.toNumber(
data.transitionDuration, config.transitionDuration
),
el: el
};
if ( !el.id ) {
el.id = "step-" + ( idx + 1 );
}
stepsData[ "impress-" + el.id ] = step;
css( el, {
position: "absolute",
transform: "translate(-50%,-50%)" +
translate( step.translate ) +
rotate( step.rotate ) +
scale( step.scale ),
transformStyle: "preserve-3d"
} );
};
// Initialize all steps.
// Read the data-* attributes, store in internal stepsData, and render with CSS.
var initAllSteps = function() {
steps = lib.util.$$( ".step", root );
steps.forEach( initStep );
};
// Build configuration from root and defaults
var buildConfig = function() {
var rootData = root.dataset;
return {
width: lib.util.toNumber( rootData.width, defaults.width ),
height: lib.util.toNumber( rootData.height, defaults.height ),
maxScale: lib.util.toNumber( rootData.maxScale, defaults.maxScale ),
minScale: lib.util.toNumber( rootData.minScale, defaults.minScale ),
perspective: lib.util.toNumber( rootData.perspective, defaults.perspective ),
transitionDuration: lib.util.toNumber(
rootData.transitionDuration, defaults.transitionDuration
)
};
};
// `init` API function that initializes (and runs) the presentation.
var init = function() {
if ( initialized ) { return; }
// Initialize the configuration object, so it can be used by pre-init plugins.
config = buildConfig();
execPreInitPlugins( root );
// First we set up the viewport for mobile devices.
// For some reason iPad goes nuts when it is not done properly.
var meta = lib.util.$( "meta[name='viewport']" ) || document.createElement( "meta" );
meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no";
if ( meta.parentNode !== document.head ) {
meta.name = "viewport";
document.head.appendChild( meta );
}
windowScale = computeWindowScale( config );
// Wrap steps with "canvas" element
lib.util.arrayify( root.childNodes ).forEach( function( el ) {
canvas.appendChild( el );
} );
root.appendChild( canvas );
// Set initial styles
document.documentElement.style.height = "100%";
css( body, {
height: "100%",
overflow: "hidden"
} );
var rootStyles = {
position: "absolute",
transformOrigin: "top left",
transition: "all 0s ease-in-out",
transformStyle: "preserve-3d"
};
css( root, rootStyles );
css( root, {
top: "50%",
left: "50%",
perspective: ( config.perspective / windowScale ) + "px",
transform: scale( windowScale )
} );
css( canvas, rootStyles );
body.classList.remove( "impress-disabled" );
body.classList.add( "impress-enabled" );
// Get and init steps
initAllSteps();
// Set a default initial state of the canvas
currentState = {
translate: { x: 0, y: 0, z: 0 },
rotate: { x: 0, y: 0, z: 0, order: "xyz" },
scale: 1
};
initialized = true;
lib.util.triggerEvent( root, "impress:init",
{ api: roots[ "impress-root-" + rootId ] } );
};
// `getStep` is a helper function that returns a step element defined by parameter.
// If a number is given, step with index given by the number is returned, if a string
// is given step element with such id is returned, if DOM element is given it is returned
// if it is a correct step element.
var getStep = function( step ) {
if ( typeof step === "number" ) {
step = step < 0 ? steps[ steps.length + step ] : steps[ step ];
} else if ( typeof step === "string" ) {
step = lib.util.byId( step );
}
return ( step && step.id && stepsData[ "impress-" + step.id ] ) ? step : null;
};
// Used to reset timeout for `impress:stepenter` event
var stepEnterTimeout = null;
// `goto` API function that moves to step given as `el` parameter (by index, id or element).
// `duration` optionally given as second parameter, is the transition duration in css.
// `reason` is the string "next", "prev" or "goto" (default) and will be made available to
// preStepLeave plugins.
// `origEvent` may contain event that caused the call to goto, such as a key press event
var goto = function( el, duration, reason, origEvent ) {
reason = reason || "goto";
origEvent = origEvent || null;
if ( !initialized ) {
return false;
}
// Re-execute initAllSteps for each transition. This allows to edit step attributes
// dynamically, such as change their coordinates, or even remove or add steps, and have
// that change apply when goto() is called.
initAllSteps();
if ( !( el = getStep( el ) ) ) {
return false;
}
// Sometimes it's possible to trigger focus on first link with some keyboard action.
// Browser in such a case tries to scroll the page to make this element visible
// (even that body overflow is set to hidden) and it breaks our careful positioning.
//
// So, as a lousy (and lazy) workaround we will make the page scroll back to the top
// whenever slide is selected
//
// If you are reading this and know any better way to handle it, I'll be glad to hear
// about it!
window.scrollTo( 0, 0 );
var step = stepsData[ "impress-" + el.id ];
duration = ( duration !== undefined ? duration : step.transitionDuration );
// If we are in fact moving to another step, start with executing the registered
// preStepLeave plugins.
if ( activeStep && activeStep !== el ) {
var event = { target: activeStep, detail: {} };
event.detail.next = el;
event.detail.transitionDuration = duration;
event.detail.reason = reason;
if ( origEvent ) {
event.origEvent = origEvent;
}
if ( execPreStepLeavePlugins( event ) === false ) {
// PreStepLeave plugins are allowed to abort the transition altogether, by
// returning false.
// see stop and substep plugins for an example of doing just that
return false;
}
// Plugins are allowed to change the detail values
el = event.detail.next;
step = stepsData[ "impress-" + el.id ];
duration = event.detail.transitionDuration;
}
if ( activeStep ) {
activeStep.classList.remove( "active" );
body.classList.remove( "impress-on-" + activeStep.id );
}
el.classList.add( "active" );
body.classList.add( "impress-on-" + el.id );
// Compute target state of the canvas based on given step
var target = {
rotate: {
x: -step.rotate.x,
y: -step.rotate.y,
z: -step.rotate.z,
order: step.rotate.order
},
translate: {
x: -step.translate.x,
y: -step.translate.y,
z: -step.translate.z
},
scale: 1 / step.scale
};
// Check if the transition is zooming in or not.
//
// This information is used to alter the transition style:
// when we are zooming in - we start with move and rotate transition
// and the scaling is delayed, but when we are zooming out we start
// with scaling down and move and rotation are delayed.
var zoomin = target.scale >= currentState.scale;
duration = lib.util.toNumber( duration, config.transitionDuration );
var delay = ( duration / 2 );
// If the same step is re-selected, force computing window scaling,
// because it is likely to be caused by window resize
if ( el === activeStep ) {
windowScale = computeWindowScale( config );
}
var targetScale = target.scale * windowScale;
// Trigger leave of currently active element (if it's not the same step again)
if ( activeStep && activeStep !== el ) {
onStepLeave( activeStep, el );
}
// Now we alter transforms of `root` and `canvas` to trigger transitions.
//
// And here is why there are two elements: `root` and `canvas` - they are
// being animated separately:
// `root` is used for scaling and `canvas` for translate and rotations.
// Transitions on them are triggered with different delays (to make
// visually nice and "natural" looking transitions), so we need to know
// that both of them are finished.
css( root, {
// To keep the perspective look similar for different scales
// we need to "scale" the perspective, too
// For IE 11 support we must specify perspective independent
// of transform.
perspective: ( config.perspective / targetScale ) + "px",
transform: scale( targetScale ),
transitionDuration: duration + "ms",
transitionDelay: ( zoomin ? delay : 0 ) + "ms"
} );
css( canvas, {
transform: rotate( target.rotate, true ) + translate( target.translate ),
transitionDuration: duration + "ms",
transitionDelay: ( zoomin ? 0 : delay ) + "ms"
} );
// Here is a tricky part...
//
// If there is no change in scale or no change in rotation and translation, it means
// there was actually no delay - because there was no transition on `root` or `canvas`
// elements. We want to trigger `impress:stepenter` event in the correct moment, so
// here we compare the current and target values to check if delay should be taken into
// account.
//
// I know that this `if` statement looks scary, but it's pretty simple when you know
// what is going on - it's simply comparing all the values.
if ( currentState.scale === target.scale ||
( currentState.rotate.x === target.rotate.x &&
currentState.rotate.y === target.rotate.y &&
currentState.rotate.z === target.rotate.z &&
currentState.translate.x === target.translate.x &&
currentState.translate.y === target.translate.y &&
currentState.translate.z === target.translate.z ) ) {
delay = 0;
}
// Store current state
currentState = target;
activeStep = el;
// And here is where we trigger `impress:stepenter` event.
// We simply set up a timeout to fire it taking transition duration (and possible delay)
// into account.
//
// I really wanted to make it in more elegant way. The `transitionend` event seemed to
// be the best way to do it, but the fact that I'm using transitions on two separate
// elements and that the `transitionend` event is only triggered when there was a
// transition (change in the values) caused some bugs and made the code really
// complicated, cause I had to handle all the conditions separately. And it still
// needed a `setTimeout` fallback for the situations when there is no transition at all.
// So I decided that I'd rather make the code simpler than use shiny new
// `transitionend`.
//
// If you want learn something interesting and see how it was done with `transitionend`
// go back to version 0.5.2 of impress.js:
// http://github.com/bartaz/impress.js/blob/0.5.2/js/impress.js
window.clearTimeout( stepEnterTimeout );
stepEnterTimeout = window.setTimeout( function() {
onStepEnter( activeStep );
}, duration + delay );
return el;
};
// `prev` API function goes to previous step (in document order)
// `event` is optional, may contain the event that caused the need to call prev()
var prev = function( origEvent ) {
var prev = steps.indexOf( activeStep ) - 1;
prev = prev >= 0 ? steps[ prev ] : steps[ steps.length - 1 ];
return goto( prev, undefined, "prev", origEvent );
};
// `next` API function goes to next step (in document order)
// `event` is optional, may contain the event that caused the need to call next()
var next = function( origEvent ) {
var next = steps.indexOf( activeStep ) + 1;
next = next < steps.length ? steps[ next ] : steps[ 0 ];
return goto( next, undefined, "next", origEvent );
};
// Swipe for touch devices by @and3rson.
// Below we extend the api to control the animation between the currently
// active step and a presumed next/prev step. See touch plugin for
// an example of using this api.
// Helper function
var interpolate = function( a, b, k ) {
return a + ( b - a ) * k;
};
// Animate a swipe.
//
// Pct is a value between -1.0 and +1.0, designating the current length
// of the swipe.
//
// If pct is negative, swipe towards the next() step, if positive,
// towards the prev() step.
//
// Note that pre-stepleave plugins such as goto can mess with what is a
// next() and prev() step, so we need to trigger the pre-stepleave event
// here, even if a swipe doesn't guarantee that the transition will
// actually happen.
//
// Calling swipe(), with any value of pct, won't in itself cause a
// transition to happen, this is just to animate the swipe. Once the
// transition is committed - such as at a touchend event - caller is
// responsible for also calling prev()/next() as appropriate.
//
// Note: For now, this function is made available to be used by the swipe plugin (which
// is the UI counterpart to this). It is a semi-internal API and intentionally not
// documented in DOCUMENTATION.md.
var swipe = function( pct ) {
if ( Math.abs( pct ) > 1 ) {
return;
}
// Prepare & execute the preStepLeave event
var event = { target: activeStep, detail: {} };
event.detail.swipe = pct;
// Will be ignored within swipe animation, but just in case a plugin wants to read this,
// humor them
event.detail.transitionDuration = config.transitionDuration;
var idx; // Needed by jshint
if ( pct < 0 ) {
idx = steps.indexOf( activeStep ) + 1;
event.detail.next = idx < steps.length ? steps[ idx ] : steps[ 0 ];
event.detail.reason = "next";
} else if ( pct > 0 ) {
idx = steps.indexOf( activeStep ) - 1;
event.detail.next = idx >= 0 ? steps[ idx ] : steps[ steps.length - 1 ];
event.detail.reason = "prev";
} else {
// No move
return;
}
if ( execPreStepLeavePlugins( event ) === false ) {
// If a preStepLeave plugin wants to abort the transition, don't animate a swipe
// For stop, this is probably ok. For substep, the plugin it self might want to do
// some animation, but that's not the current implementation.
return false;
}
var nextElement = event.detail.next;
var nextStep = stepsData[ "impress-" + nextElement.id ];
// If the same step is re-selected, force computing window scaling,
var nextScale = nextStep.scale * windowScale;
var k = Math.abs( pct );
var interpolatedStep = {
translate: {
x: interpolate( currentState.translate.x, -nextStep.translate.x, k ),
y: interpolate( currentState.translate.y, -nextStep.translate.y, k ),
z: interpolate( currentState.translate.z, -nextStep.translate.z, k )
},
rotate: {
x: interpolate( currentState.rotate.x, -nextStep.rotate.x, k ),
y: interpolate( currentState.rotate.y, -nextStep.rotate.y, k ),
z: interpolate( currentState.rotate.z, -nextStep.rotate.z, k ),
// Unfortunately there's a discontinuity if rotation order changes. Nothing I
// can do about it?
order: k < 0.7 ? currentState.rotate.order : nextStep.rotate.order
},
scale: interpolate( currentState.scale * windowScale, nextScale, k )
};
css( root, {
// To keep the perspective look similar for different scales
// we need to 'scale' the perspective, too
perspective: config.perspective / interpolatedStep.scale + "px",
transform: scale( interpolatedStep.scale ),
transitionDuration: "0ms",
transitionDelay: "0ms"
} );
css( canvas, {
transform: rotate( interpolatedStep.rotate, true ) +
translate( interpolatedStep.translate ),
transitionDuration: "0ms",
transitionDelay: "0ms"
} );
};
// Teardown impress
// Resets the DOM to the state it was before impress().init() was called.
// (If you called impress(rootId).init() for multiple different rootId's, then you must
// also call tear() once for each of them.)
var tear = function() {
lib.gc.teardown();
delete roots[ "impress-root-" + rootId ];
};
// Adding some useful classes to step elements.
//
// All the steps that have not been shown yet are given `future` class.
// When the step is entered the `future` class is removed and the `present`
// class is given. When the step is left `present` class is replaced with
// `past` class.
//
// So every step element is always in one of three possible states:
// `future`, `present` and `past`.
//
// There classes can be used in CSS to style different types of steps.
// For example the `present` class can be used to trigger some custom
// animations when step is shown.
lib.gc.addEventListener( root, "impress:init", function() {
// STEP CLASSES
steps.forEach( function( step ) {
step.classList.add( "future" );
} );
lib.gc.addEventListener( root, "impress:stepenter", function( event ) {
event.target.classList.remove( "past" );
event.target.classList.remove( "future" );
event.target.classList.add( "present" );
}, false );
lib.gc.addEventListener( root, "impress:stepleave", function( event ) {
event.target.classList.remove( "present" );
event.target.classList.add( "past" );
}, false );
}, false );
// Adding hash change support.
lib.gc.addEventListener( root, "impress:init", function() {
// Last hash detected
var lastHash = "";
// `#/step-id` is used instead of `#step-id` to prevent default browser
// scrolling to element in hash.
//
// And it has to be set after animation finishes, because in Chrome it
// makes transition laggy.
// BUG: http://code.google.com/p/chromium/issues/detail?id=62820
lib.gc.addEventListener( root, "impress:stepenter", function( event ) {
window.location.hash = lastHash = "#/" + event.target.id;
}, false );
lib.gc.addEventListener( window, "hashchange", function() {
// When the step is entered hash in the location is updated
// (just few lines above from here), so the hash change is
// triggered and we would call `goto` again on the same element.
//
// To avoid this we store last entered hash and compare.
if ( window.location.hash !== lastHash ) {
goto( lib.util.getElementFromHash() );
}
}, false );
// START
// by selecting step defined in url or first step of the presentation
goto( lib.util.getElementFromHash() || steps[ 0 ], 0 );
}, false );
body.classList.add( "impress-disabled" );
// Store and return API for given impress.js root element
return ( roots[ "impress-root-" + rootId ] = {
init: init,
goto: goto,
next: next,
prev: prev,
swipe: swipe,
tear: tear,
lib: lib
} );
};
// Flag that can be used in JS to check if browser have passed the support test
impress.supported = impressSupported;
// ADD and INIT LIBRARIES
// Library factories are defined in src/lib/*.js, and register themselves by calling
// impress.addLibraryFactory(libraryFactoryObject). They're stored here, and used to augment
// the API with library functions when client calls impress(rootId).
// See src/lib/README.md for clearer example.
// (Advanced usage: For different values of rootId, a different instance of the libaries are
// generated, in case they need to hold different state for different root elements.)
var libraryFactories = {};
impress.addLibraryFactory = function( obj ) {
for ( var libname in obj ) {
if ( obj.hasOwnProperty( libname ) ) {
libraryFactories[ libname ] = obj[ libname ];
}
}
};
// Call each library factory, and return the lib object that is added to the api.
var initLibraries = function( rootId ) { //jshint ignore:line
var lib = {};
for ( var libname in libraryFactories ) {
if ( libraryFactories.hasOwnProperty( libname ) ) {
if ( lib[ libname ] !== undefined ) {
throw "impress.js ERROR: Two libraries both tried to use libname: " + libname;
}
lib[ libname ] = libraryFactories[ libname ]( rootId );
}
}
return lib;
};
// `addPreInitPlugin` allows plugins to register a function that should
// be run (synchronously) at the beginning of init, before
// impress().init() itself executes.
impress.addPreInitPlugin = function( plugin, weight ) {
weight = parseInt( weight ) || 10;
if ( weight <= 0 ) {
throw "addPreInitPlugin: weight must be a positive integer";
}
if ( preInitPlugins[ weight ] === undefined ) {
preInitPlugins[ weight ] = [];
}
preInitPlugins[ weight ].push( plugin );
};
// Called at beginning of init, to execute all pre-init plugins.
var execPreInitPlugins = function( root ) { //jshint ignore:line
for ( var i = 0; i < preInitPlugins.length; i++ ) {
var thisLevel = preInitPlugins[ i ];
if ( thisLevel !== undefined ) {
for ( var j = 0; j < thisLevel.length; j++ ) {
thisLevel[ j ]( root, roots[ "impress-root-" + root.id ] );
}
}
}
};
// `addPreStepLeavePlugin` allows plugins to register a function that should
// be run (synchronously) at the beginning of goto()
impress.addPreStepLeavePlugin = function( plugin, weight ) { //jshint ignore:line
weight = parseInt( weight ) || 10;
if ( weight <= 0 ) {
throw "addPreStepLeavePlugin: weight must be a positive integer";
}
if ( preStepLeavePlugins[ weight ] === undefined ) {
preStepLeavePlugins[ weight ] = [];
}
preStepLeavePlugins[ weight ].push( plugin );
};
impress.getConfig = function() {
return config;
};
// Called at beginning of goto(), to execute all preStepLeave plugins.
var execPreStepLeavePlugins = function( event ) { //jshint ignore:line
for ( var i = 0; i < preStepLeavePlugins.length; i++ ) {
var thisLevel = preStepLeavePlugins[ i ];
if ( thisLevel !== undefined ) {
for ( var j = 0; j < thisLevel.length; j++ ) {
if ( thisLevel[ j ]( event ) === false ) {
// If a plugin returns false, the stepleave event (and related transition)
// is aborted
return false;
}
}
}
}
};
} )( document, window );
// THAT'S ALL FOLKS!
//
// Thanks for reading it all.
// Or thanks for scrolling down and reading the last part.
//
// I've learnt a lot when building impress.js and I hope this code and comments
// will help somebody learn at least some part of it.

39
src/index.html Normal file
View File

@@ -0,0 +1,39 @@
<!--
* impress.js - index.html
*
* This is just a test file for development of impress.js V3
*
* Created by Janis Hutz 01/08/2024, Licensed under the MIT License
* https://janishutz.com, development@janishutz.com
*
*
-->
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
.impress-supported .fallback-message {
display: none;
}
</style>
</head>
<body class="impress-not-supported">
<div class="fallback-message">
<p>Your browser <b>doesn't support the features required</b> by impress.js, so you are presented with a simplified version of this presentation.</p>
<p>For the best experience please use the latest <b>Chrome</b>, <b>Safari</b> or <b>Firefox</b> browser.</p>
</div>
<div id="impress" data-width="1920" data-height="1080">
<div id="title" class="step">
<h1>Test</h1>
</div>
</div>
<script src="/impress.js"></script>
<script>
impress().init();
</script>
</body>
</html>

429
src/lib-old/rotation.js Normal file
View File

@@ -0,0 +1,429 @@
/**
* Helper functions for rotation.
*
* Tommy Tam (c) 2021
* MIT License
*/
( function( document, window ) {
"use strict";
// Singleton library variables
var roots = [];
var libraryFactory = function( rootId ) {
if ( roots[ "impress-root-" + rootId ] ) {
return roots[ "impress-root-" + rootId ];
}
/**
* Round the number to 2 decimals, it's enough for use
*/
var roundNumber = function( num ) {
return Math.round( ( num + Number.EPSILON ) * 100 ) / 100;
};
/**
* Get the length/norm of a vector.
*
* https://en.wikipedia.org/wiki/Norm_(mathematics)
*/
var vectorLength = function( vec ) {
return Math.sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
};
/**
* Dot product of two vectors.
*
* https://en.wikipedia.org/wiki/Dot_product
*/
var vectorDotProd = function( vec1, vec2 ) {
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
};
/**
* Cross product of two vectors.
*
* https://en.wikipedia.org/wiki/Cross_product
*/
var vectorCrossProd = function( vec1, vec2 ) {
return {
x: vec1.y * vec2.z - vec1.z * vec2.y,
y: vec1.z * vec2.x - vec1.x * vec2.z,
z: vec1.x * vec2.y - vec1.y * vec2.x
};
};
/**
* Determine wheter a vector is a zero vector
*/
var isZeroVector = function( vec ) {
return !roundNumber( vec.x ) && !roundNumber( vec.y ) && !roundNumber( vec.z );
};
/**
* Scalar triple product of three vectors.
*
* It can be used to determine the handness of vectors.
*
* https://en.wikipedia.org/wiki/Triple_product#Scalar_triple_product
*/
var tripleProduct = function( vec1, vec2, vec3 ) {
return vectorDotProd( vectorCrossProd( vec1, vec2 ), vec3 );
};
/**
* The world/absolute unit coordinates.
*
* This coordinate is used by browser to position objects.
* It will not be affected by object rotations.
* All relative positions will finally be converted to this
* coordinate to be used.
*/
var worldUnitCoordinate = {
x: { x:1, y:0, z:0 },
y: { x:0, y:1, z:0 },
z: { x:0, y:0, z:1 }
};
/**
* Make quaternion from rotation axis and angle.
*
* q = [ cos(½θ), sin(½θ) axis ]
*
* If the angle is zero, returns the corresponded quaternion
* of axis.
*
* If the angle is not zero, returns the rotating quaternion
* which corresponds to rotation about the axis, by the angle θ.
*
* https://en.wikipedia.org/wiki/Quaternion
* https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
*/
var makeQuaternion = function( axis, theta = 0 ) {
var r = 0;
var t = 1;
if ( theta ) {
var radians = theta * Math.PI / 180;
r = Math.cos( radians / 2 );
t = Math.sin( radians / 2 ) / vectorLength( axis );
}
var q = [ r, axis.x * t, axis.y * t, axis.z * t ];
return q;
};
/**
* Extract vector from quaternion
*/
var quaternionToVector = function( quaternion ) {
return {
x: roundNumber( quaternion[ 1 ] ),
y: roundNumber( quaternion[ 2 ] ),
z: roundNumber( quaternion[ 3 ] )
};
};
/**
* Returns the conjugate quaternion of a quaternion
*
* https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal
*/
var conjugateQuaternion = function( quaternion ) {
return [ quaternion[ 0 ], -quaternion[ 1 ], -quaternion[ 2 ], -quaternion[ 3 ] ];
};
/**
* Left multiple two quaternion.
*
* Is's used to combine two rotating quaternion into one.
*/
var leftMulQuaternion = function( q1, q2 ) {
return [
( q1[ 0 ] * q2[ 0 ] - q1[ 1 ] * q2[ 1 ] - q1[ 2 ] * q2[ 2 ] - q1[ 3 ] * q2[ 3 ] ),
( q1[ 1 ] * q2[ 0 ] + q1[ 0 ] * q2[ 1 ] - q1[ 3 ] * q2[ 2 ] + q1[ 2 ] * q2[ 3 ] ),
( q1[ 2 ] * q2[ 0 ] + q1[ 3 ] * q2[ 1 ] + q1[ 0 ] * q2[ 2 ] - q1[ 1 ] * q2[ 3 ] ),
( q1[ 3 ] * q2[ 0 ] - q1[ 2 ] * q2[ 1 ] + q1[ 1 ] * q2[ 2 ] + q1[ 0 ] * q2[ 3 ] )
];
};
/**
* Convert a rotation into a quaternion
*/
var rotationToQuaternion = function( baseCoordinate, rotation ) {
var order = rotation.order ? rotation.order : "xyz";
var axes = order.split( "" );
var result = [ 1, 0, 0, 0 ];
for ( var i = 0; i < axes.length; i++ ) {
var deg = rotation[ axes[ i ] ];
if ( !deg || ( Math.abs( deg ) < 0.0001 ) ) {
continue;
}
// All CSS rotation is based on the rotated coordinate
// So we need to calculate the rotated coordinate first
var coordinate = baseCoordinate;
if ( i > 0 ) {
coordinate = {
x: rotateByQuaternion( baseCoordinate.x, result ),
y: rotateByQuaternion( baseCoordinate.y, result ),
z: rotateByQuaternion( baseCoordinate.z, result )
};
}
result = leftMulQuaternion(
makeQuaternion( coordinate[ axes[ i ] ], deg ),
result );
}
return result;
};
/**
* Rotate a vector by a quaternion.
*/
var rotateByQuaternion = function( vec, quaternion ) {
var q = makeQuaternion( vec );
q = leftMulQuaternion(
leftMulQuaternion( quaternion, q ),
conjugateQuaternion( quaternion ) );
return quaternionToVector( q );
};
/**
* Rotate a vector by rotaion sequence.
*/
var rotateVector = function( baseCoordinate, vec, rotation ) {
var quaternion = rotationToQuaternion( baseCoordinate, rotation );
return rotateByQuaternion( vec, quaternion );
};
/**
* Given a rotation, return the rotationed coordinate
*/
var rotateCoordinate = function( coordinate, rotation ) {
var quaternion = rotationToQuaternion( coordinate, rotation );
return {
x: rotateByQuaternion( coordinate.x, quaternion ),
y: rotateByQuaternion( coordinate.y, quaternion ),
z: rotateByQuaternion( coordinate.z, quaternion )
};
};
/**
* Return the angle between two vector.
*
* The axis is used to determine the rotation direction.
*/
var angleBetweenTwoVector = function( axis, vec1, vec2 ) {
var vecLen1 = vectorLength( vec1 );
var vecLen2 = vectorLength( vec2 );
if ( !vecLen1 || !vecLen2 ) {
return 0;
}
var cos = vectorDotProd( vec1, vec2 ) / vecLen1 / vecLen2 ;
var angle = Math.acos( cos ) * 180 / Math.PI;
if ( tripleProduct( vec1, vec2, axis ) > 0 ) {
return angle;
} else {
return -angle;
}
};
/**
* Return the angle between a vector and a plane.
*
* The plane is determined by an axis and a vector on the plane.
*/
var angleBetweenPlaneAndVector = function( axis, planeVec, rotatedVec ) {
var norm = vectorCrossProd( axis, planeVec );
if ( isZeroVector( norm ) ) {
return 0;
}
return 90 - angleBetweenTwoVector( axis, rotatedVec, norm );
};
/**
* Calculated a order specified rotation sequence to
* transform from the world coordinate to required coordinate.
*/
var coordinateToOrderedRotation = function( coordinate, order ) {
var axis0 = order[ 0 ];
var axis1 = order[ 1 ];
var axis2 = order[ 2 ];
var reversedOrder = order.split( "" ).reverse().join( "" );
var rotate2 = angleBetweenPlaneAndVector(
coordinate[ axis2 ],
worldUnitCoordinate[ axis0 ],
coordinate[ axis0 ] );
// The r2 is the reverse of rotate for axis2
// The coordinate1 is the coordinate before rotate of axis2
var r2 = { order: reversedOrder };
r2[ axis2 ] = -rotate2;
var coordinate1 = rotateCoordinate( coordinate, r2 );
// Calculate the rotation for axis1
var rotate1 = angleBetweenTwoVector(
coordinate1[ axis1 ],
worldUnitCoordinate[ axis0 ],
coordinate1[ axis0 ] );
// Calculate the rotation for axis0
var rotate0 = angleBetweenTwoVector(
worldUnitCoordinate[ axis0 ],
worldUnitCoordinate[ axis1 ],
coordinate1[ axis1 ] );
var rotation = { };
rotation.order = order;
rotation[ axis0 ] = roundNumber( rotate0 );
rotation[ axis1 ] = roundNumber( rotate1 );
rotation[ axis2 ] = roundNumber( rotate2 );
return rotation;
};
/**
* Returns the possible rotations from unit coordinate
* to specified coordinate.
*/
var possibleRotations = function( coordinate ) {
var orders = [ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx" ];
var rotations = [ ];
for ( var i = 0; i < orders.length; ++i ) {
rotations.push(
coordinateToOrderedRotation( coordinate, orders[ i ] )
);
}
return rotations;
};
/**
* Calculate a degree which in range (-180, 180] of baseDeg
*/
var nearestAngle = function( baseDeg, deg ) {
while ( deg > baseDeg + 180 ) {
deg -= 360;
}
while ( deg < baseDeg - 180 ) {
deg += 360;
}
return deg;
};
/**
* Given a base rotation and multiple rotations, return the best one.
*
* The best one is the one has least rotate from base.
*/
var bestRotation = function( baseRotate, rotations ) {
var bestScore;
var bestRotation;
for ( var i = 0; i < rotations.length; ++i ) {
var rotation = {
order: rotations[ i ].order,
x: nearestAngle( baseRotate.x, rotations[ i ].x ),
y: nearestAngle( baseRotate.y, rotations[ i ].y ),
z: nearestAngle( baseRotate.z, rotations[ i ].z )
};
var score = Math.abs( rotation.x - baseRotate.x ) +
Math.abs( rotation.y - baseRotate.y ) +
Math.abs( rotation.z - baseRotate.z );
if ( !i || ( score < bestScore ) ) {
bestScore = score;
bestRotation = rotation;
}
}
return bestRotation;
};
/**
* Given a coordinate, return the best rotation to achieve it.
*
* The baseRotate is used to select the near rotation from it.
*/
var coordinateToRotation = function( baseRotate, coordinate ) {
var rotations = possibleRotations( coordinate );
return bestRotation( baseRotate, rotations );
};
/**
* Apply a relative rotation to the base rotation.
*
* Calculate the coordinate after the rotation on each axis,
* and finally find out a one step rotation has the effect
* of two rotation.
*
* If there're multiple way to accomplish, select the one
* that is nearest to the base.
*
* Return one rotation has the same effect.
*/
var combineRotations = function( rotations ) {
// No rotation
if ( rotations.length <= 0 ) {
return { x:0, y:0, z:0, order:"xyz" };
}
// Find out the base coordinate
var coordinate = worldUnitCoordinate;
// One by one apply rotations in order
for ( var i = 0; i < rotations.length; i++ ) {
coordinate = rotateCoordinate( coordinate, rotations[ i ] );
}
// Calculate one rotation from unit coordinate to rotated
// coordinate. Because there're multiple possibles,
// select the one nearest to the base
var rotate = coordinateToRotation( rotations[ 0 ], coordinate );
return rotate;
};
var translateRelative = function( relative, prevRotation ) {
var result = rotateVector(
worldUnitCoordinate, relative, prevRotation );
result.rotate = combineRotations(
[ prevRotation, relative.rotate ] );
return result;
};
var lib = {
translateRelative: translateRelative
};
roots[ "impress-root-" + rootId ] = lib;
return lib;
};
// Let impress core know about the existence of this library
window.impress.addLibraryFactory( { rotation: libraryFactory } );
} )( document, window );

7
src/lib/position.js Normal file
View File

@@ -0,0 +1,7 @@
// File name: position.js
// Author: Janis Hutz
// Date created: 2025-10-24 13:54:52
// Date modified: 2025-10-24 13:54:53
// ------

85
src/lib/render.js Normal file
View File

@@ -0,0 +1,85 @@
// File name: render.js
// Author: Janis Hutz
// Date created: 2025-10-24 14:04:37
// Date modified: 2025-10-24 14:26:50
// ------
class ImpressCamera {
constructor () {
this.position = {
'x': 0,
'y': 0,
'z': 0
};
this.rotation = {
'x': 0,
'y': 0,
'z': 0
};
}
setPosition ( x, y, z ) {
this.position.x = x;
this.position.y = y;
this.position.z = z;
}
setRotation ( x, y, z ) {
this.rotation.x = x;
this.rotation.y = y;
this.rotation.z = z;
}
getState () {
return {
'position': this.position,
'rotation': this.rotation
};
}
}
class ImpressElement {
// eslint-disable-next-line max-params
constructor ( element, x, y, z, rotationX, rotationY, rotationZ ) {
this.element = element;
this.position = {
'x': x,
'y': y,
'z': z
};
this.rotation = {
'x': rotationX,
'y': rotationY,
'z': rotationZ
};
}
}
const renderer = () => {
const camera = new ImpressCamera();
const addElement = ( HTMLElement ) => {
// Element will need data-x, data-y, data-z, etc dataset
};
const removeElement = ( HTMLElement ) => {
};
const render = () => {
};
const moveTo = ( x, y, z, rotationX, rotationY, rotationZ ) => {
};
return {
addElement,
removeElement,
moveTo
};
};

View File

@@ -1,429 +1,7 @@
/**
* Helper functions for rotation.
*
* Tommy Tam (c) 2021
* MIT License
*/
( function( document, window ) {
"use strict";
// File name: rotation.js
// Author: Janis Hutz
// Date created: 2025-10-24 13:54:49
// Date modified: 2025-10-24 13:54:50
// ------
// Singleton library variables
var roots = [];
var libraryFactory = function( rootId ) {
if ( roots[ "impress-root-" + rootId ] ) {
return roots[ "impress-root-" + rootId ];
}
/**
* Round the number to 2 decimals, it's enough for use
*/
var roundNumber = function( num ) {
return Math.round( ( num + Number.EPSILON ) * 100 ) / 100;
};
/**
* Get the length/norm of a vector.
*
* https://en.wikipedia.org/wiki/Norm_(mathematics)
*/
var vectorLength = function( vec ) {
return Math.sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
};
/**
* Dot product of two vectors.
*
* https://en.wikipedia.org/wiki/Dot_product
*/
var vectorDotProd = function( vec1, vec2 ) {
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
};
/**
* Cross product of two vectors.
*
* https://en.wikipedia.org/wiki/Cross_product
*/
var vectorCrossProd = function( vec1, vec2 ) {
return {
x: vec1.y * vec2.z - vec1.z * vec2.y,
y: vec1.z * vec2.x - vec1.x * vec2.z,
z: vec1.x * vec2.y - vec1.y * vec2.x
};
};
/**
* Determine wheter a vector is a zero vector
*/
var isZeroVector = function( vec ) {
return !roundNumber( vec.x ) && !roundNumber( vec.y ) && !roundNumber( vec.z );
};
/**
* Scalar triple product of three vectors.
*
* It can be used to determine the handness of vectors.
*
* https://en.wikipedia.org/wiki/Triple_product#Scalar_triple_product
*/
var tripleProduct = function( vec1, vec2, vec3 ) {
return vectorDotProd( vectorCrossProd( vec1, vec2 ), vec3 );
};
/**
* The world/absolute unit coordinates.
*
* This coordinate is used by browser to position objects.
* It will not be affected by object rotations.
* All relative positions will finally be converted to this
* coordinate to be used.
*/
var worldUnitCoordinate = {
x: { x:1, y:0, z:0 },
y: { x:0, y:1, z:0 },
z: { x:0, y:0, z:1 }
};
/**
* Make quaternion from rotation axis and angle.
*
* q = [ cos(½θ), sin(½θ) axis ]
*
* If the angle is zero, returns the corresponded quaternion
* of axis.
*
* If the angle is not zero, returns the rotating quaternion
* which corresponds to rotation about the axis, by the angle θ.
*
* https://en.wikipedia.org/wiki/Quaternion
* https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
*/
var makeQuaternion = function( axis, theta = 0 ) {
var r = 0;
var t = 1;
if ( theta ) {
var radians = theta * Math.PI / 180;
r = Math.cos( radians / 2 );
t = Math.sin( radians / 2 ) / vectorLength( axis );
}
var q = [ r, axis.x * t, axis.y * t, axis.z * t ];
return q;
};
/**
* Extract vector from quaternion
*/
var quaternionToVector = function( quaternion ) {
return {
x: roundNumber( quaternion[ 1 ] ),
y: roundNumber( quaternion[ 2 ] ),
z: roundNumber( quaternion[ 3 ] )
};
};
/**
* Returns the conjugate quaternion of a quaternion
*
* https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal
*/
var conjugateQuaternion = function( quaternion ) {
return [ quaternion[ 0 ], -quaternion[ 1 ], -quaternion[ 2 ], -quaternion[ 3 ] ];
};
/**
* Left multiple two quaternion.
*
* Is's used to combine two rotating quaternion into one.
*/
var leftMulQuaternion = function( q1, q2 ) {
return [
( q1[ 0 ] * q2[ 0 ] - q1[ 1 ] * q2[ 1 ] - q1[ 2 ] * q2[ 2 ] - q1[ 3 ] * q2[ 3 ] ),
( q1[ 1 ] * q2[ 0 ] + q1[ 0 ] * q2[ 1 ] - q1[ 3 ] * q2[ 2 ] + q1[ 2 ] * q2[ 3 ] ),
( q1[ 2 ] * q2[ 0 ] + q1[ 3 ] * q2[ 1 ] + q1[ 0 ] * q2[ 2 ] - q1[ 1 ] * q2[ 3 ] ),
( q1[ 3 ] * q2[ 0 ] - q1[ 2 ] * q2[ 1 ] + q1[ 1 ] * q2[ 2 ] + q1[ 0 ] * q2[ 3 ] )
];
};
/**
* Convert a rotation into a quaternion
*/
var rotationToQuaternion = function( baseCoordinate, rotation ) {
var order = rotation.order ? rotation.order : "xyz";
var axes = order.split( "" );
var result = [ 1, 0, 0, 0 ];
for ( var i = 0; i < axes.length; i++ ) {
var deg = rotation[ axes[ i ] ];
if ( !deg || ( Math.abs( deg ) < 0.0001 ) ) {
continue;
}
// All CSS rotation is based on the rotated coordinate
// So we need to calculate the rotated coordinate first
var coordinate = baseCoordinate;
if ( i > 0 ) {
coordinate = {
x: rotateByQuaternion( baseCoordinate.x, result ),
y: rotateByQuaternion( baseCoordinate.y, result ),
z: rotateByQuaternion( baseCoordinate.z, result )
};
}
result = leftMulQuaternion(
makeQuaternion( coordinate[ axes[ i ] ], deg ),
result );
}
return result;
};
/**
* Rotate a vector by a quaternion.
*/
var rotateByQuaternion = function( vec, quaternion ) {
var q = makeQuaternion( vec );
q = leftMulQuaternion(
leftMulQuaternion( quaternion, q ),
conjugateQuaternion( quaternion ) );
return quaternionToVector( q );
};
/**
* Rotate a vector by rotaion sequence.
*/
var rotateVector = function( baseCoordinate, vec, rotation ) {
var quaternion = rotationToQuaternion( baseCoordinate, rotation );
return rotateByQuaternion( vec, quaternion );
};
/**
* Given a rotation, return the rotationed coordinate
*/
var rotateCoordinate = function( coordinate, rotation ) {
var quaternion = rotationToQuaternion( coordinate, rotation );
return {
x: rotateByQuaternion( coordinate.x, quaternion ),
y: rotateByQuaternion( coordinate.y, quaternion ),
z: rotateByQuaternion( coordinate.z, quaternion )
};
};
/**
* Return the angle between two vector.
*
* The axis is used to determine the rotation direction.
*/
var angleBetweenTwoVector = function( axis, vec1, vec2 ) {
var vecLen1 = vectorLength( vec1 );
var vecLen2 = vectorLength( vec2 );
if ( !vecLen1 || !vecLen2 ) {
return 0;
}
var cos = vectorDotProd( vec1, vec2 ) / vecLen1 / vecLen2 ;
var angle = Math.acos( cos ) * 180 / Math.PI;
if ( tripleProduct( vec1, vec2, axis ) > 0 ) {
return angle;
} else {
return -angle;
}
};
/**
* Return the angle between a vector and a plane.
*
* The plane is determined by an axis and a vector on the plane.
*/
var angleBetweenPlaneAndVector = function( axis, planeVec, rotatedVec ) {
var norm = vectorCrossProd( axis, planeVec );
if ( isZeroVector( norm ) ) {
return 0;
}
return 90 - angleBetweenTwoVector( axis, rotatedVec, norm );
};
/**
* Calculated a order specified rotation sequence to
* transform from the world coordinate to required coordinate.
*/
var coordinateToOrderedRotation = function( coordinate, order ) {
var axis0 = order[ 0 ];
var axis1 = order[ 1 ];
var axis2 = order[ 2 ];
var reversedOrder = order.split( "" ).reverse().join( "" );
var rotate2 = angleBetweenPlaneAndVector(
coordinate[ axis2 ],
worldUnitCoordinate[ axis0 ],
coordinate[ axis0 ] );
// The r2 is the reverse of rotate for axis2
// The coordinate1 is the coordinate before rotate of axis2
var r2 = { order: reversedOrder };
r2[ axis2 ] = -rotate2;
var coordinate1 = rotateCoordinate( coordinate, r2 );
// Calculate the rotation for axis1
var rotate1 = angleBetweenTwoVector(
coordinate1[ axis1 ],
worldUnitCoordinate[ axis0 ],
coordinate1[ axis0 ] );
// Calculate the rotation for axis0
var rotate0 = angleBetweenTwoVector(
worldUnitCoordinate[ axis0 ],
worldUnitCoordinate[ axis1 ],
coordinate1[ axis1 ] );
var rotation = { };
rotation.order = order;
rotation[ axis0 ] = roundNumber( rotate0 );
rotation[ axis1 ] = roundNumber( rotate1 );
rotation[ axis2 ] = roundNumber( rotate2 );
return rotation;
};
/**
* Returns the possible rotations from unit coordinate
* to specified coordinate.
*/
var possibleRotations = function( coordinate ) {
var orders = [ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx" ];
var rotations = [ ];
for ( var i = 0; i < orders.length; ++i ) {
rotations.push(
coordinateToOrderedRotation( coordinate, orders[ i ] )
);
}
return rotations;
};
/**
* Calculate a degree which in range (-180, 180] of baseDeg
*/
var nearestAngle = function( baseDeg, deg ) {
while ( deg > baseDeg + 180 ) {
deg -= 360;
}
while ( deg < baseDeg - 180 ) {
deg += 360;
}
return deg;
};
/**
* Given a base rotation and multiple rotations, return the best one.
*
* The best one is the one has least rotate from base.
*/
var bestRotation = function( baseRotate, rotations ) {
var bestScore;
var bestRotation;
for ( var i = 0; i < rotations.length; ++i ) {
var rotation = {
order: rotations[ i ].order,
x: nearestAngle( baseRotate.x, rotations[ i ].x ),
y: nearestAngle( baseRotate.y, rotations[ i ].y ),
z: nearestAngle( baseRotate.z, rotations[ i ].z )
};
var score = Math.abs( rotation.x - baseRotate.x ) +
Math.abs( rotation.y - baseRotate.y ) +
Math.abs( rotation.z - baseRotate.z );
if ( !i || ( score < bestScore ) ) {
bestScore = score;
bestRotation = rotation;
}
}
return bestRotation;
};
/**
* Given a coordinate, return the best rotation to achieve it.
*
* The baseRotate is used to select the near rotation from it.
*/
var coordinateToRotation = function( baseRotate, coordinate ) {
var rotations = possibleRotations( coordinate );
return bestRotation( baseRotate, rotations );
};
/**
* Apply a relative rotation to the base rotation.
*
* Calculate the coordinate after the rotation on each axis,
* and finally find out a one step rotation has the effect
* of two rotation.
*
* If there're multiple way to accomplish, select the one
* that is nearest to the base.
*
* Return one rotation has the same effect.
*/
var combineRotations = function( rotations ) {
// No rotation
if ( rotations.length <= 0 ) {
return { x:0, y:0, z:0, order:"xyz" };
}
// Find out the base coordinate
var coordinate = worldUnitCoordinate;
// One by one apply rotations in order
for ( var i = 0; i < rotations.length; i++ ) {
coordinate = rotateCoordinate( coordinate, rotations[ i ] );
}
// Calculate one rotation from unit coordinate to rotated
// coordinate. Because there're multiple possibles,
// select the one nearest to the base
var rotate = coordinateToRotation( rotations[ 0 ], coordinate );
return rotate;
};
var translateRelative = function( relative, prevRotation ) {
var result = rotateVector(
worldUnitCoordinate, relative, prevRotation );
result.rotate = combineRotations(
[ prevRotation, relative.rotate ] );
return result;
};
var lib = {
translateRelative: translateRelative
};
roots[ "impress-root-" + rootId ] = lib;
return lib;
};
// Let impress core know about the existence of this library
window.impress.addLibraryFactory( { rotation: libraryFactory } );
} )( document, window );

76
src/lib/vectorUtil.js Normal file
View File

@@ -0,0 +1,76 @@
/* ! Licensed under MIT License - https://github.com/impress/impress.js/blob/master/LICENSE */
/**
* impress.js
*
* impress.js is a presentation tool based on the power of CSS3 transforms and transitions
* in modern browsers and inspired by the idea behind prezi.com.
*
*
* Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-present Henrik Ingo (@henrikingo), 2025-present Janis Hutz
* and 70+ other contributors
*
* Released under the MIT License.
*
* ------------------------------------------------
* authors: Bartek Szopka, Henrik Ingo, Janis Hutz
* version: 3.0.0
* url: http://impress.js.org
* source: http://github.com/impress/impress.js/
*/
// Welcome to the vectorUtil.js file. This file exposes various functions for use in calculating with vectors
class Vector {
/**
* Description
* @param {number} x The x-coordinate
* @param {number} y The y-coordinate
* @param {number} z The z-coordinate
* @returns {undefined} Returns nothing
*/
constructor ( x, y, z ) {
this.x = x;
this.y = y;
this.z = z;
}
}
window.impressVectorUtil = () => {
/**
* Get the cross product of two vectors (https://en.wikipedia.org/wiki/Cross_product)
* @param {Vector} vec1 The first vector
* @param {Vector} vec2 The second vector
* @returns {Vector} Returns a vector object
*/
const vectorProduct = ( vec1, vec2 ) => new Vector(
( vec1.y * vec2.z ) - ( vec1.z * vec2.y ),
( vec1.z * vec2.x ) - ( vec1.x * vec2.z ),
( vec1.x * vec2.y ) - ( vec1.y * vec2.x )
);
/**
* Get the dot product of two vectors (https://en.wikipedia.org/wiki/Dot_product)
* @param {Vector} vec1 The first vector
* @param {Vector} vec2 The second vector
* @returns {number} Returns the calculated value of the dot product
*/
const dotProduct = ( vec1, vec2 ) => ( vec1.x * vec2.x ) + ( vec1.y * vec2.y ) + ( vec1.z * vec2.z );
/**
* Get the norm of a vector (https://en.wikipedia.org/wiki/Norm_(mathematics))
* @param {Vector} vec The vector of which to calculate the norm
* @returns {number} Returns the norm
*/
const norm = ( vec ) => Math.sqrt( ( vec.x * vec.x ) + ( vec.y * vec.y ) + ( vec.z * vec.z ) );
const baseChange = ( angle ) => {};
return {
norm,
dotProduct,
vectorProduct
};
};

View File

@@ -5,103 +5,109 @@
// Log all QUnit assertions to console.log(), so that they are visible in karma output
QUnit.log( function( details ) {
console.log( 'QUnit.log: ', details.result, details.message );
console.log( 'QUnit.log: ', details.result, details.message );
} );
var loadIframe = function( src, assert, callback ) {
console.log( 'Begin loadIframe' );
console.log( 'Begin loadIframe' );
// When running in Karma, the #qunit-fixture appears from somewhere and we can't set its
// contents in advance, so we set it now.
var fix = document.getElementById( 'qunit-fixture' );
fix.innerHTML = [
'\n',
' <iframe id="presentation-iframe"\n',
' width="595" height="485"\n',
' frameborder="0" marginwidth="0" marginheight="0" scrolling="no"\n',
' style="border:1px solid #CCC; max-width: 100%;">\n',
' </iframe>'
// When running in Karma, the #qunit-fixture appears from somewhere and we can't set its
// contents in advance, so we set it now.
var fix = document.getElementById( 'qunit-fixture' );
fix.innerHTML = [
'\n',
' <iframe id="presentation-iframe"\n',
' width="595" height="485"\n',
' frameborder="0" marginwidth="0" marginheight="0" scrolling="no"\n',
' style="border:1px solid #CCC; max-width: 100%;">\n',
' </iframe>'
].join( '' );
var iframe = document.getElementById( 'presentation-iframe' );
var iframe = document.getElementById( 'presentation-iframe' );
var onLoad = function() {
assert.ok( true,
'Presentation loaded. iframe.src = ' + iframe.src );
try {
assert.ok( iframe.contentDocument,
'Verifying that tests can access the presentation inside the iframe. ' +
'Note: On Firefox this fails when using paths with "../" parts for the iframe.' );
}
catch ( err ) {
assert.ok( false,
'Error when trying to access presentation in iframe. Note: When using Chrome with ' +
var onLoad = function() {
assert.ok(
true,
'Presentation loaded. iframe.src = ' + iframe.src
);
try {
assert.ok(
iframe.contentDocument,
'Verifying that tests can access the presentation inside the iframe. ' +
'Note: On Firefox this fails when using paths with "../" parts for the iframe.'
);
} catch ( err ) {
assert.ok(
false,
'Error when trying to access presentation in iframe. Note: When using Chrome with ' +
'local files (file:///) this will fail with SecurityError. ' +
'You can however use Chrome over Karma.' );
}
console.log( 'End loadIframe' );
callback();
};
'You can however use Chrome over Karma.'
);
}
console.log( 'End loadIframe' );
callback();
};
iframe.addEventListener( 'load', onLoad );
iframe.addEventListener( 'load', onLoad );
assert.ok( iframe.src = src,
'Setting iframe.src = ' + src );
assert.ok(
iframe.src = src,
'Setting iframe.src = ' + src
);
};
var initPresentation = function( assert, callback, rootId ) {
console.log( 'Begin initPresentation' );
var iframe = document.getElementById( 'presentation-iframe' );
var iframeDoc = iframe.contentDocument;
var iframeWin = iframe.contentWindow;
console.log( 'Begin initPresentation' );
var iframe = document.getElementById( 'presentation-iframe' );
var iframeDoc = iframe.contentDocument;
var iframeWin = iframe.contentWindow;
// Impress:stepenter is the last event triggered in init(), so we wait for that.
var waitForStepEnter = function( event ) {
assert.ok( true, 'impress (' + event.target.id + ') is now initialized.' );
iframeDoc.removeEventListener( 'impress:stepenter', waitForStepEnterWrapper );
console.log( 'End initPresentation' );
callback();
};
// Impress:stepenter is the last event triggered in init(), so we wait for that.
var waitForStepEnter = function( event ) {
assert.ok( true, 'impress (' + event.target.id + ') is now initialized.' );
iframeDoc.removeEventListener( 'impress:stepenter', waitForStepEnterWrapper );
console.log( 'End initPresentation' );
callback();
};
// Unfortunately, impress.js uses the impress:stepenter event internally to
// do some things related to entering a step. This causes a race condition when
// we listen for the same event and expect it to be done with everything.
// We wait 5 ms to resolve the race condition, then it's safe to start testing.
var waitForStepEnterWrapper = function( event ) {
setTimeout( function() { waitForStepEnter( event ); }, 5 );
};
iframeDoc.addEventListener( 'impress:stepenter', waitForStepEnterWrapper );
// Unfortunately, impress.js uses the impress:stepenter event internally to
// do some things related to entering a step. This causes a race condition when
// we listen for the same event and expect it to be done with everything.
// We wait 5 ms to resolve the race condition, then it's safe to start testing.
var waitForStepEnterWrapper = function( event ) {
setTimeout( function() { waitForStepEnter( event ); }, 5 );
};
iframeDoc.addEventListener( 'impress:stepenter', waitForStepEnterWrapper );
assert.strictEqual( iframeWin.impress( rootId ).init(), undefined, 'Initializing impress.' );
assert.strictEqual( iframeWin.impress( rootId ).init(), undefined, 'Initializing impress.' );
};
// Helper function to determine whether this browser is supported by
// impress.js or not. Copied from impress.js itself.
var _impressSupported = function() {
var pfx = ( function() {
var style = document.createElement( 'dummy' ).style,
prefixes = 'Webkit Moz O ms Khtml'.split( ' ' ),
memory = {};
return function( prop ) {
if ( typeof memory[ prop ] === 'undefined' ) {
var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
props = ( prop + ' ' + prefixes.join( ucProp + ' ' ) + ucProp ).split( ' ' );
memory[ prop ] = null;
for ( var i in props ) {
if ( style[ props[ i ] ] !== undefined ) {
memory[ prop ] = props[ i ];
break;
var pfx = ( function() {
var style = document.createElement( 'dummy' ).style,
prefixes = 'Webkit Moz O ms Khtml'.split( ' ' ),
memory = {};
return function( prop ) {
if ( typeof memory[ prop ] === 'undefined' ) {
var ucProp = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
props = ( prop + ' ' + prefixes.join( ucProp + ' ' ) + ucProp ).split( ' ' );
memory[ prop ] = null;
for ( var i in props ) {
if ( style[ props[ i ] ] !== undefined ) {
memory[ prop ] = props[ i ];
break;
}
}
}
}
}
return memory[ prop ];
};
} )();
return memory[ prop ];
};
} )();
var ua = navigator.userAgent.toLowerCase();
return ( pfx( 'perspective' ) !== null ) &&
var ua = navigator.userAgent.toLowerCase();
return ( pfx( 'perspective' ) !== null ) &&
( document.body.classList ) &&
( document.body.dataset ) &&
( ua.search( /(iphone)|(ipod)|(android)/ ) === -1 );
};

9
tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"outDir": "./built",
"allowJs": true,
"target": "ES6",
"skipLibCheck": true
},
"include": [ "./src/**/*" ],
}