From ba1c05a30e92cf4b0f347bc7ba8ee91810c3dd0f Mon Sep 17 00:00:00 2001 From: Chris Joel Date: Tue, 29 Jan 2019 23:24:50 -0800 Subject: [PATCH] Add visual prompt to interact with camera controls --- examples/background-image.html | 1 + package-lock.json | 158 ++++++++++++++--------------- src/assets/controls-svg.js | 71 +++++++++++++ src/features/controls.js | 17 ++++ src/template.js | 33 ++++++ src/test/features/controls-spec.js | 9 +- 6 files changed, 209 insertions(+), 80 deletions(-) create mode 100644 src/assets/controls-svg.js diff --git a/examples/background-image.html b/examples/background-image.html index 7004db7dac..a39ee24a90 100644 --- a/examples/background-image.html +++ b/examples/background-image.html @@ -58,6 +58,7 @@

With Equirectangular background-image

background-image="assets/whipple_creek_regional_park_04_1k.jpg" alt="A 3D model of a damaged helmet with a forest in the background" src="assets/DamagedHelmet/DamagedHelmet.gltf"> + diff --git a/package-lock.json b/package-lock.json index df3c7d1c97..2d794f4315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1046,19 +1046,19 @@ }, "@types/clean-css": { "version": "3.4.30", - "resolved": "http://registry.npmjs.org/@types/clean-css/-/clean-css-3.4.30.tgz", + "resolved": "https://registry.npmjs.org/@types/clean-css/-/clean-css-3.4.30.tgz", "integrity": "sha1-AFLBNvUkgAJCjjY4s33ko5gYZB0=", "dev": true }, "@types/clone": { "version": "0.1.30", - "resolved": "http://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz", + "resolved": "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz", "integrity": "sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ=", "dev": true }, "@types/compression": { "version": "0.0.33", - "resolved": "http://registry.npmjs.org/@types/compression/-/compression-0.0.33.tgz", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-0.0.33.tgz", "integrity": "sha1-ldxzOiM5qoRjgdfxN3eS0lU9wn0=", "dev": true, "requires": { @@ -1082,13 +1082,13 @@ }, "@types/cssbeautify": { "version": "0.3.1", - "resolved": "http://registry.npmjs.org/@types/cssbeautify/-/cssbeautify-0.3.1.tgz", + "resolved": "https://registry.npmjs.org/@types/cssbeautify/-/cssbeautify-0.3.1.tgz", "integrity": "sha1-jgvuj33suVIlDaDK6+BeMFkcF+8=", "dev": true }, "@types/doctrine": { "version": "0.0.1", - "resolved": "http://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.1.tgz", + "resolved": "https://registry.npmjs.org/@types/doctrine/-/doctrine-0.0.1.tgz", "integrity": "sha1-uZny2fe0PKvgoaLzm8IDvH3K2p0=", "dev": true }, @@ -1172,7 +1172,7 @@ }, "@types/html-minifier": { "version": "3.5.2", - "resolved": "http://registry.npmjs.org/@types/html-minifier/-/html-minifier-3.5.2.tgz", + "resolved": "https://registry.npmjs.org/@types/html-minifier/-/html-minifier-3.5.2.tgz", "integrity": "sha512-yikK28/KlVyf8g9i/k+TDFlteLuZ6QQTUdVqvKtzEB+8DSLCTjxfh6IK45KnW4rYFI3Y8T4LWpYJMTmfJleWaQ==", "dev": true, "requires": { @@ -1183,7 +1183,7 @@ }, "@types/is-windows": { "version": "0.2.0", - "resolved": "http://registry.npmjs.org/@types/is-windows/-/is-windows-0.2.0.tgz", + "resolved": "https://registry.npmjs.org/@types/is-windows/-/is-windows-0.2.0.tgz", "integrity": "sha1-byTuSHMdMRaOpRBhDW3RXl/Jxv8=", "dev": true }, @@ -1224,7 +1224,7 @@ }, "@types/opn": { "version": "3.0.28", - "resolved": "http://registry.npmjs.org/@types/opn/-/opn-3.0.28.tgz", + "resolved": "https://registry.npmjs.org/@types/opn/-/opn-3.0.28.tgz", "integrity": "sha1-CX0NHJtXSVc6XZbfEyOHu20CEYo=", "dev": true, "requires": { @@ -1233,7 +1233,7 @@ }, "@types/parse5": { "version": "2.2.34", - "resolved": "http://registry.npmjs.org/@types/parse5/-/parse5-2.2.34.tgz", + "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-2.2.34.tgz", "integrity": "sha1-44cKEOgnNacg9i1x3NGDunjvOp0=", "dev": true, "requires": { @@ -1242,7 +1242,7 @@ }, "@types/path-is-inside": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/@types/path-is-inside/-/path-is-inside-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/@types/path-is-inside/-/path-is-inside-1.0.0.tgz", "integrity": "sha512-hfnXRGugz+McgX2jxyy5qz9sB21LRzlGn24zlwN2KEgoPtEvjzNRrLtUkOOebPDPZl3Rq7ywKxYvylVcEZDnEw==", "dev": true }, @@ -1278,7 +1278,7 @@ }, "@types/relateurl": { "version": "0.2.28", - "resolved": "http://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.28.tgz", + "resolved": "https://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.28.tgz", "integrity": "sha1-a9p9uGU/piZD9e5p6facEaOS46Y=", "dev": true }, @@ -1371,7 +1371,7 @@ }, "@types/whatwg-url": { "version": "6.4.0", - "resolved": "http://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-6.4.0.tgz", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-6.4.0.tgz", "integrity": "sha512-tonhlcbQ2eho09am6RHnHOgvtDfDYINd5rgxD+2YSkKENooVCFsWizJz139MQW/PV8FfClyKrNe9ZbdHrSCxGg==", "dev": true, "requires": { @@ -1440,7 +1440,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { @@ -1449,7 +1449,7 @@ "dependencies": { "acorn": { "version": "3.3.0", - "resolved": "http://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", "dev": true } @@ -1479,7 +1479,7 @@ "dependencies": { "es6-promisify": { "version": "5.0.0", - "resolved": "http://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "dev": true, "requires": { @@ -1753,7 +1753,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -1772,7 +1772,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -1825,7 +1825,7 @@ }, "babel-helper-is-nodes-equiv": { "version": "0.0.1", - "resolved": "http://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", "dev": true }, @@ -1965,25 +1965,25 @@ }, "babel-plugin-transform-member-expression-literals": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-Jy69Ki1DQbhsJNzYQ3SuWqNwKHQ=", "dev": true }, "babel-plugin-transform-merge-sibling-variables": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-SKMw0oKT4xjQcXXCYMdIWec5i0M=", "dev": true }, "babel-plugin-transform-minify-booleans": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-He72nCITUDipHeH10T11njRkxDw=", "dev": true }, "babel-plugin-transform-property-literals": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-NxJ6qgQSXD0Iv5XNtajx0uRMpFM=", "dev": true, "requires": { @@ -1998,13 +1998,13 @@ }, "babel-plugin-transform-remove-console": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-xXF6+fdpGLKCHPrvRNgkXU6pQiw=", "dev": true }, "babel-plugin-transform-remove-debugger": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-H8NcKcfAh4zzDlWKczZRkG6IjkQ=", "dev": true }, @@ -2019,19 +2019,19 @@ }, "babel-plugin-transform-simplify-comparison-operators": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-9UmabcPtaGvaUzY4ZrZ92ndMW+0=", "dev": true }, "babel-plugin-transform-undefined-to-void": { "version": "6.10.0-alpha.f95869d4", - "resolved": "http://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.10.0-alpha.f95869d4.tgz", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.10.0-alpha.f95869d4.tgz", "integrity": "sha1-F1oaMJDmFkA/jIGc3Ooa7LZlI7I=", "dev": true }, "babel-preset-minify": { "version": "0.4.0-alpha.caaefb4c", - "resolved": "http://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.4.0-alpha.caaefb4c.tgz", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.4.0-alpha.caaefb4c.tgz", "integrity": "sha1-pQUsWVXdl9JGmbKB/amjAuqMGHE=", "dev": true, "requires": { @@ -2229,7 +2229,7 @@ }, "basic-auth": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", "dev": true }, @@ -2304,7 +2304,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -2509,7 +2509,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -2590,7 +2590,7 @@ }, "camelcase-keys": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { @@ -2600,7 +2600,7 @@ }, "cancel-token": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/cancel-token/-/cancel-token-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/cancel-token/-/cancel-token-0.1.1.tgz", "integrity": "sha1-wYGXZ0uxyEwdaTPr8V2NWlznm08=", "dev": true, "requires": { @@ -2753,7 +2753,7 @@ }, "cleankill": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/cleankill/-/cleankill-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/cleankill/-/cleankill-2.0.0.tgz", "integrity": "sha1-WYMN/ItBHVPccq0J1Fp46jMWGpE=", "dev": true }, @@ -2960,7 +2960,7 @@ }, "commander": { "version": "2.15.1", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true }, @@ -3505,7 +3505,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "dev": true, "requires": { @@ -3618,7 +3618,7 @@ }, "enabled": { "version": "1.0.2", - "resolved": "http://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", "dev": true, "requires": { @@ -3803,7 +3803,7 @@ }, "espree": { "version": "3.5.4", - "resolved": "http://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", "dev": true, "requires": { @@ -4276,7 +4276,7 @@ }, "finalhandler": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", "dev": true, "requires": { @@ -4323,7 +4323,7 @@ "dependencies": { "async": { "version": "0.2.10", - "resolved": "http://registry.npmjs.org/async/-/async-0.2.10.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", "dev": true } @@ -5046,7 +5046,7 @@ }, "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, @@ -5187,7 +5187,7 @@ }, "got": { "version": "6.7.1", - "resolved": "http://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "dev": true, "requires": { @@ -5778,7 +5778,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -5942,7 +5942,7 @@ }, "is-obj": { "version": "1.0.1", - "resolved": "http://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, @@ -6110,7 +6110,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -6404,7 +6404,7 @@ }, "koa-send": { "version": "4.1.3", - "resolved": "http://registry.npmjs.org/koa-send/-/koa-send-4.1.3.tgz", + "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-4.1.3.tgz", "integrity": "sha512-3UetMBdaXSiw24qM2Mx5mKmxLKw5ZTPRjACjfhK6Haca55RKm9hr/uHDrkrxhSl5/S1CKI/RivZVIopiatZuTA==", "dev": true, "requires": { @@ -6530,7 +6530,7 @@ }, "load-json-file": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { @@ -6774,7 +6774,7 @@ }, "lolex": { "version": "1.3.2", - "resolved": "http://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.3.2.tgz", "integrity": "sha1-fD2mL/yzDw9agKJWbKJORdigHzE=", "dev": true }, @@ -7068,7 +7068,7 @@ }, "marked": { "version": "0.3.19", - "resolved": "http://registry.npmjs.org/marked/-/marked-0.3.19.tgz", + "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz", "integrity": "sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==", "dev": true }, @@ -7100,7 +7100,7 @@ }, "media-typer": { "version": "0.3.0", - "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "dev": true }, @@ -7115,7 +7115,7 @@ }, "meow": { "version": "3.7.0", - "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { @@ -7133,7 +7133,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -7234,7 +7234,7 @@ }, "minimist": { "version": "0.0.8", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, @@ -7261,7 +7261,7 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { @@ -7504,7 +7504,7 @@ }, "chalk": { "version": "0.4.0", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", "dev": true, "requires": { @@ -7515,7 +7515,7 @@ }, "strip-ansi": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", "dev": true } @@ -8468,7 +8468,7 @@ }, "async": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/async/-/async-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/async/-/async-1.0.0.tgz", "integrity": "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k=", "dev": true }, @@ -8813,7 +8813,7 @@ "dependencies": { "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -8848,7 +8848,7 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } @@ -8877,7 +8877,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { @@ -9183,7 +9183,7 @@ "dependencies": { "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -9366,7 +9366,7 @@ }, "safe-regex": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", "dev": true, "requires": { @@ -9632,7 +9632,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "dev": true, "requires": { @@ -9803,7 +9803,7 @@ }, "sinon": { "version": "1.17.7", - "resolved": "http://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.17.7.tgz", "integrity": "sha1-RUKk9JugxFwF6y6d2dID4rjv4L8=", "dev": true, "requires": { @@ -10232,7 +10232,7 @@ }, "stacky": { "version": "1.3.1", - "resolved": "http://registry.npmjs.org/stacky/-/stacky-1.3.1.tgz", + "resolved": "https://registry.npmjs.org/stacky/-/stacky-1.3.1.tgz", "integrity": "sha1-PxF+UYe5pz0j+HbWnwXIWxGAShI=", "dev": true, "requires": { @@ -10248,7 +10248,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -10261,13 +10261,13 @@ }, "lodash": { "version": "3.10.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -10353,7 +10353,7 @@ }, "byte-size": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/byte-size/-/byte-size-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-3.0.0.tgz", "integrity": "sha1-QG+eI2aqXav2NnLrKR17sJSV2nU=", "dev": true }, @@ -10468,7 +10468,7 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, @@ -10605,7 +10605,7 @@ "dependencies": { "rimraf": { "version": "2.2.8", - "resolved": "http://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", "dev": true, "optional": true @@ -10665,7 +10665,7 @@ }, "text-encoding": { "version": "0.6.4", - "resolved": "http://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", + "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz", "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=", "dev": true }, @@ -10700,7 +10700,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -11295,7 +11295,7 @@ }, "chai": { "version": "3.5.0", - "resolved": "http://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", "dev": true, "requires": { @@ -11306,7 +11306,7 @@ }, "commander": { "version": "2.9.0", - "resolved": "http://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", "dev": true, "requires": { @@ -11324,7 +11324,7 @@ }, "deep-eql": { "version": "0.1.3", - "resolved": "http://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", "dev": true, "requires": { @@ -11373,7 +11373,7 @@ }, "lodash": { "version": "3.10.1", - "resolved": "http://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", "dev": true }, @@ -11818,7 +11818,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { @@ -11848,7 +11848,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -11891,7 +11891,7 @@ }, "xmlbuilder": { "version": "8.2.2", - "resolved": "http://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-8.2.2.tgz", "integrity": "sha1-aSSGc0ELS6QuGmE2VR0pIjNap3M=", "dev": true, "optional": true diff --git a/src/assets/controls-svg.js b/src/assets/controls-svg.js new file mode 100644 index 0000000000..9cd0e56baa --- /dev/null +++ b/src/assets/controls-svg.js @@ -0,0 +1,71 @@ +export default ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; diff --git a/src/features/controls.js b/src/features/controls.js index 4adb721b9f..527ff4fd4f 100644 --- a/src/features/controls.js +++ b/src/features/controls.js @@ -31,8 +31,10 @@ const $updateOrbitCamera = Symbol('updateOrbitCamera'); const $orbitCamera = Symbol('orbitCamera'); const $defaultCamera = Symbol('defaultCamera'); +const $blurHandler = Symbol('blurHandler'); const $focusHandler = Symbol('focusHandler'); const $changeHandler = Symbol('changeHandler'); +const $onBlur = Symbol('onBlur'); const $onFocus = Symbol('onFocus'); const $onChange = Symbol('onChange'); @@ -41,6 +43,8 @@ const $waitingToPromptUser = Symbol('waitingToPromptUser'); const $userPromptedOnce = Symbol('userPromptedOnce'); const $idleTime = Symbol('idleTime'); +export const $promptElement = Symbol('promptElement'); + export const ControlsMixin = (ModelViewerElement) => { return class extends ModelViewerElement { static get properties() { @@ -57,6 +61,8 @@ export const ControlsMixin = (ModelViewerElement) => { this[$waitingToPromptUser] = false; this[$shouldPromptUserToInteract] = true; + this[$promptElement] = this.shadowRoot.querySelector('.controls-prompt'); + this[$orbitCamera] = this[$scene].camera.clone(); this[$orbitCamera].near = ORBIT_NEAR_PLANE; this[$orbitCamera].far = ORBIT_FAR_PLANE; @@ -65,6 +71,7 @@ export const ControlsMixin = (ModelViewerElement) => { this[$changeHandler] = () => this[$onChange](); this[$focusHandler] = () => this[$onFocus](); + this[$blurHandler] = () => this[$onBlur](); } update(changedProperties) { @@ -83,6 +90,7 @@ export const ControlsMixin = (ModelViewerElement) => { this[$controls].addEventListener('change', this[$changeHandler]); this[$scene].canvas.addEventListener('focus', this[$focusHandler]); + this[$scene].canvas.addEventListener('blur', this[$blurHandler]); this[$updateOrbitCamera](); } else { @@ -91,6 +99,7 @@ export const ControlsMixin = (ModelViewerElement) => { if (this[$controls]) { this[$controls].removeEventListener('change', this[$changeHandler]); this[$scene].canvas.removeEventListener('focus', this[$focusHandler]); + this[$scene].canvas.removeEventListener('blur', this[$blurHandler]); this[$controls].dispose(); this[$controls] = null; @@ -114,6 +123,8 @@ export const ControlsMixin = (ModelViewerElement) => { // particular instance: this[$userPromptedOnce] = true; this[$waitingToPromptUser] = false; + + this[$promptElement].classList.add('visible'); } } @@ -173,11 +184,17 @@ export const ControlsMixin = (ModelViewerElement) => { } } + [$onBlur]() { + this[$waitingToPromptUser] = false; + this[$promptElement].classList.remove('visible'); + } + [$onChange](e) { this[$needsRender](); // Effectively cancel the timer waiting for user interaction: this[$waitingToPromptUser] = false; + this[$promptElement].classList.remove('visible'); // NOTE(cdata): On change (in other words, the camera has adjusted its // orbit), if the user has been prompted at least once already, we no diff --git a/src/template.js b/src/template.js index 4b70b3e2f2..d657be854e 100644 --- a/src/template.js +++ b/src/template.js @@ -13,6 +13,7 @@ * limitations under the License. */ +import ControlsPrompt from './assets/controls-svg.js'; import ARGlyph from './assets/view-in-ar-material-svg.js'; const template = document.createElement('template'); @@ -89,6 +90,31 @@ template.innerHTML = ` canvas.show { display: block; } + + .slot.controls-prompt { + display: flex; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + align-items: center; + justify-content: center; + opacity: 0; + transform-origin: center center; + transform: scale(0.9); + transition: transform 0.3s, opacity 0.3s; + } + + .slot.controls-prompt svg { + transform: scale(0.5); + } + + .slot.controls-prompt.visible { + opacity: 1; + transform: scale(1); + } `; diff --git a/src/test/features/controls-spec.js b/src/test/features/controls-spec.js index 994d25eac9..ff5fd58b4d 100644 --- a/src/test/features/controls-spec.js +++ b/src/test/features/controls-spec.js @@ -13,7 +13,7 @@ * limitations under the License. */ -import {$controls, ControlsMixin, IDLE_PROMPT, IDLE_PROMPT_THRESHOLD_MS} from '../../features/controls.js'; +import {$controls, $promptElement, ControlsMixin, IDLE_PROMPT, IDLE_PROMPT_THRESHOLD_MS} from '../../features/controls.js'; import ModelViewerElementBase, {$scene} from '../../model-viewer-base.js'; import {assetPath, dispatchSyntheticEvent, rafPasses, timePasses, until, waitForEvent} from '../helpers.js'; @@ -87,6 +87,7 @@ suite('ModelViewerElementBase with ControlsMixin', () => { suite('a11y', () => { test('prompts user to interact when focused', async () => { const {canvas} = element[$scene]; + const promptElement = element[$promptElement]; const originalLabel = canvas.getAttribute('aria-label'); // NOTE(cdata): This wait time was added in order to deflake tests on @@ -99,10 +100,13 @@ suite('ModelViewerElementBase with ControlsMixin', () => { canvas.focus(); await until(() => canvas.getAttribute('aria-label') === IDLE_PROMPT); + + expect(promptElement.classList.contains('visible')).to.be.equal(true); }); test('does not prompt if user already interacted', async () => { const {canvas} = element[$scene]; + const promptElement = element[$promptElement]; const originalLabel = canvas.getAttribute('aria-label'); canvas.focus(); @@ -114,6 +118,9 @@ suite('ModelViewerElementBase with ControlsMixin', () => { await timePasses(IDLE_PROMPT_THRESHOLD_MS + 100); expect(canvas.getAttribute('aria-label')).to.be.equal(originalLabel); + + expect(promptElement.classList.contains('visible')) + .to.be.equal(false); }); }); });