Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c9f6c67457 | ||
|
|
48466a42ae | ||
|
|
c95b93a48b | ||
|
|
5da68e0686 | ||
|
|
fd945d5574 | ||
|
|
784b51663f | ||
|
|
f7e19b459e | ||
|
|
eb3c330184 |
532
.eslintrc.js
532
.eslintrc.js
@@ -1,300 +1,296 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'browser': true,
|
||||
'es6': true
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true
|
||||
},
|
||||
'extends': [
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/recommended'
|
||||
],
|
||||
'globals': {
|
||||
'Atomics': 'readonly',
|
||||
'SharedArrayBuffer': 'readonly'
|
||||
"extends": "eslint:recommended",
|
||||
"globals": {
|
||||
"Atomics": "readonly",
|
||||
"SharedArrayBuffer": "readonly"
|
||||
},
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 2022
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018
|
||||
},
|
||||
'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'
|
||||
"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': 'off',
|
||||
'comma-dangle': 'error',
|
||||
'comma-spacing': [
|
||||
'error',
|
||||
"callback-return": "error",
|
||||
"camelcase": "error",
|
||||
"capitalized-comments": "off",
|
||||
"class-methods-use-this": "error",
|
||||
"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-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-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"
|
||||
],
|
||||
'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',
|
||||
'single'
|
||||
"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"
|
||||
],
|
||||
'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"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
61
.github/workflows/pipeline.yaml
vendored
Normal file
61
.github/workflows/pipeline.yaml
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
name: Automates the Verification, Testing, and Building Process
|
||||
|
||||
env:
|
||||
NPM_CONFIG_LOGLEVEL: "warn"
|
||||
NPM_CONFIG_PREFER_OFFLINE: "true"
|
||||
|
||||
jobs:
|
||||
verification:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
- name: Install dependencies
|
||||
run: npm clean-install
|
||||
- name: Lint code
|
||||
run: npm run lint
|
||||
|
||||
testing:
|
||||
needs: verification
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
- name: Install dependencies
|
||||
run: npm clean-install
|
||||
- name: Run test suite
|
||||
run: npm run test
|
||||
|
||||
assembly:
|
||||
needs: testing
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22.x
|
||||
- name: Install dependencies
|
||||
run: npm clean-install
|
||||
- name: Build artifact(s)
|
||||
run: npm run build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,7 +3,6 @@
|
||||
/node_modules
|
||||
/npm-debug.log
|
||||
/*.tgz
|
||||
/built
|
||||
|
||||
# Files for editors and other tools
|
||||
/.brackets.json
|
||||
|
||||
5
.jscsrc
Normal file
5
.jscsrc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"preset": "jquery",
|
||||
// Since we check quotemarks already in jshint, this can be turned off
|
||||
"validateQuoteMarks": false
|
||||
}
|
||||
17
.jshintrc
Normal file
17
.jshintrc
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"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
14
.vscode/tasks.json
vendored
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "typescript",
|
||||
"tsconfig": "tsconfig.json",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
],
|
||||
"group": "build",
|
||||
"label": "tsc: build - tsconfig.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
# Introduction
|
||||
Welcome to impress.js! This presentation framework allows you to create stunning presentations with the power of CSS3 transformations.
|
||||
**NOTE:** This Guide is not made for you, if you have never written HTML and/or CSS before. Knowing your way around in JavaScript certainly helps, but is not a necessity. You may still continue this tutorial and try to understand what we do as you go.
|
||||
**NOTE:** This Guide is not made for you if you have never written HTML and/or CSS before. Knowing your way around in JavaScript certainly helps, but it is not a necessity. You may still continue this tutorial and try to understand what we do as you go.
|
||||
|
||||
For more advanced and complete documentation, you might prefer the [DOCUMENTATION](DOCUMENTATION.md).
|
||||
|
||||
# Getting started with impress.js
|
||||
## Installation / acquiring the framework
|
||||
First of all, you need to know, if you are going to have WiFi connection when you hold your presentation. If you are not sure, please use the method where you download the file instead of the cdn.
|
||||
First of all, you need to know if you are going to have a WiFi connection when you hold your presentation. If you are not sure, please use the method where you download the file instead of the CDN.
|
||||
|
||||
### Including from cdn
|
||||
Loading the script from the cdn is quite straight forward. If you copy the below example code, you need to do nothing else, impress will be loaded automatically.
|
||||
### Including from CDN
|
||||
Loading the script from the CDN is quite straightforward. If you copy the example code below, you need to do nothing else; impress.js will be loaded automatically.
|
||||
|
||||
**Direct links to different versions of the impress.js file**
|
||||
- V2.0.0: https://cdn.jsdelivr.net/gh/impress/impress.js@2.0.0/js/impress.js
|
||||
@@ -17,11 +17,11 @@ Loading the script from the cdn is quite straight forward. If you copy the below
|
||||
- Source: https://cdn.jsdelivr.net/gh/impress/impress.js/js/impress.js
|
||||
|
||||
### Download the file to your PC
|
||||
Head to the releases tab and download the source code as zip or as a tarball. Go ahead and unzip / untar it. You need to copy the folder */js/* into the folder you are working in. Optionally, if you want to make your life a bit easier, you can copy also copy the folder */css/* in there.
|
||||
Head to the releases tab and download the source code as a zip or a tarball. Go ahead and unzip/untar it. You need to copy the folder */js/* into the folder you are working in. Optionally, to make your life a bit easier, you can also copy the */css/* folder into the same location.
|
||||
|
||||
|
||||
## Setting up the project
|
||||
Open up your favorite text-editor / IDE, for example Visual Studio Code, Atom, Notepad ++, ...
|
||||
Open up your favorite text editor / IDE, for example, Visual Studio Code, Atom, Notepad++, ...
|
||||
Now, create a new file called *index.html* and create the basic HTML structure:
|
||||
|
||||
```
|
||||
@@ -50,19 +50,19 @@ 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" 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. Since this isn't exciting, we won't change anything and will review 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.
|
||||
|
||||
So now, we reached the HTML body. You can see that it already belongs to a class. This class just tells impress.js that this is the body where the "fallback-message" should be displayed when it detects, that your browser does not support CSS3 and therefore impress.js won't work. You can easily omit that class though, including the "fallback-message" div with its content, if you only intend to use the presentation for yourself and you know about the fact that some browsers might not work.
|
||||
So now, we have reached the HTML body. You can see that it already belongs to a class. This class just tells impress.js that this is the body where the "fallback-message" should be displayed when it detects, that your browser does not support CSS3 and therefore impress.js won't work. You can easily omit that class though, including the "fallback-message" div with its content, if you only intend to use the presentation for yourself and you know about the fact that some browsers might not work.
|
||||
|
||||
Now, probably the most important part of all is the *div* that belongs to the ```impress``` class. This *div* should contain all the HTML code you write, as everything outside that class will not be animated by impress.js.
|
||||
|
||||
Finally, we load the ```impress.js``` script from your local copy (if you have one) or from the cdn, if you do not have a local copy and execute
|
||||
Finally, we load the ```impress.js``` script from your local copy (if you have one) or from the CDN, if you do not have a local copy, and execute
|
||||
```
|
||||
impress().init()
|
||||
```
|
||||
to initialize impress.js. Now, let's continue on to explore more and more features of this amazing tool!
|
||||
to initialize impress.js. Now, let's continue to explore 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:
|
||||
@@ -74,7 +74,7 @@ Hello World
|
||||
|
||||
Now, if you reload the presentation, you start to see a \*slight\* problem. All your text is stacked... How do we work around that?
|
||||
|
||||
Obviously, impress.js has an answer to it. You can add the following additional attributes to your div, to make it work:
|
||||
Obviously, impress.js has an answer to it. You can add the following additional attributes to your div to make it work:
|
||||
|
||||
Attribute | Explanation
|
||||
----------------|------------
|
||||
@@ -87,11 +87,11 @@ data-rotate-y | Rotate the element along the y-axis
|
||||
data-rotate-z | Rotate the element along the z-axis
|
||||
data-scale | Scale the element.
|
||||
|
||||
These are the basic positioning options in impress.js. All of the attributes take Strings as arguments, so be aware of the fact, that you need to put quotation marks around the numbers! The *data-rotate* attributes take an angle in form of a String as argument.
|
||||
These are the basic positioning options in impress.js. All of the attributes take Strings as arguments, so be aware that you need to put quotation marks around the numbers! The *data-rotate* attributes take an angle in the form of a String as an argument.
|
||||
|
||||
Now, that you have created the slides, you might want to style them. This is where CSS comes into play. Add another file to your project called, e.g., ```style.css```.
|
||||
Now that you have created the slides, you might want to style them. This is where CSS comes into play. Add another file to your project called, e.g., ```style.css```.
|
||||
|
||||
**NOTE:** Whatever you do, do not mess with positioning and rotation of the div that belongs to the class *step*, but add a div inside of it, if you really have to mess with these properties. See the example below. Always position *steps* with the *data-* attribute!
|
||||
**NOTE:** Whatever you do, do not mess with the positioning and rotation of the div that belongs to the class *step*, but add a div inside of it, if you really have to mess with these properties. See the example below. Always position *steps* with the *data-* attribute!
|
||||
|
||||
```
|
||||
<div class="step yourClassNameHere" data-x="1000" data-y="1000" data-z="-1000" data-scale="2" data-rotate-z="90">
|
||||
@@ -115,19 +115,19 @@ data-min-scale | 0 | Minimum scale factor.
|
||||
data-perspective | 1000 | Perspective for 3D rendering. See https://developer.mozilla.org/en/CSS/perspective
|
||||
|
||||
### **Renaming Steps**
|
||||
You can give each step an ID. The name of the ID will be displayed in the browsers navigation bar instead of the default *step-x* whereas x is replaced by the current step number. This can be especially helpful, when trying to jump between steps and go back to a previous one. If you want to know how to move to a specific slide, you should take a look at the [README](./src/plugins/goto/README.md) of the "Goto" plugin.
|
||||
You can give each step an ID. The name of the ID will be displayed in the browser's navigation bar instead of the default *step-x*, where x is replaced by the current step number. This can be especially helpful when trying to jump between steps and go back to a previous one. If you want to know how to move to a specific slide, you should take a look at the [README](./src/plugins/goto/README.md) of the "Goto" plugin.
|
||||
|
||||
# Using PLUGINS
|
||||
Impress.js is limited to everything that we have discussed so far and some other details, we won't go over here. Check the [DOCUMENTATION](DOCUMENTATION.md) for that.
|
||||
Impress.js is limited to everything we have discussed so far, along with some additional details; we won't cover them here. Check the [DOCUMENTATION](DOCUMENTATION.md) for that.
|
||||
|
||||
impress.js has accumulated a lot of very useful plugins. You may find all of them [here](./src/plugins/)!
|
||||
|
||||
Each Plugin has a README.md file which you may read to get an idea on how to use them. Some of the plugins run unnoticed in the background, like the *resize* plugin, which automatically resizes the presentation whenever the browser window changed in size. Here, I will give you an overview of some of the plugins that impress.js includes by default.
|
||||
Each Plugin has a README.md file, which you may read to get an idea of how to use it. Some plugins run unnoticed in the background, such as the *resize* plugin, which automatically resizes the presentation whenever the browser window changes size. Here, I will give you an overview of some of the plugins that impress.js includes by default.
|
||||
|
||||
**NOTE:** As previously mentioned, if you'd like to get more info about how it works, take a look at the [DOCUMENTATION](DOCUMENTATION.md) or the README.md files of the plugins.
|
||||
|
||||
## [impressConsole](/src/plugins/impressConsole/README.md)
|
||||
This plugin opens up and additional browser tab which contains a speaker console. There you can see the current slide, the past slide and your notes. You add notes to your presentation by adding a *div* that belongs to the class "notes" to your *div* that belongs to the class "step".
|
||||
This plugin opens up an additional browser tab that contains a speaker console. There you can see the current slide, the past slide, and your notes. You add notes to your presentation by adding a *div* that belongs to the class "notes" to your *div* that belongs to the class "step".
|
||||
|
||||
### **adding notes to your presentation**
|
||||
You may add notes to your presentation by adding a div of class *notes* into the div of class *step*, like so:
|
||||
@@ -151,17 +151,17 @@ Now that you have added the notes to your HTML, it is time to hide them. You nee
|
||||
To enter it, press P.
|
||||
|
||||
## [Goto](/src/plugins/goto/README.md)
|
||||
This plugin allows you to directly go to a certain step, by either passing in a number or the id of the step you'd like to go to.
|
||||
This plugin allows you to directly go to a certain step by either passing in a number or the ID of the step you'd like to go to.
|
||||
|
||||
## [Progress](/src/plugins/progress/README.md)
|
||||
This plugin, as its name implies, displays the progress in your presentation.
|
||||
|
||||
## [Blackout](/src/plugins/blackout/blackout.js)
|
||||
This plugin hides the screen, if you press B, which is handy in a lot of situations.
|
||||
This plugin hides the screen when you press B, which is handy in many situations.
|
||||
|
||||
## Other plugins
|
||||
You may find the other plugins [here](/src/plugins/). It certainly helps if you familiarise yourself with the plugins.
|
||||
|
||||
|
||||
# Thank you for reading this
|
||||
If you want to know more, you can always ready the [DOCUMENTATION](DOCUMENTATION.md) or, even better, read the Source Code and try to understand how it works!
|
||||
If you want to know more, you can always read the [DOCUMENTATION](DOCUMENTATION.md) or, even better, read the Source Code and try to understand how it works!
|
||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2016 Bartek Szopka, 2016-2024 Henrik Ingo, 2024 Janis Hutz
|
||||
Copyright (c) 2011-2016 Bartek Szopka
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
207
README.md
207
README.md
@@ -1,128 +1,77 @@
|
||||
<div id="title" align="center">
|
||||
<img src="./logo.jpg" width="300">
|
||||
<h1>impress.js</h1>
|
||||
</div>
|
||||
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>
|
||||
[](https://circleci.com/gh/impress/impress.js)
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
**WARNING**
|
||||
|
||||
impress.js may not help you if you have nothing interesting to say ;)
|
||||
|
||||
|
||||
***THIS VERSION IS UNSTABLE AND INCOMPLETE. Please use the [upstream version](https://github.com/impress/impress.js) (V2.0.0)!***
|
||||
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!
|
||||
|
||||
We are switching to TS as the main impress development language, but you can still develop plugins in JS, if you wish!
|
||||
### 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
|
||||
|
||||
# Getting Started with impress.js
|
||||
Welcome to impress.js, the impressive JavaScript framework, that allows you to build presentations for web browsers.
|
||||
### Getting Started Guide
|
||||
Check out our new [Getting Started](GettingStarted.md) guide if you want a quick introduction to the project!
|
||||
|
||||
## 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
|
||||
### Checking out and initializing the git repository
|
||||
|
||||
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.
|
||||
|
||||
## Details
|
||||
For developers, once you've made changes to the code, you should run these commands for testing:
|
||||
**Stable releases**
|
||||
|
||||
npm install
|
||||
npm run all
|
||||
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).
|
||||
|
||||
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.
|
||||
|
||||
More info about the [src/](src/) directory can be found in [src/plugins/README.md](src/plugins/README.md).
|
||||
### Documentation
|
||||
|
||||
## Requirements
|
||||
TODO: Check that these requirements are still ok
|
||||
* >= node 7.6
|
||||
* npm
|
||||
|
||||
# REPOSITORY STRUCTURE
|
||||
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
|
||||
--------------------
|
||||
|
||||
* [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.
|
||||
@@ -137,35 +86,53 @@ TODO: Check that these requirements are still ok
|
||||
* [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.
|
||||
|
||||
TODO: Update repo structure once updating is complete
|
||||
WANT TO CONTRIBUTE?
|
||||
---------------------
|
||||
|
||||
# About impress.js
|
||||
## ABOUT THE NAME
|
||||
For developers, once you've made changes to the code, you should run these commands for testing:
|
||||
|
||||
impress.js name is [courtesy of @skuzniak](https://twitter.com/skuzniak/status/143627215165333504).
|
||||
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.
|
||||
|
||||
More info about the [src/](src/) directory can be found in [src/plugins/README.md](src/plugins/README.md).
|
||||
|
||||
### Requirements
|
||||
|
||||
* >= node 7.6
|
||||
* npm
|
||||
|
||||
|
||||
ABOUT THE NAME
|
||||
----------------
|
||||
|
||||
impress.js name is [courtesy of @skuzniak](http://twitter.com/skuzniak/status/143627215165333504).
|
||||
|
||||
It's an (un)fortunate coincidence that an Open/LibreOffice presentation tool is called Impress ;)
|
||||
|
||||
## Reference API
|
||||
Reference API
|
||||
--------------
|
||||
|
||||
See the [Reference API](/docs/DOCUMENTATION.md)
|
||||
See the [Reference API](DOCUMENTATION.md)
|
||||
|
||||
TODO: Will be updated once full release of V3 is ready
|
||||
BROWSER SUPPORT
|
||||
-----------------
|
||||
|
||||
## Browser support (again, but for devs)
|
||||
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.
|
||||
|
||||
impress.js uses the following CSS and JavaScript features
|
||||
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.
|
||||
|
||||
TODO: Update list below
|
||||
In particular, impress.js makes use of the following JS and CSS features:
|
||||
|
||||
* [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)
|
||||
* [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 and License
|
||||
|
||||
Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-2023 Henrik Ingo (@henrikingo) and [85+ other contributors](https://github.com/impress/impress.js/graphs/contributors)
|
||||
Copyright 2011-2012 Bartek Szopka (@bartaz), 2016-2023 Henrik Ingo (@henrikingo) and [70+ other contributors](https://github.com/impress/impress.js/graphs/contributors)
|
||||
|
||||
Released under the MIT [License](LICENSE)
|
||||
|
||||
75
build.js
Normal file
75
build.js
Normal 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)=>{
|
||||
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);
|
||||
@@ -1,2 +0,0 @@
|
||||
# Adding Elements to impress
|
||||
You can add elements to impress by calling the `impress.addElement` function.
|
||||
@@ -325,7 +325,7 @@
|
||||
A(Support for<br />diagrams)
|
||||
B[Provided by<br />mermaid.js]
|
||||
C{Already<br />know<br />mermaid?}
|
||||
D(<a href="http://knsv.github.io/mermaid/index.html#usage">Tutorial</a>)
|
||||
D(Tutorial)
|
||||
E(Great, hope you enjoy!)
|
||||
A-->B
|
||||
B-->C
|
||||
@@ -338,7 +338,7 @@
|
||||
<h1><a href="http://docs.mathjax.org/en/latest/start.html">MathJax.js</a></h1>
|
||||
<p>Use \(\LaTeX\), MathML or AsciiMath to properly show mathematical formula.</p>
|
||||
<div class="notes">
|
||||
Mermaid.js, likewise in a href="https://github.com/impress/impress.js/tree/master/extras">extras/</a>
|
||||
Mermaid.js, likewise in <a href="https://github.com/impress/impress.js/tree/master/extras">extras/</a>
|
||||
directory, draws SVG diagrams from a MarkDown-like syntax. To learn
|
||||
more about it <a href="http://knsv.github.io/mermaid/index.html#usage">read the fine manual</a>.
|
||||
</div>
|
||||
|
||||
@@ -415,7 +415,7 @@ if ("ontouchstart" in document.documentElement) {
|
||||
but it's optional - if not provided default transition duration for the presentation will be used.
|
||||
|
||||
You can also simply call `impress()` again to get the API, so `impress().next()` is also allowed.
|
||||
Don't worry, it wont initialize the presentation again.
|
||||
Don't worry, it won't initialize the presentation again.
|
||||
|
||||
For some example uses of this API check the last part of the source of impress.js where the API
|
||||
is used in event handlers.
|
||||
|
||||
8871
package-lock.json
generated
8871
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress.js",
|
||||
"version": "3.0.0",
|
||||
"version": "1.1.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,16 +24,15 @@
|
||||
"scripts": {
|
||||
"all": "npm run build && npm run test && npm run lint",
|
||||
"build": "node build.js",
|
||||
"lint": "npm exec -- eslint src test",
|
||||
"lint": "npm exec -- jshint src test/*.js && npm exec -- jscs src test/*.js",
|
||||
"new-lint": "npm exec -- eslint src test",
|
||||
"test": "npm exec -- karma start --log-level debug --single-run=true"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^6.18.0",
|
||||
"@typescript-eslint/parser": "^6.18.0",
|
||||
"eslint": "^8.56.0",
|
||||
"jscs": "^2.1.1",
|
||||
"eslint": "^6.8.0",
|
||||
"jscs": "^3.0.7",
|
||||
"jshint": "^2.11.0",
|
||||
"karma": "^6.4.2",
|
||||
"karma": "^4.4.1",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-firefox-launcher": "^1.3.0",
|
||||
"karma-qunit": "^4.0.0",
|
||||
@@ -42,7 +41,6 @@
|
||||
"qunit": "^2.9.3",
|
||||
"qunit-assert-close": "^2.1.2",
|
||||
"syn": "^0.14.1",
|
||||
"terser": "^4.6.7",
|
||||
"typescript": "^5.3.3"
|
||||
"terser": "^4.6.7"
|
||||
}
|
||||
}
|
||||
|
||||
75
src/build.js
75
src/build.js
@@ -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 ) => 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 );
|
||||
1126
src/impress.js
1126
src/impress.js
File diff suppressed because it is too large
Load Diff
@@ -1,925 +0,0 @@
|
||||
/*! 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.
|
||||
@@ -1,39 +0,0 @@
|
||||
<!--
|
||||
* 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>
|
||||
@@ -1,429 +0,0 @@
|
||||
/**
|
||||
* 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 );
|
||||
@@ -1,7 +0,0 @@
|
||||
// File name: position.js
|
||||
// Author: Janis Hutz
|
||||
// Date created: 2025-10-24 13:54:52
|
||||
// Date modified: 2025-10-24 13:54:53
|
||||
// ------
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
// 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
|
||||
};
|
||||
};
|
||||
@@ -1,7 +1,429 @@
|
||||
// File name: rotation.js
|
||||
// Author: Janis Hutz
|
||||
// Date created: 2025-10-24 13:54:49
|
||||
// Date modified: 2025-10-24 13:54:50
|
||||
// ------
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/* ! 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
|
||||
};
|
||||
};
|
||||
@@ -26,23 +26,18 @@ var loadIframe = function( src, assert, callback ) {
|
||||
var iframe = document.getElementById( 'presentation-iframe' );
|
||||
|
||||
var onLoad = function() {
|
||||
assert.ok(
|
||||
true,
|
||||
'Presentation loaded. iframe.src = ' + iframe.src
|
||||
);
|
||||
assert.ok( true,
|
||||
'Presentation loaded. iframe.src = ' + iframe.src );
|
||||
try {
|
||||
assert.ok(
|
||||
iframe.contentDocument,
|
||||
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,
|
||||
'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.'
|
||||
);
|
||||
'You can however use Chrome over Karma.' );
|
||||
}
|
||||
console.log( 'End loadIframe' );
|
||||
callback();
|
||||
@@ -50,10 +45,8 @@ var loadIframe = function( src, assert, callback ) {
|
||||
|
||||
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 ) {
|
||||
@@ -111,3 +104,4 @@ var _impressSupported = function() {
|
||||
( document.body.dataset ) &&
|
||||
( ua.search( /(iphone)|(ipod)|(android)/ ) === -1 );
|
||||
};
|
||||
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "./built",
|
||||
"allowJs": true,
|
||||
"target": "ES6",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [ "./src/**/*" ],
|
||||
}
|
||||
Reference in New Issue
Block a user