Add existing to tracked
@@ -0,0 +1,261 @@
|
||||
Copyright 2011-2022 CesiumJS Contributors
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2011-2020 CesiumJS Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Patents US9153063B2 US9865085B1 US10592242
|
||||
|
||||
Patents pending US15/829,786 US16/850,266 US16/851,958
|
||||
|
||||
# Third-Party Code
|
||||
|
||||
CesiumJS includes the following third-party code.
|
||||
|
||||
### NoSleep.js
|
||||
|
||||
https://github.com/richtr/NoSleep.js
|
||||
|
||||
> NoSleep.js v0.5.0 - git.io/vfn01
|
||||
> Rich Tibbett
|
||||
> MIT license
|
||||
|
||||
### Knockout
|
||||
|
||||
http://knockoutjs.com/
|
||||
|
||||
> (c) The Knockout.js team - http://knockoutjs.com/
|
||||
> License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
### Knockout ES5 plugin
|
||||
|
||||
https://github.com/SteveSanderson/knockout-es5
|
||||
|
||||
> Copyright (c) Steve Sanderson
|
||||
> MIT license
|
||||
>
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
# Tests
|
||||
|
||||
The CesiumJS tests use the following third-party libraries and data.
|
||||
|
||||
### Jasmine
|
||||
|
||||
http://jasmine.github.io/
|
||||
|
||||
Copyright (c) 2008-2014 Pivotal Labs
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,56 @@
|
||||
# @cesium/widgets
|
||||
|
||||
[](https://github.com/CesiumGS/cesium/actions/workflows/dev.yml)
|
||||
[](https://www.npmjs.com/package/@cesium/widgets)
|
||||
[](https://cesium.com/learn/)
|
||||
|
||||

|
||||
|
||||
[CesiumJS](../../README.md) is a JavaScript library for creating 3D globes and 2D maps in a web browser without a plugin. It uses WebGL for hardware-accelerated graphics, and is cross-platform, cross-browser, and tuned for dynamic-data visualization.
|
||||
|
||||
`@cesium/widgets` is a widgets library for use with CesiumJS—including the `CesiumViewer` widget plus widgets for common tasks such as animation, base layer selection and geocoding.
|
||||
|
||||
---
|
||||
|
||||
[**Examples**](https://sandcastle.cesium.com/) :earth_asia: [**Docs**](https://cesium.com/learn/cesiumjs-learn/) :earth_americas: [**Website**](https://cesium.com/cesiumjs) :earth_africa: [**Forum**](https://community.cesium.com/) :earth_asia: [**User Stories**](https://cesium.com/user-stories/)
|
||||
|
||||
---
|
||||
|
||||
## Install
|
||||
|
||||
`@cesium/widgets` is published as ES modules with full typing support.
|
||||
|
||||
Install with npm
|
||||
|
||||
```sh
|
||||
npm install @cesium/widgets --save
|
||||
```
|
||||
|
||||
Or, install with yarn
|
||||
|
||||
```sh
|
||||
yarn add @cesium/widgets
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Import individual modules to benefit from tree shaking optimizations through most build tools:
|
||||
|
||||
```js
|
||||
import { Viewer } from "@cesium/widgets";
|
||||
import "@cesium/widgets/Source/widgets.css";
|
||||
|
||||
const viewer = new Viewer("cesiumContainer");
|
||||
```
|
||||
|
||||
See our [Quickstart Guide](https://cesium.com/learn/cesiumjs-learn/cesiumjs-quickstart/) for more information on getting a CesiumJS app up and running.
|
||||
|
||||
## Community
|
||||
|
||||
Have questions? Ask them on the [community forum](https://community.cesium.com/).
|
||||
|
||||
Interested in contributing? See [CONTRIBUTING.md](../../CONTRIBUTING.md). :heart:
|
||||
|
||||
## License
|
||||
|
||||
[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). CesiumJS is free for both commercial and non-commercial use.
|
||||
@@ -0,0 +1,176 @@
|
||||
.cesium-animation-theme {
|
||||
visibility: hidden;
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: -100;
|
||||
}
|
||||
|
||||
.cesium-animation-themeNormal {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.cesium-animation-themeHover {
|
||||
color: #4488b0;
|
||||
}
|
||||
|
||||
.cesium-animation-themeSelect {
|
||||
color: #242;
|
||||
}
|
||||
|
||||
.cesium-animation-themeDisabled {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.cesium-animation-themeKnob {
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.cesium-animation-themePointer {
|
||||
color: #2e2;
|
||||
}
|
||||
|
||||
.cesium-animation-themeSwoosh {
|
||||
color: #8ac;
|
||||
}
|
||||
|
||||
.cesium-animation-themeSwooshHover {
|
||||
color: #aef;
|
||||
}
|
||||
|
||||
.cesium-animation-svgText {
|
||||
fill: #edffff;
|
||||
font-family: Sans-Serif;
|
||||
font-size: 15px;
|
||||
text-anchor: middle;
|
||||
}
|
||||
|
||||
.cesium-animation-blank {
|
||||
fill: #000;
|
||||
fill-opacity: 0.01; /* This must be clickable, so it can't be 'fill: none'. */
|
||||
stroke: none;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton {
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton .cesium-animation-buttonGlow {
|
||||
fill: #fff;
|
||||
stroke: none;
|
||||
/* Widget will add: filter: url(#animation_blurred); */
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton:hover .cesium-animation-buttonGlow {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton .cesium-animation-buttonPath {
|
||||
fill: #edffff;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton .cesium-animation-buttonMain {
|
||||
/* Widget will add: fill: url(#animation_buttonNormal); */
|
||||
stroke: #444;
|
||||
stroke-width: 1.2;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton:hover .cesium-animation-buttonMain {
|
||||
/* Widget will add: fill: url(#animation_buttonHovered); */
|
||||
stroke: #aef;
|
||||
}
|
||||
|
||||
.cesium-animation-rectButton:active .cesium-animation-buttonMain {
|
||||
fill: #abd6ff;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonDisabled {
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonDisabled .cesium-animation-buttonMain {
|
||||
/* Widget will add: fill: url(#animation_buttonDisabled); */
|
||||
stroke: #555;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonDisabled .cesium-animation-buttonPath {
|
||||
fill: #818181;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonDisabled .cesium-animation-buttonGlow {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonToggled .cesium-animation-buttonGlow {
|
||||
display: block;
|
||||
fill: #2e2;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonToggled .cesium-animation-buttonMain {
|
||||
stroke: #2e2;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonToggled:hover .cesium-animation-buttonGlow {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.cesium-animation-buttonToggled:hover .cesium-animation-buttonMain {
|
||||
stroke: #2e2;
|
||||
}
|
||||
|
||||
.cesium-animation-shuttleRingG {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Widget will add:
|
||||
.cesium-animation-shuttleRingG .cesium-animation-shuttleRingSwoosh {
|
||||
fill: url(#animation_shuttleRingSwooshGradient);
|
||||
}
|
||||
|
||||
.cesium-animation-shuttleRingG:hover .cesium-animation-shuttleRingSwoosh {
|
||||
fill: url(#animation_shuttleRingSwooshHovered);
|
||||
}
|
||||
*/
|
||||
|
||||
.cesium-animation-shuttleRingPointer {
|
||||
/* Widget will add: fill: url(#animation_shuttleRingPointerGradient); */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-animation-shuttleRingPausePointer {
|
||||
/* Widget will add: fill: url(#animation_shuttleRingPointerPaused); */
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-animation-shuttleRingBack {
|
||||
fill: #181818;
|
||||
fill-opacity: 0.8;
|
||||
stroke: #333;
|
||||
stroke-width: 1.2;
|
||||
}
|
||||
|
||||
.cesium-animation-shuttleRingSwoosh line {
|
||||
stroke: #8ac;
|
||||
stroke-width: 3;
|
||||
stroke-opacity: 0.2;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
.cesium-animation-knobOuter {
|
||||
/* Widget will add: fill: url(#animation_knobOuter); */
|
||||
cursor: pointer;
|
||||
stroke: #444;
|
||||
stroke-width: 1.2;
|
||||
}
|
||||
|
||||
.cesium-animation-knobInner {
|
||||
/* Widget will add: fill: url(#animation_knobInner); */
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,666 @@
|
||||
import {
|
||||
addAllToArray,
|
||||
binarySearch,
|
||||
ClockRange,
|
||||
ClockStep,
|
||||
defined,
|
||||
DeveloperError,
|
||||
JulianDate,
|
||||
} from "@cesium/engine";
|
||||
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
import ToggleButtonViewModel from "../ToggleButtonViewModel.js";
|
||||
|
||||
const monthNames = [
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
];
|
||||
const realtimeShuttleRingAngle = 15;
|
||||
const maxShuttleRingAngle = 105;
|
||||
|
||||
function numberComparator(left, right) {
|
||||
return left - right;
|
||||
}
|
||||
|
||||
function getTypicalMultiplierIndex(multiplier, shuttleRingTicks) {
|
||||
const index = binarySearch(shuttleRingTicks, multiplier, numberComparator);
|
||||
return index < 0 ? ~index : index;
|
||||
}
|
||||
|
||||
function angleToMultiplier(angle, shuttleRingTicks) {
|
||||
//Use a linear scale for -1 to 1 between -15 < angle < 15 degrees
|
||||
if (Math.abs(angle) <= realtimeShuttleRingAngle) {
|
||||
return angle / realtimeShuttleRingAngle;
|
||||
}
|
||||
|
||||
const minp = realtimeShuttleRingAngle;
|
||||
const maxp = maxShuttleRingAngle;
|
||||
let maxv;
|
||||
const minv = 0;
|
||||
let scale;
|
||||
if (angle > 0) {
|
||||
maxv = Math.log(shuttleRingTicks[shuttleRingTicks.length - 1]);
|
||||
scale = (maxv - minv) / (maxp - minp);
|
||||
return Math.exp(minv + scale * (angle - minp));
|
||||
}
|
||||
|
||||
maxv = Math.log(-shuttleRingTicks[0]);
|
||||
scale = (maxv - minv) / (maxp - minp);
|
||||
return -Math.exp(minv + scale * (Math.abs(angle) - minp));
|
||||
}
|
||||
|
||||
function multiplierToAngle(multiplier, shuttleRingTicks, clockViewModel) {
|
||||
if (clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK) {
|
||||
return realtimeShuttleRingAngle;
|
||||
}
|
||||
|
||||
if (Math.abs(multiplier) <= 1) {
|
||||
return multiplier * realtimeShuttleRingAngle;
|
||||
}
|
||||
|
||||
const fastedMultipler = shuttleRingTicks[shuttleRingTicks.length - 1];
|
||||
if (multiplier > fastedMultipler) {
|
||||
multiplier = fastedMultipler;
|
||||
} else if (multiplier < -fastedMultipler) {
|
||||
multiplier = -fastedMultipler;
|
||||
}
|
||||
|
||||
const minp = realtimeShuttleRingAngle;
|
||||
const maxp = maxShuttleRingAngle;
|
||||
let maxv;
|
||||
const minv = 0;
|
||||
let scale;
|
||||
|
||||
if (multiplier > 0) {
|
||||
maxv = Math.log(fastedMultipler);
|
||||
scale = (maxv - minv) / (maxp - minp);
|
||||
return (Math.log(multiplier) - minv) / scale + minp;
|
||||
}
|
||||
|
||||
maxv = Math.log(-shuttleRingTicks[0]);
|
||||
scale = (maxv - minv) / (maxp - minp);
|
||||
return -((Math.log(Math.abs(multiplier)) - minv) / scale + minp);
|
||||
}
|
||||
|
||||
/**
|
||||
* The view model for the {@link Animation} widget.
|
||||
* @alias AnimationViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {ClockViewModel} clockViewModel The ClockViewModel instance to use.
|
||||
*
|
||||
* @see Animation
|
||||
*/
|
||||
function AnimationViewModel(clockViewModel) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(clockViewModel)) {
|
||||
throw new DeveloperError("clockViewModel is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const that = this;
|
||||
this._clockViewModel = clockViewModel;
|
||||
this._allShuttleRingTicks = [];
|
||||
this._dateFormatter = AnimationViewModel.defaultDateFormatter;
|
||||
this._timeFormatter = AnimationViewModel.defaultTimeFormatter;
|
||||
|
||||
/**
|
||||
* Gets or sets whether the shuttle ring is currently being dragged. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.shuttleRingDragging = false;
|
||||
|
||||
/**
|
||||
* Gets or sets whether dragging the shuttle ring should cause the multiplier
|
||||
* to snap to the defined tick values rather than interpolating between them.
|
||||
* This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.snapToTicks = false;
|
||||
|
||||
knockout.track(this, [
|
||||
"_allShuttleRingTicks",
|
||||
"_dateFormatter",
|
||||
"_timeFormatter",
|
||||
"shuttleRingDragging",
|
||||
"snapToTicks",
|
||||
]);
|
||||
|
||||
this._sortedFilteredPositiveTicks = [];
|
||||
|
||||
this.setShuttleRingTicks(AnimationViewModel.defaultTicks);
|
||||
|
||||
/**
|
||||
* Gets the string representation of the current time. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.timeLabel = undefined;
|
||||
knockout.defineProperty(this, "timeLabel", function () {
|
||||
return that._timeFormatter(that._clockViewModel.currentTime, that);
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the string representation of the current date. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.dateLabel = undefined;
|
||||
knockout.defineProperty(this, "dateLabel", function () {
|
||||
return that._dateFormatter(that._clockViewModel.currentTime, that);
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the string representation of the current multiplier. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.multiplierLabel = undefined;
|
||||
knockout.defineProperty(this, "multiplierLabel", function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
if (clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK) {
|
||||
return "Today";
|
||||
}
|
||||
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
|
||||
//If it's a whole number, just return it.
|
||||
if (multiplier % 1 === 0) {
|
||||
return `${multiplier.toFixed(0)}x`;
|
||||
}
|
||||
|
||||
//Convert to decimal string and remove any trailing zeroes
|
||||
return `${multiplier.toFixed(3).replace(/0{0,3}$/, "")}x`;
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the current shuttle ring angle. This property is observable.
|
||||
* @type {number}
|
||||
*/
|
||||
this.shuttleRingAngle = undefined;
|
||||
knockout.defineProperty(this, "shuttleRingAngle", {
|
||||
get: function () {
|
||||
return multiplierToAngle(
|
||||
clockViewModel.multiplier,
|
||||
that._allShuttleRingTicks,
|
||||
clockViewModel,
|
||||
);
|
||||
},
|
||||
set: function (angle) {
|
||||
angle = Math.max(
|
||||
Math.min(angle, maxShuttleRingAngle),
|
||||
-maxShuttleRingAngle,
|
||||
);
|
||||
const ticks = that._allShuttleRingTicks;
|
||||
|
||||
const clockViewModel = that._clockViewModel;
|
||||
clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK_MULTIPLIER;
|
||||
|
||||
//If we are at the max angle, simply return the max value in either direction.
|
||||
if (Math.abs(angle) === maxShuttleRingAngle) {
|
||||
clockViewModel.multiplier =
|
||||
angle > 0 ? ticks[ticks.length - 1] : ticks[0];
|
||||
return;
|
||||
}
|
||||
|
||||
let multiplier = angleToMultiplier(angle, ticks);
|
||||
if (that.snapToTicks) {
|
||||
multiplier = ticks[getTypicalMultiplierIndex(multiplier, ticks)];
|
||||
} else if (multiplier !== 0) {
|
||||
const positiveMultiplier = Math.abs(multiplier);
|
||||
|
||||
if (positiveMultiplier > 100) {
|
||||
const numDigits = positiveMultiplier.toFixed(0).length - 2;
|
||||
const divisor = Math.pow(10, numDigits);
|
||||
multiplier = (Math.round(multiplier / divisor) * divisor) | 0;
|
||||
} else if (positiveMultiplier > realtimeShuttleRingAngle) {
|
||||
multiplier = Math.round(multiplier);
|
||||
} else if (positiveMultiplier > 1) {
|
||||
multiplier = +multiplier.toFixed(1);
|
||||
} else if (positiveMultiplier > 0) {
|
||||
multiplier = +multiplier.toFixed(2);
|
||||
}
|
||||
}
|
||||
clockViewModel.multiplier = multiplier;
|
||||
},
|
||||
});
|
||||
|
||||
this._canAnimate = undefined;
|
||||
knockout.defineProperty(this, "_canAnimate", function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const clockRange = clockViewModel.clockRange;
|
||||
|
||||
if (that.shuttleRingDragging || clockRange === ClockRange.UNBOUNDED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
const currentTime = clockViewModel.currentTime;
|
||||
const startTime = clockViewModel.startTime;
|
||||
|
||||
let result;
|
||||
if (clockRange === ClockRange.LOOP_STOP) {
|
||||
result =
|
||||
JulianDate.greaterThan(currentTime, startTime) ||
|
||||
(currentTime.equals(startTime) && multiplier > 0);
|
||||
} else {
|
||||
const stopTime = clockViewModel.stopTime;
|
||||
result =
|
||||
(JulianDate.greaterThan(currentTime, startTime) &&
|
||||
JulianDate.lessThan(currentTime, stopTime)) || //
|
||||
(currentTime.equals(startTime) && multiplier > 0) || //
|
||||
(currentTime.equals(stopTime) && multiplier < 0);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
clockViewModel.shouldAnimate = false;
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
this._isSystemTimeAvailable = undefined;
|
||||
knockout.defineProperty(this, "_isSystemTimeAvailable", function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const clockRange = clockViewModel.clockRange;
|
||||
if (clockRange === ClockRange.UNBOUNDED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const systemTime = clockViewModel.systemTime;
|
||||
return (
|
||||
JulianDate.greaterThanOrEquals(systemTime, clockViewModel.startTime) &&
|
||||
JulianDate.lessThanOrEquals(systemTime, clockViewModel.stopTime)
|
||||
);
|
||||
});
|
||||
|
||||
this._isAnimating = undefined;
|
||||
knockout.defineProperty(this, "_isAnimating", function () {
|
||||
return (
|
||||
that._clockViewModel.shouldAnimate &&
|
||||
(that._canAnimate || that.shuttleRingDragging)
|
||||
);
|
||||
});
|
||||
|
||||
const pauseCommand = createCommand(function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
if (clockViewModel.shouldAnimate) {
|
||||
clockViewModel.shouldAnimate = false;
|
||||
} else if (that._canAnimate) {
|
||||
clockViewModel.shouldAnimate = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._pauseViewModel = new ToggleButtonViewModel(pauseCommand, {
|
||||
toggled: knockout.computed(function () {
|
||||
return !that._isAnimating;
|
||||
}),
|
||||
tooltip: "Pause",
|
||||
});
|
||||
|
||||
const playReverseCommand = createCommand(function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
if (multiplier > 0) {
|
||||
clockViewModel.multiplier = -multiplier;
|
||||
}
|
||||
clockViewModel.shouldAnimate = true;
|
||||
});
|
||||
|
||||
this._playReverseViewModel = new ToggleButtonViewModel(playReverseCommand, {
|
||||
toggled: knockout.computed(function () {
|
||||
return that._isAnimating && clockViewModel.multiplier < 0;
|
||||
}),
|
||||
tooltip: "Play Reverse",
|
||||
});
|
||||
|
||||
const playForwardCommand = createCommand(function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
if (multiplier < 0) {
|
||||
clockViewModel.multiplier = -multiplier;
|
||||
}
|
||||
clockViewModel.shouldAnimate = true;
|
||||
});
|
||||
|
||||
this._playForwardViewModel = new ToggleButtonViewModel(playForwardCommand, {
|
||||
toggled: knockout.computed(function () {
|
||||
return (
|
||||
that._isAnimating &&
|
||||
clockViewModel.multiplier > 0 &&
|
||||
clockViewModel.clockStep !== ClockStep.SYSTEM_CLOCK
|
||||
);
|
||||
}),
|
||||
tooltip: "Play Forward",
|
||||
});
|
||||
|
||||
const playRealtimeCommand = createCommand(
|
||||
function () {
|
||||
that._clockViewModel.clockStep = ClockStep.SYSTEM_CLOCK;
|
||||
},
|
||||
knockout.getObservable(this, "_isSystemTimeAvailable"),
|
||||
);
|
||||
|
||||
this._playRealtimeViewModel = new ToggleButtonViewModel(playRealtimeCommand, {
|
||||
toggled: knockout.computed(function () {
|
||||
return clockViewModel.clockStep === ClockStep.SYSTEM_CLOCK;
|
||||
}),
|
||||
tooltip: knockout.computed(function () {
|
||||
return that._isSystemTimeAvailable
|
||||
? "Today (real-time)"
|
||||
: "Current time not in range";
|
||||
}),
|
||||
});
|
||||
|
||||
this._slower = createCommand(function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const shuttleRingTicks = that._allShuttleRingTicks;
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
const index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) - 1;
|
||||
if (index >= 0) {
|
||||
clockViewModel.multiplier = shuttleRingTicks[index];
|
||||
}
|
||||
});
|
||||
|
||||
this._faster = createCommand(function () {
|
||||
const clockViewModel = that._clockViewModel;
|
||||
const shuttleRingTicks = that._allShuttleRingTicks;
|
||||
const multiplier = clockViewModel.multiplier;
|
||||
const index = getTypicalMultiplierIndex(multiplier, shuttleRingTicks) + 1;
|
||||
if (index < shuttleRingTicks.length) {
|
||||
clockViewModel.multiplier = shuttleRingTicks[index];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or sets the default date formatter used by new instances.
|
||||
*
|
||||
* @member
|
||||
* @type {AnimationViewModel.DateFormatter}
|
||||
*/
|
||||
AnimationViewModel.defaultDateFormatter = function (date, viewModel) {
|
||||
const gregorianDate = JulianDate.toGregorianDate(date);
|
||||
return `${monthNames[gregorianDate.month - 1]} ${gregorianDate.day} ${
|
||||
gregorianDate.year
|
||||
}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets or sets the default array of known clock multipliers associated with new instances of the shuttle ring.
|
||||
* @type {number[]}
|
||||
*/
|
||||
AnimationViewModel.defaultTicks = [
|
||||
//
|
||||
0.001,
|
||||
0.002,
|
||||
0.005,
|
||||
0.01,
|
||||
0.02,
|
||||
0.05,
|
||||
0.1,
|
||||
0.25,
|
||||
0.5,
|
||||
1.0,
|
||||
2.0,
|
||||
5.0,
|
||||
10.0, //
|
||||
15.0,
|
||||
30.0,
|
||||
60.0,
|
||||
120.0,
|
||||
300.0,
|
||||
600.0,
|
||||
900.0,
|
||||
1800.0,
|
||||
3600.0,
|
||||
7200.0,
|
||||
14400.0, //
|
||||
21600.0,
|
||||
43200.0,
|
||||
86400.0,
|
||||
172800.0,
|
||||
345600.0,
|
||||
604800.0,
|
||||
];
|
||||
|
||||
/**
|
||||
* Gets or sets the default time formatter used by new instances.
|
||||
*
|
||||
* @member
|
||||
* @type {AnimationViewModel.TimeFormatter}
|
||||
*/
|
||||
AnimationViewModel.defaultTimeFormatter = function (date, viewModel) {
|
||||
const gregorianDate = JulianDate.toGregorianDate(date);
|
||||
const millisecond = Math.round(gregorianDate.millisecond);
|
||||
if (Math.abs(viewModel._clockViewModel.multiplier) < 1) {
|
||||
return `${gregorianDate.hour
|
||||
.toString()
|
||||
.padStart(2, "0")}:${gregorianDate.minute
|
||||
.toString()
|
||||
.padStart(2, "0")}:${gregorianDate.second
|
||||
.toString()
|
||||
.padStart(2, "0")}.${millisecond.toString().padStart(3, "0")}`;
|
||||
}
|
||||
return `${gregorianDate.hour
|
||||
.toString()
|
||||
.padStart(2, "0")}:${gregorianDate.minute
|
||||
.toString()
|
||||
.padStart(2, "0")}:${gregorianDate.second.toString().padStart(2, "0")} UTC`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets a copy of the array of positive known clock multipliers to associate with the shuttle ring.
|
||||
*
|
||||
* @returns {number[]} The array of known clock multipliers associated with the shuttle ring.
|
||||
*/
|
||||
AnimationViewModel.prototype.getShuttleRingTicks = function () {
|
||||
return this._sortedFilteredPositiveTicks.slice(0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the array of positive known clock multipliers to associate with the shuttle ring.
|
||||
* These values will have negative equivalents created for them and sets both the minimum
|
||||
* and maximum range of values for the shuttle ring as well as the values that are snapped
|
||||
* to when a single click is made. The values need not be in order, as they will be sorted
|
||||
* automatically, and duplicate values will be removed.
|
||||
*
|
||||
* @param {number[]} positiveTicks The list of known positive clock multipliers to associate with the shuttle ring.
|
||||
*/
|
||||
AnimationViewModel.prototype.setShuttleRingTicks = function (positiveTicks) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(positiveTicks)) {
|
||||
throw new DeveloperError("positiveTicks is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
let i;
|
||||
let len;
|
||||
let tick;
|
||||
|
||||
const hash = {};
|
||||
const sortedFilteredPositiveTicks = this._sortedFilteredPositiveTicks;
|
||||
sortedFilteredPositiveTicks.length = 0;
|
||||
for (i = 0, len = positiveTicks.length; i < len; ++i) {
|
||||
tick = positiveTicks[i];
|
||||
//filter duplicates
|
||||
if (!hash.hasOwnProperty(tick)) {
|
||||
hash[tick] = true;
|
||||
sortedFilteredPositiveTicks.push(tick);
|
||||
}
|
||||
}
|
||||
sortedFilteredPositiveTicks.sort(numberComparator);
|
||||
|
||||
const allTicks = [];
|
||||
for (len = sortedFilteredPositiveTicks.length, i = len - 1; i >= 0; --i) {
|
||||
tick = sortedFilteredPositiveTicks[i];
|
||||
if (tick !== 0) {
|
||||
allTicks.push(-tick);
|
||||
}
|
||||
}
|
||||
addAllToArray(allTicks, sortedFilteredPositiveTicks);
|
||||
|
||||
this._allShuttleRingTicks = allTicks;
|
||||
};
|
||||
|
||||
Object.defineProperties(AnimationViewModel.prototype, {
|
||||
/**
|
||||
* Gets a command that decreases the speed of animation.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
* @type {Command}
|
||||
*/
|
||||
slower: {
|
||||
get: function () {
|
||||
return this._slower;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a command that increases the speed of animation.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
* @type {Command}
|
||||
*/
|
||||
faster: {
|
||||
get: function () {
|
||||
return this._faster;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the clock view model.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {ClockViewModel}
|
||||
*/
|
||||
clockViewModel: {
|
||||
get: function () {
|
||||
return this._clockViewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the pause toggle button view model.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {ToggleButtonViewModel}
|
||||
*/
|
||||
pauseViewModel: {
|
||||
get: function () {
|
||||
return this._pauseViewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the reverse toggle button view model.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {ToggleButtonViewModel}
|
||||
*/
|
||||
playReverseViewModel: {
|
||||
get: function () {
|
||||
return this._playReverseViewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the play toggle button view model.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {ToggleButtonViewModel}
|
||||
*/
|
||||
playForwardViewModel: {
|
||||
get: function () {
|
||||
return this._playForwardViewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the realtime toggle button view model.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {ToggleButtonViewModel}
|
||||
*/
|
||||
playRealtimeViewModel: {
|
||||
get: function () {
|
||||
return this._playRealtimeViewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the function which formats a date for display.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {AnimationViewModel.DateFormatter}
|
||||
* @default AnimationViewModel.defaultDateFormatter
|
||||
*/
|
||||
dateFormatter: {
|
||||
//TODO:@exception {DeveloperError} dateFormatter must be a function.
|
||||
get: function () {
|
||||
return this._dateFormatter;
|
||||
},
|
||||
set: function (dateFormatter) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (typeof dateFormatter !== "function") {
|
||||
throw new DeveloperError("dateFormatter must be a function");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._dateFormatter = dateFormatter;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the function which formats a time for display.
|
||||
* @memberof AnimationViewModel.prototype
|
||||
*
|
||||
* @type {AnimationViewModel.TimeFormatter}
|
||||
* @default AnimationViewModel.defaultTimeFormatter
|
||||
*/
|
||||
timeFormatter: {
|
||||
//TODO:@exception {DeveloperError} timeFormatter must be a function.
|
||||
get: function () {
|
||||
return this._timeFormatter;
|
||||
},
|
||||
set: function (timeFormatter) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (typeof timeFormatter !== "function") {
|
||||
throw new DeveloperError("timeFormatter must be a function");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._timeFormatter = timeFormatter;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//Currently exposed for tests.
|
||||
AnimationViewModel._maxShuttleRingAngle = maxShuttleRingAngle;
|
||||
AnimationViewModel._realtimeShuttleRingAngle = realtimeShuttleRingAngle;
|
||||
|
||||
/**
|
||||
* A function that formats a date for display.
|
||||
* @callback AnimationViewModel.DateFormatter
|
||||
*
|
||||
* @param {JulianDate} date The date to be formatted
|
||||
* @param {AnimationViewModel} viewModel The AnimationViewModel instance requesting formatting.
|
||||
* @returns {string} The string representation of the calendar date portion of the provided date.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that formats a time for display.
|
||||
* @callback AnimationViewModel.TimeFormatter
|
||||
*
|
||||
* @param {JulianDate} date The date to be formatted
|
||||
* @param {AnimationViewModel} viewModel The AnimationViewModel instance requesting formatting.
|
||||
* @returns {string} The string representation of the time portion of the provided date.
|
||||
*/
|
||||
export default AnimationViewModel;
|
||||
@@ -0,0 +1,99 @@
|
||||
.cesium-lighter .cesium-animation-themeNormal {
|
||||
color: #e5f2fe;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeHover {
|
||||
color: #abd6ff;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeSelect {
|
||||
color: #e5f2fe;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeDisabled {
|
||||
color: #efefef;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeKnob {
|
||||
color: #e1e2e3;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themePointer {
|
||||
color: #fa5;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeSwoosh {
|
||||
color: #ace;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-themeSwooshHover {
|
||||
color: #bdf;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-svgText {
|
||||
fill: #111;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-rectButton .cesium-animation-buttonPath {
|
||||
fill: #111;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-rectButton .cesium-animation-buttonMain {
|
||||
stroke: #759dc0;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-buttonToggled .cesium-animation-buttonGlow {
|
||||
fill: #ffaa2a;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-buttonToggled .cesium-animation-buttonMain {
|
||||
/* Widget will add: fill: url(#animation_buttonToggled); */
|
||||
stroke: #ea0;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-animation-rectButton:hover
|
||||
.cesium-animation-buttonMain {
|
||||
stroke: #759dc0;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-animation-buttonToggled:hover
|
||||
.cesium-animation-buttonGlow {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-animation-buttonToggled:hover
|
||||
.cesium-animation-buttonMain {
|
||||
stroke: #ea0;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-animation-rectButton:active
|
||||
.cesium-animation-buttonMain {
|
||||
fill: #abd6ff;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-buttonDisabled .cesium-animation-buttonMain {
|
||||
stroke: #d3d3d3;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-buttonDisabled .cesium-animation-buttonPath {
|
||||
fill: #818181;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-shuttleRingBack {
|
||||
fill: #fafafa;
|
||||
fill-opacity: 1;
|
||||
stroke: #aeaeae;
|
||||
stroke-width: 1.2;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-shuttleRingSwoosh line {
|
||||
stroke: #8ac;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-animation-knobOuter {
|
||||
stroke: #a5a5a5;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
.cesium-baseLayerPicker-selected {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-dropDown {
|
||||
display: block;
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
top: auto;
|
||||
right: 0;
|
||||
width: 320px; /* Includes space needed for scrollbar */
|
||||
max-height: 500px;
|
||||
margin-top: 5px;
|
||||
background-color: rgba(38, 38, 38, 0.75);
|
||||
border: 1px solid #444;
|
||||
padding: 6px;
|
||||
overflow: auto;
|
||||
border-radius: 10px;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
transform: translate(0, -20%);
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
visibility 0s 0.2s,
|
||||
opacity 0.2s ease-in,
|
||||
transform 0.2s ease-in;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-dropDown-visible {
|
||||
transform: translate(0, 0);
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition:
|
||||
opacity 0.2s ease-out,
|
||||
transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-sectionTitle {
|
||||
display: block;
|
||||
font-family: sans-serif;
|
||||
font-size: 16pt;
|
||||
text-align: left;
|
||||
color: #edffff;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-choices {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-categoryTitle {
|
||||
color: #edffff;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-choices {
|
||||
display: block;
|
||||
border: 1px solid #888;
|
||||
border-radius: 5px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-item {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin: 2px 5px;
|
||||
width: 64px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-itemLabel {
|
||||
display: block;
|
||||
font-family: sans-serif;
|
||||
font-size: 8pt;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: #edffff;
|
||||
cursor: pointer;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-item:hover .cesium-baseLayerPicker-itemLabel,
|
||||
.cesium-baseLayerPicker-item:focus .cesium-baseLayerPicker-itemLabel {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-itemIcon {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: inherit;
|
||||
height: auto;
|
||||
background-size: 100% 100%;
|
||||
border: solid 1px #444;
|
||||
border-radius: 9px;
|
||||
color: #edffff;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-item:hover .cesium-baseLayerPicker-itemIcon {
|
||||
border-color: #fff;
|
||||
box-shadow:
|
||||
0 0 8px #fff,
|
||||
0 0 8px #fff;
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-selectedItem .cesium-baseLayerPicker-itemLabel {
|
||||
color: rgb(189, 236, 248);
|
||||
}
|
||||
|
||||
.cesium-baseLayerPicker-selectedItem .cesium-baseLayerPicker-itemIcon {
|
||||
border: double 4px rgb(189, 236, 248);
|
||||
}
|
||||
@@ -0,0 +1,312 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import BaseLayerPickerViewModel from "./BaseLayerPickerViewModel.js";
|
||||
|
||||
/**
|
||||
* <span style="display: block; text-align: center;">
|
||||
* <img src="Images/BaseLayerPicker.png" width="264" alt="BaseLayerPicker" />
|
||||
* <br />BaseLayerPicker with its drop-panel open.
|
||||
* </span>
|
||||
* <br /><br />
|
||||
* The BaseLayerPicker is a single button widget that displays a panel of available imagery and
|
||||
* terrain providers. When imagery is selected, the corresponding imagery layer is created and inserted
|
||||
* as the base layer of the imagery collection; removing the existing base. When terrain is selected,
|
||||
* it replaces the current terrain provider. Each item in the available providers list contains a name,
|
||||
* a representative icon, and a tooltip to display more information when hovered. The list is initially
|
||||
* empty, and must be configured before use, as illustrated in the below example.
|
||||
* <br /><br />
|
||||
* By default, the BaseLayerPicker uses a default list of example providers for demonstration purposes.
|
||||
* Notably some of these providers, such as <a href="https://developers.arcgis.com" target="_blank">Esri ArcGIS</a> and <a href="https://docs.stadiamaps.com/ target="_blank">Stadia Maps</a>, have seperate terms of service and require authentication for production use.
|
||||
*
|
||||
* @alias BaseLayerPicker
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The parent HTML container node or ID for this widget.
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Globe} options.globe The Globe to use.
|
||||
* @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
|
||||
* @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used.
|
||||
* @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
|
||||
* @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* // In HTML head, include a link to the BaseLayerPicker.css stylesheet,
|
||||
* // and in the body, include: <div id="baseLayerPickerContainer"
|
||||
* // style="position:absolute;top:24px;right:24px;width:38px;height:38px;"></div>
|
||||
*
|
||||
* //Create the list of available providers we would like the user to select from.
|
||||
* //This example uses 3, OpenStreetMap, The Black Marble, and a single, non-streaming world image.
|
||||
* const imageryViewModels = [];
|
||||
* imageryViewModels.push(new Cesium.ProviderViewModel({
|
||||
* name: "Open\u00adStreet\u00adMap",
|
||||
* iconUrl: Cesium.buildModuleUrl("Widgets/Images/ImageryProviders/openStreetMap.png"),
|
||||
* tooltip: "OpenStreetMap (OSM) is a collaborative project to create a free editable \
|
||||
* map of the world.\nhttp://www.openstreetmap.org",
|
||||
* creationFunction: function() {
|
||||
* return new Cesium.OpenStreetMapImageryProvider({
|
||||
* url: "https://tile.openstreetmap.org/"
|
||||
* });
|
||||
* }
|
||||
* }));
|
||||
*
|
||||
* imageryViewModels.push(new Cesium.ProviderViewModel({
|
||||
* name: "Earth at Night",
|
||||
* iconUrl: Cesium.buildModuleUrl("Widgets/Images/ImageryProviders/blackMarble.png"),
|
||||
* tooltip: "The lights of cities and villages trace the outlines of civilization \
|
||||
* in this global view of the Earth at night as seen by NASA/NOAA's Suomi NPP satellite.",
|
||||
* creationFunction: function() {
|
||||
* return Cesium.IonImageryProvider.fromAssetId(3812);
|
||||
* }
|
||||
* }));
|
||||
*
|
||||
* imageryViewModels.push(new Cesium.ProviderViewModel({
|
||||
* name: "Natural Earth\u00a0II",
|
||||
* iconUrl: Cesium.buildModuleUrl("Widgets/Images/ImageryProviders/naturalEarthII.png"),
|
||||
* tooltip: "Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/",
|
||||
* creationFunction: function() {
|
||||
* return Cesium.TileMapServiceImageryProvider.fromUrl(
|
||||
* Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII")
|
||||
* );
|
||||
* }
|
||||
* }));
|
||||
*
|
||||
* //Create a CesiumWidget without imagery, if you haven't already done so.
|
||||
* const cesiumWidget = new Cesium.CesiumWidget("cesiumContainer", { baseLayer: false });
|
||||
*
|
||||
* //Finally, create the baseLayerPicker widget using our view models.
|
||||
* const layers = cesiumWidget.imageryLayers;
|
||||
* const baseLayerPicker = new Cesium.BaseLayerPicker("baseLayerPickerContainer", {
|
||||
* globe: cesiumWidget.scene.globe,
|
||||
* imageryProviderViewModels: imageryViewModels
|
||||
* });
|
||||
*
|
||||
* @see TerrainProvider
|
||||
* @see ImageryProvider
|
||||
* @see ImageryLayerCollection
|
||||
*/
|
||||
function BaseLayerPicker(container, options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const viewModel = new BaseLayerPickerViewModel(options);
|
||||
|
||||
const element = document.createElement("button");
|
||||
element.type = "button";
|
||||
element.className = "cesium-button cesium-toolbar-button";
|
||||
element.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
attr: { title: buttonTooltip },\
|
||||
click: toggleDropDown",
|
||||
);
|
||||
container.appendChild(element);
|
||||
|
||||
const imgElement = document.createElement("img");
|
||||
imgElement.setAttribute("draggable", "false");
|
||||
imgElement.className = "cesium-baseLayerPicker-selected";
|
||||
imgElement.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
attr: { src: buttonImageUrl }, visible: !!buttonImageUrl",
|
||||
);
|
||||
element.appendChild(imgElement);
|
||||
|
||||
const dropPanel = document.createElement("div");
|
||||
dropPanel.className = "cesium-baseLayerPicker-dropDown";
|
||||
dropPanel.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-baseLayerPicker-dropDown-visible" : dropDownVisible }',
|
||||
);
|
||||
container.appendChild(dropPanel);
|
||||
|
||||
const imageryTitle = document.createElement("div");
|
||||
imageryTitle.className = "cesium-baseLayerPicker-sectionTitle";
|
||||
imageryTitle.setAttribute(
|
||||
"data-bind",
|
||||
"visible: imageryProviderViewModels.length > 0",
|
||||
);
|
||||
imageryTitle.innerHTML = "Imagery";
|
||||
dropPanel.appendChild(imageryTitle);
|
||||
|
||||
const imagerySection = document.createElement("div");
|
||||
imagerySection.className = "cesium-baseLayerPicker-section";
|
||||
imagerySection.setAttribute("data-bind", "foreach: _imageryProviders");
|
||||
dropPanel.appendChild(imagerySection);
|
||||
|
||||
const imageryCategories = document.createElement("div");
|
||||
imageryCategories.className = "cesium-baseLayerPicker-category";
|
||||
imagerySection.appendChild(imageryCategories);
|
||||
|
||||
const categoryTitle = document.createElement("div");
|
||||
categoryTitle.className = "cesium-baseLayerPicker-categoryTitle";
|
||||
categoryTitle.setAttribute("data-bind", "text: name");
|
||||
imageryCategories.appendChild(categoryTitle);
|
||||
|
||||
const imageryChoices = document.createElement("div");
|
||||
imageryChoices.className = "cesium-baseLayerPicker-choices";
|
||||
imageryChoices.setAttribute("data-bind", "foreach: providers");
|
||||
imageryCategories.appendChild(imageryChoices);
|
||||
|
||||
const imageryProvider = document.createElement("div");
|
||||
imageryProvider.className = "cesium-baseLayerPicker-item";
|
||||
imageryProvider.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-baseLayerPicker-selectedItem" : $data === $parents[1].selectedImagery },\
|
||||
attr: { title: tooltip },\
|
||||
visible: creationCommand.canExecute,\
|
||||
click: function($data) { $parents[1].selectedImagery = $data; }',
|
||||
);
|
||||
imageryChoices.appendChild(imageryProvider);
|
||||
|
||||
const providerIcon = document.createElement("img");
|
||||
providerIcon.className = "cesium-baseLayerPicker-itemIcon";
|
||||
providerIcon.setAttribute("data-bind", "attr: { src: iconUrl }");
|
||||
providerIcon.setAttribute("draggable", "false");
|
||||
imageryProvider.appendChild(providerIcon);
|
||||
|
||||
const providerLabel = document.createElement("div");
|
||||
providerLabel.className = "cesium-baseLayerPicker-itemLabel";
|
||||
providerLabel.setAttribute("data-bind", "text: name");
|
||||
imageryProvider.appendChild(providerLabel);
|
||||
|
||||
const terrainTitle = document.createElement("div");
|
||||
terrainTitle.className = "cesium-baseLayerPicker-sectionTitle";
|
||||
terrainTitle.setAttribute(
|
||||
"data-bind",
|
||||
"visible: terrainProviderViewModels.length > 0",
|
||||
);
|
||||
terrainTitle.innerHTML = "Terrain";
|
||||
dropPanel.appendChild(terrainTitle);
|
||||
|
||||
const terrainSection = document.createElement("div");
|
||||
terrainSection.className = "cesium-baseLayerPicker-section";
|
||||
terrainSection.setAttribute("data-bind", "foreach: _terrainProviders");
|
||||
dropPanel.appendChild(terrainSection);
|
||||
|
||||
const terrainCategories = document.createElement("div");
|
||||
terrainCategories.className = "cesium-baseLayerPicker-category";
|
||||
terrainSection.appendChild(terrainCategories);
|
||||
|
||||
const terrainCategoryTitle = document.createElement("div");
|
||||
terrainCategoryTitle.className = "cesium-baseLayerPicker-categoryTitle";
|
||||
terrainCategoryTitle.setAttribute("data-bind", "text: name");
|
||||
terrainCategories.appendChild(terrainCategoryTitle);
|
||||
|
||||
const terrainChoices = document.createElement("div");
|
||||
terrainChoices.className = "cesium-baseLayerPicker-choices";
|
||||
terrainChoices.setAttribute("data-bind", "foreach: providers");
|
||||
terrainCategories.appendChild(terrainChoices);
|
||||
|
||||
const terrainProvider = document.createElement("div");
|
||||
terrainProvider.className = "cesium-baseLayerPicker-item";
|
||||
terrainProvider.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-baseLayerPicker-selectedItem" : $data === $parents[1].selectedTerrain },\
|
||||
attr: { title: tooltip },\
|
||||
visible: creationCommand.canExecute,\
|
||||
click: function($data) { $parents[1].selectedTerrain = $data; }',
|
||||
);
|
||||
terrainChoices.appendChild(terrainProvider);
|
||||
|
||||
const terrainProviderIcon = document.createElement("img");
|
||||
terrainProviderIcon.className = "cesium-baseLayerPicker-itemIcon";
|
||||
terrainProviderIcon.setAttribute("data-bind", "attr: { src: iconUrl }");
|
||||
terrainProviderIcon.setAttribute("draggable", "false");
|
||||
terrainProvider.appendChild(terrainProviderIcon);
|
||||
|
||||
const terrainProviderLabel = document.createElement("div");
|
||||
terrainProviderLabel.className = "cesium-baseLayerPicker-itemLabel";
|
||||
terrainProviderLabel.setAttribute("data-bind", "text: name");
|
||||
terrainProvider.appendChild(terrainProviderLabel);
|
||||
|
||||
knockout.applyBindings(viewModel, element);
|
||||
knockout.applyBindings(viewModel, dropPanel);
|
||||
|
||||
this._viewModel = viewModel;
|
||||
this._container = container;
|
||||
this._element = element;
|
||||
this._dropPanel = dropPanel;
|
||||
|
||||
this._closeDropDown = function (e) {
|
||||
if (!(element.contains(e.target) || dropPanel.contains(e.target))) {
|
||||
viewModel.dropDownVisible = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._closeDropDown, true);
|
||||
document.addEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(BaseLayerPicker.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof BaseLayerPicker.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof BaseLayerPicker.prototype
|
||||
*
|
||||
* @type {BaseLayerPickerViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
BaseLayerPicker.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
BaseLayerPicker.prototype.destroy = function () {
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._closeDropDown, true);
|
||||
document.removeEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
|
||||
knockout.cleanNode(this._element);
|
||||
knockout.cleanNode(this._dropPanel);
|
||||
this._container.removeChild(this._element);
|
||||
this._container.removeChild(this._dropPanel);
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default BaseLayerPicker;
|
||||
@@ -0,0 +1,331 @@
|
||||
import {
|
||||
Frozen,
|
||||
defined,
|
||||
DeveloperError,
|
||||
EllipsoidTerrainProvider,
|
||||
ImageryLayer,
|
||||
Terrain,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link BaseLayerPicker}.
|
||||
* @alias BaseLayerPickerViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Globe} options.globe The Globe to use.
|
||||
* @param {ProviderViewModel[]} [options.imageryProviderViewModels=[]] The array of ProviderViewModel instances to use for imagery.
|
||||
* @param {ProviderViewModel} [options.selectedImageryProviderViewModel] The view model for the current base imagery layer, if not supplied the first available imagery layer is used.
|
||||
* @param {ProviderViewModel[]} [options.terrainProviderViewModels=[]] The array of ProviderViewModel instances to use for terrain.
|
||||
* @param {ProviderViewModel} [options.selectedTerrainProviderViewModel] The view model for the current base terrain layer, if not supplied the first available terrain layer is used.
|
||||
*
|
||||
* @exception {DeveloperError} imageryProviderViewModels must be an array.
|
||||
* @exception {DeveloperError} terrainProviderViewModels must be an array.
|
||||
*/
|
||||
function BaseLayerPickerViewModel(options) {
|
||||
options = options ?? Frozen.EMPTY_OBJECT;
|
||||
|
||||
const globe = options.globe;
|
||||
const imageryProviderViewModels =
|
||||
options.imageryProviderViewModels ?? Frozen.EMPTY_ARRAY;
|
||||
const terrainProviderViewModels =
|
||||
options.terrainProviderViewModels ?? Frozen.EMPTY_ARRAY;
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(globe)) {
|
||||
throw new DeveloperError("globe is required");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._globe = globe;
|
||||
|
||||
/**
|
||||
* Gets or sets an array of ProviderViewModel instances available for imagery selection.
|
||||
* This property is observable.
|
||||
* @type {ProviderViewModel[]}
|
||||
*/
|
||||
this.imageryProviderViewModels = imageryProviderViewModels.slice(0);
|
||||
|
||||
/**
|
||||
* Gets or sets an array of ProviderViewModel instances available for terrain selection.
|
||||
* This property is observable.
|
||||
* @type {ProviderViewModel[]}
|
||||
*/
|
||||
this.terrainProviderViewModels = terrainProviderViewModels.slice(0);
|
||||
|
||||
/**
|
||||
* Gets or sets whether the imagery selection drop-down is currently visible.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.dropDownVisible = false;
|
||||
|
||||
knockout.track(this, [
|
||||
"imageryProviderViewModels",
|
||||
"terrainProviderViewModels",
|
||||
"dropDownVisible",
|
||||
]);
|
||||
|
||||
const imageryObservable = knockout.getObservable(
|
||||
this,
|
||||
"imageryProviderViewModels",
|
||||
);
|
||||
const imageryProviders = knockout.pureComputed(function () {
|
||||
const providers = imageryObservable();
|
||||
const categories = {};
|
||||
let i;
|
||||
for (i = 0; i < providers.length; i++) {
|
||||
const provider = providers[i];
|
||||
const category = provider.category;
|
||||
if (defined(categories[category])) {
|
||||
categories[category].push(provider);
|
||||
} else {
|
||||
categories[category] = [provider];
|
||||
}
|
||||
}
|
||||
const allCategoryNames = Object.keys(categories);
|
||||
|
||||
const result = [];
|
||||
for (i = 0; i < allCategoryNames.length; i++) {
|
||||
const name = allCategoryNames[i];
|
||||
result.push({
|
||||
name: name,
|
||||
providers: categories[name],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
this._imageryProviders = imageryProviders;
|
||||
|
||||
const terrainObservable = knockout.getObservable(
|
||||
this,
|
||||
"terrainProviderViewModels",
|
||||
);
|
||||
const terrainProviders = knockout.pureComputed(function () {
|
||||
const providers = terrainObservable();
|
||||
const categories = {};
|
||||
let i;
|
||||
for (i = 0; i < providers.length; i++) {
|
||||
const provider = providers[i];
|
||||
const category = provider.category;
|
||||
if (defined(categories[category])) {
|
||||
categories[category].push(provider);
|
||||
} else {
|
||||
categories[category] = [provider];
|
||||
}
|
||||
}
|
||||
const allCategoryNames = Object.keys(categories);
|
||||
|
||||
const result = [];
|
||||
for (i = 0; i < allCategoryNames.length; i++) {
|
||||
const name = allCategoryNames[i];
|
||||
result.push({
|
||||
name: name,
|
||||
providers: categories[name],
|
||||
});
|
||||
}
|
||||
return result;
|
||||
});
|
||||
this._terrainProviders = terrainProviders;
|
||||
|
||||
/**
|
||||
* Gets the button tooltip. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.buttonTooltip = undefined;
|
||||
knockout.defineProperty(this, "buttonTooltip", function () {
|
||||
const selectedImagery = this.selectedImagery;
|
||||
const selectedTerrain = this.selectedTerrain;
|
||||
|
||||
const imageryTip = defined(selectedImagery)
|
||||
? selectedImagery.name
|
||||
: undefined;
|
||||
const terrainTip = defined(selectedTerrain)
|
||||
? selectedTerrain.name
|
||||
: undefined;
|
||||
|
||||
if (defined(imageryTip) && defined(terrainTip)) {
|
||||
return `${imageryTip}\n${terrainTip}`;
|
||||
} else if (defined(imageryTip)) {
|
||||
return imageryTip;
|
||||
}
|
||||
return terrainTip;
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the button background image. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.buttonImageUrl = undefined;
|
||||
knockout.defineProperty(this, "buttonImageUrl", function () {
|
||||
const selectedImagery = this.selectedImagery;
|
||||
if (defined(selectedImagery)) {
|
||||
return selectedImagery.iconUrl;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the currently selected imagery. This property is observable.
|
||||
* @type {ProviderViewModel}
|
||||
* @default undefined
|
||||
*/
|
||||
this.selectedImagery = undefined;
|
||||
const selectedImageryViewModel = knockout.observable();
|
||||
|
||||
this._currentImageryLayers = [];
|
||||
knockout.defineProperty(this, "selectedImagery", {
|
||||
get: function () {
|
||||
return selectedImageryViewModel();
|
||||
},
|
||||
set: function (value) {
|
||||
if (selectedImageryViewModel() === value) {
|
||||
this.dropDownVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let i;
|
||||
const currentImageryLayers = this._currentImageryLayers;
|
||||
const currentImageryLayersLength = currentImageryLayers.length;
|
||||
const imageryLayers = this._globe.imageryLayers;
|
||||
let hadExistingBaseLayer = false;
|
||||
for (i = 0; i < currentImageryLayersLength; i++) {
|
||||
const layersLength = imageryLayers.length;
|
||||
for (let x = 0; x < layersLength; x++) {
|
||||
const layer = imageryLayers.get(x);
|
||||
if (layer === currentImageryLayers[i]) {
|
||||
imageryLayers.remove(layer);
|
||||
hadExistingBaseLayer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (defined(value)) {
|
||||
const newProviders = value.creationCommand();
|
||||
if (Array.isArray(newProviders)) {
|
||||
const newProvidersLength = newProviders.length;
|
||||
this._currentImageryLayers = [];
|
||||
for (i = newProvidersLength - 1; i >= 0; i--) {
|
||||
const layer = ImageryLayer.fromProviderAsync(newProviders[i]);
|
||||
imageryLayers.add(layer, 0);
|
||||
this._currentImageryLayers.push(layer);
|
||||
}
|
||||
} else {
|
||||
this._currentImageryLayers = [];
|
||||
const layer = ImageryLayer.fromProviderAsync(newProviders);
|
||||
layer.name = value.name;
|
||||
if (hadExistingBaseLayer) {
|
||||
imageryLayers.add(layer, 0);
|
||||
} else {
|
||||
const baseLayer = imageryLayers.get(0);
|
||||
if (defined(baseLayer)) {
|
||||
imageryLayers.remove(baseLayer);
|
||||
}
|
||||
imageryLayers.add(layer, 0);
|
||||
}
|
||||
this._currentImageryLayers.push(layer);
|
||||
}
|
||||
}
|
||||
selectedImageryViewModel(value);
|
||||
this.dropDownVisible = false;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the currently selected terrain. This property is observable.
|
||||
* @type {ProviderViewModel}
|
||||
* @default undefined
|
||||
*/
|
||||
this.selectedTerrain = undefined;
|
||||
const selectedTerrainViewModel = knockout.observable();
|
||||
|
||||
knockout.defineProperty(this, "selectedTerrain", {
|
||||
get: function () {
|
||||
return selectedTerrainViewModel();
|
||||
},
|
||||
set: function (value) {
|
||||
if (selectedTerrainViewModel() === value) {
|
||||
this.dropDownVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let newProvider;
|
||||
if (defined(value)) {
|
||||
newProvider = value.creationCommand();
|
||||
}
|
||||
|
||||
// If this is not a promise, we must set this synchronously to avoid overriding depthTestAgainstTerrain
|
||||
// See https://github.com/CesiumGS/cesium/issues/6991
|
||||
if (defined(newProvider) && !defined(newProvider.then)) {
|
||||
this._globe.depthTestAgainstTerrain = !(
|
||||
newProvider instanceof EllipsoidTerrainProvider
|
||||
);
|
||||
this._globe.terrainProvider = newProvider;
|
||||
} else if (defined(newProvider)) {
|
||||
let cancelUpdate = false;
|
||||
const removeCancelListener =
|
||||
this._globe.terrainProviderChanged.addEventListener(() => {
|
||||
cancelUpdate = true;
|
||||
removeCancelListener();
|
||||
});
|
||||
|
||||
const terrain = new Terrain(newProvider);
|
||||
const removeEventListener = terrain.readyEvent.addEventListener(
|
||||
(terrainProvider) => {
|
||||
if (cancelUpdate) {
|
||||
// Early return in case something has changed outside of the picker.
|
||||
return;
|
||||
}
|
||||
|
||||
this._globe.depthTestAgainstTerrain = !(
|
||||
terrainProvider instanceof EllipsoidTerrainProvider
|
||||
);
|
||||
this._globe.terrainProvider = terrainProvider;
|
||||
removeEventListener();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
selectedTerrainViewModel(value);
|
||||
this.dropDownVisible = false;
|
||||
},
|
||||
});
|
||||
|
||||
const that = this;
|
||||
this._toggleDropDown = createCommand(function () {
|
||||
that.dropDownVisible = !that.dropDownVisible;
|
||||
});
|
||||
|
||||
this.selectedImagery =
|
||||
options.selectedImageryProviderViewModel ?? imageryProviderViewModels[0];
|
||||
this.selectedTerrain = options.selectedTerrainProviderViewModel;
|
||||
}
|
||||
|
||||
Object.defineProperties(BaseLayerPickerViewModel.prototype, {
|
||||
/**
|
||||
* Gets the command to toggle the visibility of the drop down.
|
||||
* @memberof BaseLayerPickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleDropDown: {
|
||||
get: function () {
|
||||
return this._toggleDropDown;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the globe.
|
||||
* @memberof BaseLayerPickerViewModel.prototype
|
||||
*
|
||||
* @type {Globe}
|
||||
*/
|
||||
globe: {
|
||||
get: function () {
|
||||
return this._globe;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default BaseLayerPickerViewModel;
|
||||
@@ -0,0 +1,104 @@
|
||||
import { defined, DeveloperError } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* A view model that represents each item in the {@link BaseLayerPicker}.
|
||||
*
|
||||
* @alias ProviderViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options The object containing all parameters.
|
||||
* @param {string} options.name The name of the layer.
|
||||
* @param {string} options.tooltip The tooltip to show when the item is moused over.
|
||||
* @param {string} options.iconUrl An icon representing the layer.
|
||||
* @param {string} [options.category] A category for the layer.
|
||||
* @param {ProviderViewModel.CreationFunction|Command} options.creationFunction A function or Command
|
||||
* that creates one or more providers which will be added to the globe when this item is selected.
|
||||
*
|
||||
* @see BaseLayerPicker
|
||||
* @see ImageryProvider
|
||||
* @see TerrainProvider
|
||||
*/
|
||||
function ProviderViewModel(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options.name)) {
|
||||
throw new DeveloperError("options.name is required.");
|
||||
}
|
||||
if (!defined(options.tooltip)) {
|
||||
throw new DeveloperError("options.tooltip is required.");
|
||||
}
|
||||
if (!defined(options.iconUrl)) {
|
||||
throw new DeveloperError("options.iconUrl is required.");
|
||||
}
|
||||
if (typeof options.creationFunction !== "function") {
|
||||
throw new DeveloperError("options.creationFunction is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
let creationCommand = options.creationFunction;
|
||||
if (!defined(creationCommand.canExecute)) {
|
||||
creationCommand = createCommand(creationCommand);
|
||||
}
|
||||
|
||||
this._creationCommand = creationCommand;
|
||||
|
||||
/**
|
||||
* Gets the display name. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.name = options.name;
|
||||
|
||||
/**
|
||||
* Gets the tooltip. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.tooltip = options.tooltip;
|
||||
|
||||
/**
|
||||
* Gets the icon. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.iconUrl = options.iconUrl;
|
||||
|
||||
this._category = options.category ?? "";
|
||||
|
||||
knockout.track(this, ["name", "tooltip", "iconUrl"]);
|
||||
}
|
||||
|
||||
Object.defineProperties(ProviderViewModel.prototype, {
|
||||
/**
|
||||
* Gets the Command that creates one or more providers which will be added to
|
||||
* the globe when this item is selected.
|
||||
* @memberof ProviderViewModel.prototype
|
||||
* @memberof ProviderViewModel.prototype
|
||||
* @type {Command}
|
||||
* @readonly
|
||||
*/
|
||||
creationCommand: {
|
||||
get: function () {
|
||||
return this._creationCommand;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the category
|
||||
* @type {string}
|
||||
* @memberof ProviderViewModel.prototype
|
||||
* @readonly
|
||||
*/
|
||||
category: {
|
||||
get: function () {
|
||||
return this._category;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* A function which creates one or more providers.
|
||||
* @callback ProviderViewModel.CreationFunction
|
||||
* @returns {ImageryProvider|TerrainProvider|ImageryProvider[]|TerrainProvider[]|Promise<TerrainProvider>|Promise<ImageryProvider>|Promise<TerrainProvider[]>|Promise<ImageryProvider[]>}
|
||||
* The ImageryProvider or TerrainProvider, or array of providers, to be added
|
||||
* to the globe.
|
||||
*/
|
||||
export default ProviderViewModel;
|
||||
@@ -0,0 +1,392 @@
|
||||
import {
|
||||
ArcGisMapServerImageryProvider,
|
||||
buildModuleUrl,
|
||||
createWorldImageryAsync,
|
||||
IonImageryProvider,
|
||||
IonWorldImageryStyle,
|
||||
OpenStreetMapImageryProvider,
|
||||
TileMapServiceImageryProvider,
|
||||
ArcGisBaseMapType,
|
||||
} from "@cesium/engine";
|
||||
import ProviderViewModel from "./ProviderViewModel.js";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function createDefaultImageryProviderViewModels() {
|
||||
const providerViewModels = [];
|
||||
const useRetinaTiles = devicePixelRatio >= 2.0;
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Bing Maps Aerial",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/ImageryProviders/bingAerial.png"),
|
||||
tooltip: "Bing Maps aerial imagery, provided by Cesium ion",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return createWorldImageryAsync({
|
||||
style: IonWorldImageryStyle.AERIAL,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Bing Maps Aerial with Labels",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/bingAerialLabels.png",
|
||||
),
|
||||
tooltip: "Bing Maps aerial imagery with labels, provided by Cesium ion",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return createWorldImageryAsync({
|
||||
style: IonWorldImageryStyle.AERIAL_WITH_LABELS,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Bing Maps Roads",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/ImageryProviders/bingRoads.png"),
|
||||
tooltip: "Bing Maps standard road maps, provided by Cesium ion",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return createWorldImageryAsync({
|
||||
style: IonWorldImageryStyle.ROAD,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "ArcGIS World Imagery",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/ArcGisMapServiceWorldImagery.png",
|
||||
),
|
||||
tooltip:
|
||||
"\
|
||||
ArcGIS World Imagery provides one meter or better satellite and aerial imagery in many parts of the world and lower \
|
||||
resolution satellite imagery worldwide. The map includes 15m TerraColor imagery at small and mid-scales (~1:591M down to ~1:288k) \
|
||||
for the world. The map features Maxar imagery at 0.3m resolution for select metropolitan areas around the world, 0.5m \
|
||||
resolution across the United States and parts of Western Europe, and 1m resolution imagery across the rest of the world. \
|
||||
In addition to commercial sources, the World Imagery map features high-resolution aerial photography contributed by the \
|
||||
GIS User Community. This imagery ranges from 0.3m to 0.03m resolution (down to ~1:280 nin select communities). \
|
||||
For more information on this map, including the terms of use, visit us online at \n\
|
||||
https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return ArcGisMapServerImageryProvider.fromBasemapType(
|
||||
ArcGisBaseMapType.SATELLITE,
|
||||
{
|
||||
enablePickFeatures: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "ArcGIS World Hillshade",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/ArcGisMapServiceWorldHillshade.png",
|
||||
),
|
||||
tooltip:
|
||||
"\
|
||||
ArcGIS World Hillshade map portrays elevation as an artistic hillshade. This map is designed to be used as a backdrop for topographical, soil, hydro, \
|
||||
landcover or other outdoor recreational maps. The map was compiled from a variety of sources from several data providers. \
|
||||
The basemap has global coverage down to a scale of ~1:72k. In select areas of the United States and Europe, coverage is available \
|
||||
down to ~1:9k. For more information on this map, including the terms of use, visit us online at \n\
|
||||
https://www.arcgis.com/home/item.html?id=1b243539f4514b6ba35e7d995890db1d",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return ArcGisMapServerImageryProvider.fromBasemapType(
|
||||
ArcGisBaseMapType.HILLSHADE,
|
||||
{
|
||||
enablePickFeatures: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Esri World Ocean",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/ArcGisMapServiceWorldOcean.png",
|
||||
),
|
||||
tooltip:
|
||||
"\
|
||||
ArcGIS World Ocean map is designed to be used as a base map by marine GIS professionals and as a reference map by anyone interested in ocean data. \
|
||||
The base map features marine bathymetry. Land features include inland waters and roads overlaid on land cover and shaded relief imagery. \
|
||||
The map was compiled from a variety of best available sources from several data providers, including General Bathymetric Chart of the Oceans GEBCO_08 Grid, \
|
||||
National Oceanic and Atmospheric Administration (NOAA), and National Geographic, Garmin, HERE, Geonames.org, and Esri, and various other contributors. \
|
||||
The base map currently provides coverage for the world down to a scale of ~1:577k, and coverage down to 1:72k in US coastal areas, and various other areas. \
|
||||
Coverage down to ~ 1:9k is available limited areas based on regional hydrographic survey data. The base map was designed and developed by Esri. \
|
||||
For more information on this map, including our terms of use, visit us online at \n\
|
||||
https://www.arcgis.com/home/item.html?id=1e126e7520f9466c9ca28b8f28b5e500",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return ArcGisMapServerImageryProvider.fromBasemapType(
|
||||
ArcGisBaseMapType.OCEANS,
|
||||
{
|
||||
enablePickFeatures: false,
|
||||
},
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Open\u00adStreet\u00adMap",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/openStreetMap.png",
|
||||
),
|
||||
tooltip:
|
||||
"OpenStreetMap (OSM) is a collaborative project to create a free editable map \
|
||||
of the world.\nhttp://www.openstreetmap.org",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return new OpenStreetMapImageryProvider({
|
||||
url: "https://tile.openstreetmap.org/",
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Stadia x Stamen Watercolor",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/stamenWatercolor.png",
|
||||
),
|
||||
tooltip:
|
||||
"Based on the original basemaps created for the Knight Foundation and reminiscent of hand drawn maps, the watercolor maps from Stamen Design apply raster effect area washes and organic edges over a paper texture to add warm pop to any map.\nhttps://docs.stadiamaps.com/map-styles/stamen-watercolor/",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return new OpenStreetMapImageryProvider({
|
||||
url: "https://tiles.stadiamaps.com/tiles/stamen_watercolor/",
|
||||
fileExtension: "jpg",
|
||||
credit: `© <a href="https://stamen.com/" target="_blank">Stamen Design</a>
|
||||
© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a>
|
||||
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
||||
© <a href="https://www.openstreetmap.org/about/" target="_blank">OpenStreetMap contributors</a>`,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Stadia x Stamen Toner",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/stamenToner.png",
|
||||
),
|
||||
tooltip:
|
||||
"Based on the original basemaps created for the Knight Foundation and the most popular of the excellent styles from Stamen Design, these high-contrast B+W (black and white) maps are the perfect backdrop for your colorful and eye-catching overlays.\nhttps://docs.stadiamaps.com/map-styles/stamen-toner/",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return new OpenStreetMapImageryProvider({
|
||||
url: "https://tiles.stadiamaps.com/tiles/stamen_toner/",
|
||||
retinaTiles: useRetinaTiles,
|
||||
credit: `© <a href="https://stamen.com/" target="_blank">Stamen Design</a>
|
||||
© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a>
|
||||
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
||||
© <a href="https://www.openstreetmap.org/about/" target="_blank">OpenStreetMap contributors</a>`,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Stadia Alidade Smooth",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/stadiaAlidadeSmooth.png",
|
||||
),
|
||||
tooltip:
|
||||
"Stadia's custom Alidade Smooth style is designed for maps that use a lot of markers or overlays. It features a muted color scheme and fewer points of interest to allow your added data to shine.\nhttps://docs.stadiamaps.com/map-styles/alidade-smooth/",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return new OpenStreetMapImageryProvider({
|
||||
url: "https://tiles.stadiamaps.com/tiles/alidade_smooth/",
|
||||
retinaTiles: useRetinaTiles,
|
||||
credit: `© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a>
|
||||
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
||||
© <a href="https://www.openstreetmap.org/about/" target="_blank">OpenStreetMap contributors</a>`,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Stadia Alidade Smooth Dark",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/stadiaAlidadeSmoothDark.png",
|
||||
),
|
||||
tooltip:
|
||||
"Stadia Alidade Smooth Dark, like its lighter cousin, is also designed to stay out of the way. It just flips the dark mode switch on the color scheme. With the lights out, your data can now literally shine.\nhttps://docs.stadiamaps.com/map-styles/alidade-smooth-dark/",
|
||||
category: "Other",
|
||||
creationFunction: function () {
|
||||
return new OpenStreetMapImageryProvider({
|
||||
url: "https://tiles.stadiamaps.com/tiles/alidade_smooth_dark/",
|
||||
retinaTiles: useRetinaTiles,
|
||||
credit: `© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a>
|
||||
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
||||
© <a href="https://www.openstreetmap.org/about/" target="_blank">OpenStreetMap contributors</a>`,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Sentinel-2",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/ImageryProviders/sentinel-2.png"),
|
||||
tooltip:
|
||||
"Sentinel-2 cloudless by EOX IT Services GmbH (Contains modified Copernicus Sentinel data 2016 and 2017).",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3954);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Blue Marble",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/ImageryProviders/blueMarble.png"),
|
||||
tooltip: "Blue Marble Next Generation July, 2004 imagery from NASA.",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3845);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Earth at night",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/earthAtNight.png",
|
||||
),
|
||||
tooltip:
|
||||
"The Earth at night, also known as The Black Marble, is a 500 meter resolution global composite imagery layer released by NASA.",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3812);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Natural Earth\u00a0II",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/naturalEarthII.png",
|
||||
),
|
||||
tooltip:
|
||||
"Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return TileMapServiceImageryProvider.fromUrl(
|
||||
buildModuleUrl("Assets/Textures/NaturalEarthII"),
|
||||
);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Google Maps Satellite",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/googleSatellite.png",
|
||||
),
|
||||
tooltip: "Imagery from Google Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3830182);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Google Maps Satellite with Labels",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/googleSatelliteLabels.png",
|
||||
),
|
||||
tooltip: "Imagery with place labels from Google Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3830183);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Google Maps Roadmap",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/googleRoadmap.png",
|
||||
),
|
||||
tooltip:
|
||||
"Labeled roads and other features on a base landscape from Google Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3830184);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Google Maps Contour",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/googleContour.png",
|
||||
),
|
||||
tooltip:
|
||||
"Hillshade mapping, contour lines, natural features (roadmap features hidden) from Google Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3830186);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Azure Maps Aerial",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/ImageryProviders/azureAerial.png",
|
||||
),
|
||||
tooltip: "Imagery from Azure Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3891168);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Azure Maps Roads",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/ImageryProviders/azureRoads.png"),
|
||||
tooltip:
|
||||
"Labeled roads and other features on a base landscape from Azure Maps",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return IonImageryProvider.fromAssetId(3891169);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return providerViewModels;
|
||||
}
|
||||
export default createDefaultImageryProviderViewModels;
|
||||
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
buildModuleUrl,
|
||||
createWorldTerrainAsync,
|
||||
Ellipsoid,
|
||||
EllipsoidTerrainProvider,
|
||||
} from "@cesium/engine";
|
||||
import ProviderViewModel from "./ProviderViewModel.js";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function createDefaultTerrainProviderViewModels() {
|
||||
const providerViewModels = [];
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "WGS84 Ellipsoid",
|
||||
iconUrl: buildModuleUrl("Widgets/Images/TerrainProviders/Ellipsoid.png"),
|
||||
tooltip: "WGS84 standard ellipsoid, also known as EPSG:4326",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return new EllipsoidTerrainProvider({ ellipsoid: Ellipsoid.WGS84 });
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
providerViewModels.push(
|
||||
new ProviderViewModel({
|
||||
name: "Cesium World Terrain",
|
||||
iconUrl: buildModuleUrl(
|
||||
"Widgets/Images/TerrainProviders/CesiumWorldTerrain.png",
|
||||
),
|
||||
tooltip:
|
||||
"High-resolution global terrain tileset curated from several datasources and hosted by Cesium ion",
|
||||
category: "Cesium ion",
|
||||
creationFunction: function () {
|
||||
return createWorldTerrainAsync({
|
||||
requestWaterMask: true,
|
||||
requestVertexNormals: true,
|
||||
});
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
return providerViewModels;
|
||||
}
|
||||
export default createDefaultTerrainProviderViewModels;
|
||||
@@ -0,0 +1,33 @@
|
||||
.cesium-lighter .cesium-baseLayerPicker-itemIcon {
|
||||
border-color: #759dc0;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-baseLayerPicker-dropDown {
|
||||
background-color: rgba(240, 240, 240, 0.75);
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-baseLayerPicker-sectionTitle {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-baseLayerPicker-itemLabel {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-baseLayerPicker-item:hover
|
||||
.cesium-baseLayerPicker-itemIcon {
|
||||
border-color: #000;
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-baseLayerPicker-selectedItem
|
||||
.cesium-baseLayerPicker-itemLabel {
|
||||
color: rgb(0, 61, 168);
|
||||
}
|
||||
|
||||
.cesium-lighter
|
||||
.cesium-baseLayerPicker-selectedItem
|
||||
.cesium-baseLayerPicker-itemIcon {
|
||||
border: double 4px rgb(0, 61, 168);
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
ul.cesium-cesiumInspector-statistics {
|
||||
margin: 0;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
ul.cesium-cesiumInspector-statistics + ul.cesium-cesiumInspector-statistics {
|
||||
border-top: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-slider {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-slider input[type="number"] {
|
||||
text-align: left;
|
||||
background-color: #222;
|
||||
outline: none;
|
||||
border: 1px solid #444;
|
||||
color: #edffff;
|
||||
width: 100px;
|
||||
border-radius: 3px;
|
||||
padding: 1px;
|
||||
margin-left: 10px;
|
||||
cursor: auto;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-slider input[type="number"]::-webkit-outer-spin-button,
|
||||
.cesium-cesiumInspector-slider input[type="number"]::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-slider input[type="range"] {
|
||||
margin-left: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-hide .cesium-cesiumInspector-styleEditor {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-styleEditor {
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
background: rgba(48, 51, 54, 0.8);
|
||||
border: 1px solid #444;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-styleEditor textarea {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
background: transparent;
|
||||
color: #edffff;
|
||||
border: none;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
overflow-wrap: normal;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector {
|
||||
width: 300px;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector-statistics {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector-disabledElementsInfo {
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0 0 0 20px;
|
||||
color: #eed202;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector div,
|
||||
.cesium-3DTilesInspector input[type="range"] {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-error {
|
||||
color: #ff9e9e;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector .cesium-cesiumInspector-section {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.cesium-3DTilesInspector
|
||||
.cesium-cesiumInspector-sectionHeader
|
||||
+ .cesium-cesiumInspector-show {
|
||||
border-top: 1px solid white;
|
||||
}
|
||||
|
||||
input.cesium-cesiumInspector-url {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
overflow-x: scroll;
|
||||
background-color: transparent;
|
||||
color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
height: 1em;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector .field-group {
|
||||
display: table;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector .field-group > label {
|
||||
display: table-cell;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector .field-group > .field {
|
||||
display: table-cell;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,387 @@
|
||||
import { Check, destroyObject, getElement } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import InspectorShared from "../InspectorShared.js";
|
||||
import Cesium3DTilesInspectorViewModel from "./Cesium3DTilesInspectorViewModel.js";
|
||||
|
||||
/**
|
||||
* Inspector widget to aid in debugging 3D Tiles
|
||||
*
|
||||
* @alias Cesium3DTilesInspector
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene the Scene instance to use.
|
||||
*/
|
||||
function Cesium3DTilesInspector(container, scene) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.defined("container", container);
|
||||
Check.typeOf.object("scene", scene);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
const element = document.createElement("div");
|
||||
const performanceContainer = document.createElement("div");
|
||||
performanceContainer.setAttribute("data-bind", "visible: performance");
|
||||
const viewModel = new Cesium3DTilesInspectorViewModel(
|
||||
scene,
|
||||
performanceContainer,
|
||||
);
|
||||
|
||||
this._viewModel = viewModel;
|
||||
this._container = container;
|
||||
this._element = element;
|
||||
|
||||
const text = document.createElement("div");
|
||||
text.textContent = "3D Tiles Inspector";
|
||||
text.className = "cesium-cesiumInspector-button";
|
||||
text.setAttribute("data-bind", "click: toggleInspector");
|
||||
element.appendChild(text);
|
||||
element.className = "cesium-cesiumInspector cesium-3DTilesInspector";
|
||||
element.setAttribute(
|
||||
"data-bind",
|
||||
'css: { "cesium-cesiumInspector-visible" : inspectorVisible, "cesium-cesiumInspector-hidden" : !inspectorVisible}',
|
||||
);
|
||||
container.appendChild(element);
|
||||
|
||||
const panel = document.createElement("div");
|
||||
panel.className = "cesium-cesiumInspector-dropDown";
|
||||
element.appendChild(panel);
|
||||
|
||||
const createSection = InspectorShared.createSection;
|
||||
const createCheckbox = InspectorShared.createCheckbox;
|
||||
const createRangeInput = InspectorShared.createRangeInput;
|
||||
const createButton = InspectorShared.createButton;
|
||||
|
||||
const tilesetPanelContents = createSection(
|
||||
panel,
|
||||
"Tileset",
|
||||
"tilesetVisible",
|
||||
"toggleTileset",
|
||||
);
|
||||
const displayPanelContents = createSection(
|
||||
panel,
|
||||
"Display",
|
||||
"displayVisible",
|
||||
"toggleDisplay",
|
||||
);
|
||||
const updatePanelContents = createSection(
|
||||
panel,
|
||||
"Update",
|
||||
"updateVisible",
|
||||
"toggleUpdate",
|
||||
);
|
||||
const loggingPanelContents = createSection(
|
||||
panel,
|
||||
"Logging",
|
||||
"loggingVisible",
|
||||
"toggleLogging",
|
||||
);
|
||||
const tileDebugLabelsPanelContents = createSection(
|
||||
panel,
|
||||
"Tile Debug Labels",
|
||||
"tileDebugLabelsVisible",
|
||||
"toggleTileDebugLabels",
|
||||
);
|
||||
const stylePanelContents = createSection(
|
||||
panel,
|
||||
"Style",
|
||||
"styleVisible",
|
||||
"toggleStyle",
|
||||
);
|
||||
const optimizationPanelContents = createSection(
|
||||
panel,
|
||||
"Optimization",
|
||||
"optimizationVisible",
|
||||
"toggleOptimization",
|
||||
);
|
||||
|
||||
const properties = document.createElement("div");
|
||||
properties.className = "field-group";
|
||||
const propertiesLabel = document.createElement("label");
|
||||
propertiesLabel.className = "field-label";
|
||||
propertiesLabel.appendChild(document.createTextNode("Properties: "));
|
||||
const propertiesField = document.createElement("div");
|
||||
propertiesField.setAttribute("data-bind", "text: properties");
|
||||
properties.appendChild(propertiesLabel);
|
||||
properties.appendChild(propertiesField);
|
||||
tilesetPanelContents.appendChild(properties);
|
||||
tilesetPanelContents.appendChild(
|
||||
createButton("Pick Tileset", "togglePickTileset", "pickActive"),
|
||||
);
|
||||
tilesetPanelContents.appendChild(
|
||||
createButton("Trim Tiles Cache", "trimTilesCache"),
|
||||
);
|
||||
tilesetPanelContents.appendChild(createCheckbox("Enable Picking", "picking"));
|
||||
|
||||
displayPanelContents.appendChild(createCheckbox("Colorize", "colorize"));
|
||||
const wireframeCheckbox = displayPanelContents.appendChild(
|
||||
createCheckbox(
|
||||
"Wireframe",
|
||||
"wireframe",
|
||||
"_tileset === undefined || hasEnabledWireframe",
|
||||
),
|
||||
);
|
||||
|
||||
// Create warning text when the Wireframe checkbox is disabled
|
||||
const warningText = document.createElement("p");
|
||||
warningText.setAttribute(
|
||||
"data-bind",
|
||||
"visible: _tileset !== undefined && !hasEnabledWireframe",
|
||||
);
|
||||
warningText.setAttribute(
|
||||
"class",
|
||||
"cesium-3DTilesInspector-disabledElementsInfo",
|
||||
);
|
||||
warningText.innerText =
|
||||
"Set enableDebugWireframe to true in the tileset constructor to enable this option.";
|
||||
wireframeCheckbox.appendChild(warningText);
|
||||
|
||||
displayPanelContents.appendChild(
|
||||
createCheckbox("Bounding Volumes", "showBoundingVolumes"),
|
||||
);
|
||||
displayPanelContents.appendChild(
|
||||
createCheckbox("Content Volumes", "showContentBoundingVolumes"),
|
||||
);
|
||||
displayPanelContents.appendChild(
|
||||
createCheckbox("Request Volumes", "showRequestVolumes"),
|
||||
);
|
||||
|
||||
displayPanelContents.appendChild(
|
||||
createCheckbox("Point Cloud Shading", "pointCloudShading"),
|
||||
);
|
||||
const pointCloudShadingContainer = document.createElement("div");
|
||||
pointCloudShadingContainer.setAttribute(
|
||||
"data-bind",
|
||||
"visible: pointCloudShading",
|
||||
);
|
||||
pointCloudShadingContainer.appendChild(
|
||||
createRangeInput(
|
||||
"Geometric Error Scale",
|
||||
"geometricErrorScale",
|
||||
0,
|
||||
2,
|
||||
0.01,
|
||||
),
|
||||
);
|
||||
pointCloudShadingContainer.appendChild(
|
||||
createRangeInput("Maximum Attenuation", "maximumAttenuation", 0, 32, 1),
|
||||
);
|
||||
pointCloudShadingContainer.appendChild(
|
||||
createRangeInput("Base Resolution", "baseResolution", 0, 1, 0.01),
|
||||
);
|
||||
pointCloudShadingContainer.appendChild(
|
||||
createCheckbox("Eye Dome Lighting (EDL)", "eyeDomeLighting"),
|
||||
);
|
||||
displayPanelContents.appendChild(pointCloudShadingContainer);
|
||||
|
||||
const edlContainer = document.createElement("div");
|
||||
edlContainer.setAttribute("data-bind", "visible: eyeDomeLighting");
|
||||
edlContainer.appendChild(
|
||||
createRangeInput("EDL Strength", "eyeDomeLightingStrength", 0, 2.0, 0.1),
|
||||
);
|
||||
edlContainer.appendChild(
|
||||
createRangeInput("EDL Radius", "eyeDomeLightingRadius", 0, 4.0, 0.1),
|
||||
);
|
||||
pointCloudShadingContainer.appendChild(edlContainer);
|
||||
|
||||
updatePanelContents.appendChild(
|
||||
createCheckbox("Freeze Frame", "freezeFrame"),
|
||||
);
|
||||
updatePanelContents.appendChild(
|
||||
createCheckbox("Dynamic Screen Space Error", "dynamicScreenSpaceError"),
|
||||
);
|
||||
const sseContainer = document.createElement("div");
|
||||
sseContainer.appendChild(
|
||||
createRangeInput(
|
||||
"Maximum Screen Space Error",
|
||||
"maximumScreenSpaceError",
|
||||
0,
|
||||
128,
|
||||
1,
|
||||
),
|
||||
);
|
||||
updatePanelContents.appendChild(sseContainer);
|
||||
const dynamicScreenSpaceErrorContainer = document.createElement("div");
|
||||
dynamicScreenSpaceErrorContainer.setAttribute(
|
||||
"data-bind",
|
||||
"visible: dynamicScreenSpaceError",
|
||||
);
|
||||
dynamicScreenSpaceErrorContainer.appendChild(
|
||||
createRangeInput(
|
||||
"Screen Space Error Density",
|
||||
"dynamicScreenSpaceErrorDensitySliderValue",
|
||||
0,
|
||||
1,
|
||||
0.005,
|
||||
"dynamicScreenSpaceErrorDensity",
|
||||
),
|
||||
);
|
||||
dynamicScreenSpaceErrorContainer.appendChild(
|
||||
createRangeInput(
|
||||
"Screen Space Error Factor",
|
||||
"dynamicScreenSpaceErrorFactor",
|
||||
1,
|
||||
32,
|
||||
0.1,
|
||||
),
|
||||
);
|
||||
updatePanelContents.appendChild(dynamicScreenSpaceErrorContainer);
|
||||
|
||||
loggingPanelContents.appendChild(
|
||||
createCheckbox("Performance", "performance"),
|
||||
);
|
||||
loggingPanelContents.appendChild(performanceContainer);
|
||||
loggingPanelContents.appendChild(
|
||||
createCheckbox("Statistics", "showStatistics"),
|
||||
);
|
||||
const statistics = document.createElement("div");
|
||||
statistics.className = "cesium-3dTilesInspector-statistics";
|
||||
statistics.setAttribute(
|
||||
"data-bind",
|
||||
"html: statisticsText, visible: showStatistics",
|
||||
);
|
||||
loggingPanelContents.appendChild(statistics);
|
||||
loggingPanelContents.appendChild(
|
||||
createCheckbox("Pick Statistics", "showPickStatistics"),
|
||||
);
|
||||
const pickStatistics = document.createElement("div");
|
||||
pickStatistics.className = "cesium-3dTilesInspector-statistics";
|
||||
pickStatistics.setAttribute(
|
||||
"data-bind",
|
||||
"html: pickStatisticsText, visible: showPickStatistics",
|
||||
);
|
||||
loggingPanelContents.appendChild(pickStatistics);
|
||||
loggingPanelContents.appendChild(
|
||||
createCheckbox("Resource Cache Statistics", "showResourceCacheStatistics"),
|
||||
);
|
||||
const resourceCacheStatistics = document.createElement("div");
|
||||
resourceCacheStatistics.className = "cesium-3dTilesInspector-statistics";
|
||||
resourceCacheStatistics.setAttribute(
|
||||
"data-bind",
|
||||
"html: resourceCacheStatisticsText, visible: showResourceCacheStatistics",
|
||||
);
|
||||
loggingPanelContents.appendChild(resourceCacheStatistics);
|
||||
|
||||
const stylePanelEditor = document.createElement("div");
|
||||
stylePanelContents.appendChild(stylePanelEditor);
|
||||
stylePanelEditor.appendChild(document.createTextNode("Color Blend Mode: "));
|
||||
const blendDropdown = document.createElement("select");
|
||||
blendDropdown.setAttribute(
|
||||
"data-bind",
|
||||
"options: colorBlendModes, " +
|
||||
'optionsText: "text", ' +
|
||||
'optionsValue: "value", ' +
|
||||
"value: colorBlendMode",
|
||||
);
|
||||
stylePanelEditor.appendChild(blendDropdown);
|
||||
const styleEditor = document.createElement("textarea");
|
||||
styleEditor.setAttribute(
|
||||
"data-bind",
|
||||
"textInput: styleString, event: { keydown: styleEditorKeyPress }",
|
||||
);
|
||||
stylePanelEditor.className = "cesium-cesiumInspector-styleEditor";
|
||||
stylePanelEditor.appendChild(styleEditor);
|
||||
const closeStylesBtn = createButton("Compile (Ctrl+Enter)", "compileStyle");
|
||||
stylePanelEditor.appendChild(closeStylesBtn);
|
||||
const errorBox = document.createElement("div");
|
||||
errorBox.className = "cesium-cesiumInspector-error";
|
||||
errorBox.setAttribute("data-bind", "text: editorError");
|
||||
stylePanelEditor.appendChild(errorBox);
|
||||
|
||||
tileDebugLabelsPanelContents.appendChild(
|
||||
createCheckbox("Show Picked Only", "showOnlyPickedTileDebugLabel"),
|
||||
);
|
||||
tileDebugLabelsPanelContents.appendChild(
|
||||
createCheckbox("Geometric Error", "showGeometricError"),
|
||||
);
|
||||
tileDebugLabelsPanelContents.appendChild(
|
||||
createCheckbox("Rendering Statistics", "showRenderingStatistics"),
|
||||
);
|
||||
tileDebugLabelsPanelContents.appendChild(
|
||||
createCheckbox("Memory Usage (MB)", "showMemoryUsage"),
|
||||
);
|
||||
tileDebugLabelsPanelContents.appendChild(createCheckbox("Url", "showUrl"));
|
||||
|
||||
optimizationPanelContents.appendChild(
|
||||
createCheckbox("Skip Tile LODs", "skipLevelOfDetail"),
|
||||
);
|
||||
const skipScreenSpaceErrorFactorContainer = document.createElement("div");
|
||||
skipScreenSpaceErrorFactorContainer.appendChild(
|
||||
createRangeInput("Skip SSE Factor", "skipScreenSpaceErrorFactor", 1, 50, 1),
|
||||
);
|
||||
optimizationPanelContents.appendChild(skipScreenSpaceErrorFactorContainer);
|
||||
const baseScreenSpaceError = document.createElement("div");
|
||||
baseScreenSpaceError.appendChild(
|
||||
createRangeInput(
|
||||
"SSE before skipping LOD",
|
||||
"baseScreenSpaceError",
|
||||
0,
|
||||
4096,
|
||||
1,
|
||||
),
|
||||
);
|
||||
optimizationPanelContents.appendChild(baseScreenSpaceError);
|
||||
const skipLevelsContainer = document.createElement("div");
|
||||
skipLevelsContainer.appendChild(
|
||||
createRangeInput("Min. levels to skip", "skipLevels", 0, 10, 1),
|
||||
);
|
||||
optimizationPanelContents.appendChild(skipLevelsContainer);
|
||||
optimizationPanelContents.appendChild(
|
||||
createCheckbox(
|
||||
"Load only tiles that meet the max SSE.",
|
||||
"immediatelyLoadDesiredLevelOfDetail",
|
||||
),
|
||||
);
|
||||
optimizationPanelContents.appendChild(
|
||||
createCheckbox("Load siblings of visible tiles", "loadSiblings"),
|
||||
);
|
||||
|
||||
knockout.applyBindings(viewModel, element);
|
||||
}
|
||||
|
||||
Object.defineProperties(Cesium3DTilesInspector.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof Cesium3DTilesInspector.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof Cesium3DTilesInspector.prototype
|
||||
*
|
||||
* @type {Cesium3DTilesInspectorViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
Cesium3DTilesInspector.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
Cesium3DTilesInspector.prototype.destroy = function () {
|
||||
knockout.cleanNode(this._element);
|
||||
this._container.removeChild(this._element);
|
||||
this.viewModel.destroy();
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
|
||||
export default Cesium3DTilesInspector;
|
||||
@@ -0,0 +1,134 @@
|
||||
.cesium-cesiumInspector {
|
||||
border-radius: 5px;
|
||||
transition: width ease-in-out 0.25s;
|
||||
background: rgba(48, 51, 54, 0.8);
|
||||
border: 1px solid #444;
|
||||
color: #edffff;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 4px 12px;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-button {
|
||||
text-align: center;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-visible .cesium-cesiumInspector-button {
|
||||
border-bottom: 1px solid #aaa;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector input:enabled,
|
||||
.cesium-cesiumInspector-button {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-visible {
|
||||
width: 185px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-hidden {
|
||||
width: 122px;
|
||||
height: 17px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-sectionContent {
|
||||
max-height: 600px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-section-collapsed
|
||||
.cesium-cesiumInspector-sectionContent {
|
||||
max-height: 0;
|
||||
padding: 0 !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-dropDown {
|
||||
margin: 5px 0;
|
||||
font-family: sans-serif;
|
||||
font-size: 10pt;
|
||||
width: 185px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-frustumStatistics {
|
||||
padding-left: 10px;
|
||||
padding: 5px;
|
||||
background-color: rgba(80, 80, 80, 0.75);
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-pickButton {
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border: 1px solid #444;
|
||||
color: #edffff;
|
||||
border-radius: 5px;
|
||||
padding: 3px 7px;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-pickButton:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-pickButton:active,
|
||||
.cesium-cesiumInspector-pickButtonHighlight {
|
||||
color: #000; /* For text buttons */
|
||||
background: #adf;
|
||||
border-color: #fff;
|
||||
box-shadow: 0 0 8px #fff;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-sectionHeader {
|
||||
font-weight: bold;
|
||||
font-size: 10pt;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-pickSection {
|
||||
border: 1px solid #aaa;
|
||||
border-radius: 5px;
|
||||
padding: 3px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-sectionContent {
|
||||
margin-bottom: 10px;
|
||||
transition: max-height 0.25s;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-tileText {
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-relativeText {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-sectionHeader::before {
|
||||
margin-right: 5px;
|
||||
content: "-";
|
||||
width: 1ch;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cesium-cesiumInspector-section-collapsed
|
||||
.cesium-cesiumInspector-sectionHeader::before {
|
||||
content: "+";
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import InspectorShared from "../InspectorShared.js";
|
||||
import CesiumInspectorViewModel from "./CesiumInspectorViewModel.js";
|
||||
|
||||
/**
|
||||
* Inspector widget to aid in debugging
|
||||
*
|
||||
* @alias CesiumInspector
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene The Scene instance to use.
|
||||
*
|
||||
* @demo {@link https://sandcastle.cesium.com/index.html?id=cesium-inspector|Cesium Sandcastle Cesium Inspector Demo}
|
||||
*/
|
||||
function CesiumInspector(container, scene) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const performanceContainer = document.createElement("div");
|
||||
|
||||
const viewModel = new CesiumInspectorViewModel(scene, performanceContainer);
|
||||
this._viewModel = viewModel;
|
||||
this._container = container;
|
||||
|
||||
const element = document.createElement("div");
|
||||
this._element = element;
|
||||
const text = document.createElement("div");
|
||||
text.textContent = "Cesium Inspector";
|
||||
text.className = "cesium-cesiumInspector-button";
|
||||
text.setAttribute("data-bind", "click: toggleDropDown");
|
||||
element.appendChild(text);
|
||||
element.className = "cesium-cesiumInspector";
|
||||
element.setAttribute(
|
||||
"data-bind",
|
||||
'css: { "cesium-cesiumInspector-visible" : dropDownVisible, "cesium-cesiumInspector-hidden" : !dropDownVisible }',
|
||||
);
|
||||
container.appendChild(this._element);
|
||||
|
||||
const panel = document.createElement("div");
|
||||
panel.className = "cesium-cesiumInspector-dropDown";
|
||||
element.appendChild(panel);
|
||||
|
||||
const createSection = InspectorShared.createSection;
|
||||
const createCheckbox = InspectorShared.createCheckbox;
|
||||
|
||||
// General
|
||||
const generalSection = createSection(
|
||||
panel,
|
||||
"General",
|
||||
"generalVisible",
|
||||
"toggleGeneral",
|
||||
);
|
||||
|
||||
const debugShowFrustums = createCheckbox("Show Frustums", "frustums");
|
||||
const frustumStatistics = document.createElement("div");
|
||||
frustumStatistics.className = "cesium-cesiumInspector-frustumStatistics";
|
||||
frustumStatistics.setAttribute(
|
||||
"data-bind",
|
||||
"visible: frustums, html: frustumStatisticText",
|
||||
);
|
||||
debugShowFrustums.appendChild(frustumStatistics);
|
||||
generalSection.appendChild(debugShowFrustums);
|
||||
|
||||
generalSection.appendChild(
|
||||
createCheckbox("Show Frustum Planes", "frustumPlanes"),
|
||||
);
|
||||
generalSection.appendChild(
|
||||
createCheckbox("Performance Display", "performance"),
|
||||
);
|
||||
|
||||
performanceContainer.className = "cesium-cesiumInspector-performanceDisplay";
|
||||
generalSection.appendChild(performanceContainer);
|
||||
|
||||
const shaderCacheDisplay = document.createElement("div");
|
||||
shaderCacheDisplay.className = "cesium-cesiumInspector-shaderCache";
|
||||
shaderCacheDisplay.setAttribute("data-bind", "html: shaderCacheText");
|
||||
generalSection.appendChild(shaderCacheDisplay);
|
||||
|
||||
const depthFrustum = document.createElement("div");
|
||||
generalSection.appendChild(depthFrustum);
|
||||
|
||||
// Use a span with HTML binding so that we can indent with non-breaking spaces.
|
||||
const gLabel = document.createElement("span");
|
||||
gLabel.setAttribute(
|
||||
"data-bind",
|
||||
'html: " Frustum:"',
|
||||
);
|
||||
depthFrustum.appendChild(gLabel);
|
||||
|
||||
const gText = document.createElement("span");
|
||||
gText.setAttribute("data-bind", "text: depthFrustumText");
|
||||
depthFrustum.appendChild(gText);
|
||||
|
||||
const gMinusButton = document.createElement("input");
|
||||
gMinusButton.type = "button";
|
||||
gMinusButton.value = "-";
|
||||
gMinusButton.className = "cesium-cesiumInspector-pickButton";
|
||||
gMinusButton.setAttribute("data-bind", "click: decrementDepthFrustum");
|
||||
depthFrustum.appendChild(gMinusButton);
|
||||
|
||||
const gPlusButton = document.createElement("input");
|
||||
gPlusButton.type = "button";
|
||||
gPlusButton.value = "+";
|
||||
gPlusButton.className = "cesium-cesiumInspector-pickButton";
|
||||
gPlusButton.setAttribute("data-bind", "click: incrementDepthFrustum");
|
||||
depthFrustum.appendChild(gPlusButton);
|
||||
|
||||
// Primitives
|
||||
const primSection = createSection(
|
||||
panel,
|
||||
"Primitives",
|
||||
"primitivesVisible",
|
||||
"togglePrimitives",
|
||||
);
|
||||
const pickPrimRequired = document.createElement("div");
|
||||
pickPrimRequired.className = "cesium-cesiumInspector-pickSection";
|
||||
primSection.appendChild(pickPrimRequired);
|
||||
|
||||
const pickPrimitiveButton = document.createElement("input");
|
||||
pickPrimitiveButton.type = "button";
|
||||
pickPrimitiveButton.value = "Pick a primitive";
|
||||
pickPrimitiveButton.className = "cesium-cesiumInspector-pickButton";
|
||||
pickPrimitiveButton.setAttribute(
|
||||
"data-bind",
|
||||
'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickPrimitiveActive}, click: pickPrimitive',
|
||||
);
|
||||
let buttonWrap = document.createElement("div");
|
||||
buttonWrap.className = "cesium-cesiumInspector-center";
|
||||
buttonWrap.appendChild(pickPrimitiveButton);
|
||||
pickPrimRequired.appendChild(buttonWrap);
|
||||
|
||||
pickPrimRequired.appendChild(
|
||||
createCheckbox(
|
||||
"Show bounding sphere",
|
||||
"primitiveBoundingSphere",
|
||||
"hasPickedPrimitive",
|
||||
),
|
||||
);
|
||||
pickPrimRequired.appendChild(
|
||||
createCheckbox(
|
||||
"Show reference frame",
|
||||
"primitiveReferenceFrame",
|
||||
"hasPickedPrimitive",
|
||||
),
|
||||
);
|
||||
|
||||
this._primitiveOnly = createCheckbox(
|
||||
"Show only selected",
|
||||
"filterPrimitive",
|
||||
"hasPickedPrimitive",
|
||||
);
|
||||
pickPrimRequired.appendChild(this._primitiveOnly);
|
||||
|
||||
// Terrain
|
||||
const terrainSection = createSection(
|
||||
panel,
|
||||
"Terrain",
|
||||
"terrainVisible",
|
||||
"toggleTerrain",
|
||||
);
|
||||
const pickTileRequired = document.createElement("div");
|
||||
pickTileRequired.className = "cesium-cesiumInspector-pickSection";
|
||||
terrainSection.appendChild(pickTileRequired);
|
||||
const pickTileButton = document.createElement("input");
|
||||
pickTileButton.type = "button";
|
||||
pickTileButton.value = "Pick a tile";
|
||||
pickTileButton.className = "cesium-cesiumInspector-pickButton";
|
||||
pickTileButton.setAttribute(
|
||||
"data-bind",
|
||||
'css: {"cesium-cesiumInspector-pickButtonHighlight" : pickTileActive}, click: pickTile',
|
||||
);
|
||||
buttonWrap = document.createElement("div");
|
||||
buttonWrap.appendChild(pickTileButton);
|
||||
buttonWrap.className = "cesium-cesiumInspector-center";
|
||||
pickTileRequired.appendChild(buttonWrap);
|
||||
const tileInfo = document.createElement("div");
|
||||
pickTileRequired.appendChild(tileInfo);
|
||||
const parentTile = document.createElement("input");
|
||||
parentTile.type = "button";
|
||||
parentTile.value = "Parent";
|
||||
parentTile.className = "cesium-cesiumInspector-pickButton";
|
||||
parentTile.setAttribute("data-bind", "click: selectParent");
|
||||
const nwTile = document.createElement("input");
|
||||
nwTile.type = "button";
|
||||
nwTile.value = "NW";
|
||||
nwTile.className = "cesium-cesiumInspector-pickButton";
|
||||
nwTile.setAttribute("data-bind", "click: selectNW");
|
||||
const neTile = document.createElement("input");
|
||||
neTile.type = "button";
|
||||
neTile.value = "NE";
|
||||
neTile.className = "cesium-cesiumInspector-pickButton";
|
||||
neTile.setAttribute("data-bind", "click: selectNE");
|
||||
const swTile = document.createElement("input");
|
||||
swTile.type = "button";
|
||||
swTile.value = "SW";
|
||||
swTile.className = "cesium-cesiumInspector-pickButton";
|
||||
swTile.setAttribute("data-bind", "click: selectSW");
|
||||
const seTile = document.createElement("input");
|
||||
seTile.type = "button";
|
||||
seTile.value = "SE";
|
||||
seTile.className = "cesium-cesiumInspector-pickButton";
|
||||
seTile.setAttribute("data-bind", "click: selectSE");
|
||||
|
||||
const tileText = document.createElement("div");
|
||||
tileText.className = "cesium-cesiumInspector-tileText";
|
||||
tileInfo.className = "cesium-cesiumInspector-frustumStatistics";
|
||||
tileInfo.appendChild(tileText);
|
||||
tileInfo.setAttribute("data-bind", "visible: hasPickedTile");
|
||||
tileText.setAttribute("data-bind", "html: tileText");
|
||||
|
||||
const relativeText = document.createElement("div");
|
||||
relativeText.className = "cesium-cesiumInspector-relativeText";
|
||||
relativeText.textContent = "Select relative:";
|
||||
tileInfo.appendChild(relativeText);
|
||||
|
||||
const table = document.createElement("table");
|
||||
const tr1 = document.createElement("tr");
|
||||
const tr2 = document.createElement("tr");
|
||||
const td1 = document.createElement("td");
|
||||
td1.appendChild(parentTile);
|
||||
const td2 = document.createElement("td");
|
||||
td2.appendChild(nwTile);
|
||||
const td3 = document.createElement("td");
|
||||
td3.appendChild(neTile);
|
||||
tr1.appendChild(td1);
|
||||
tr1.appendChild(td2);
|
||||
tr1.appendChild(td3);
|
||||
const td4 = document.createElement("td");
|
||||
const td5 = document.createElement("td");
|
||||
td5.appendChild(swTile);
|
||||
const td6 = document.createElement("td");
|
||||
td6.appendChild(seTile);
|
||||
tr2.appendChild(td4);
|
||||
tr2.appendChild(td5);
|
||||
tr2.appendChild(td6);
|
||||
table.appendChild(tr1);
|
||||
table.appendChild(tr2);
|
||||
|
||||
tileInfo.appendChild(table);
|
||||
|
||||
pickTileRequired.appendChild(
|
||||
createCheckbox(
|
||||
"Show bounding volume",
|
||||
"tileBoundingSphere",
|
||||
"hasPickedTile",
|
||||
),
|
||||
);
|
||||
pickTileRequired.appendChild(
|
||||
createCheckbox("Show only selected", "filterTile", "hasPickedTile"),
|
||||
);
|
||||
|
||||
terrainSection.appendChild(createCheckbox("Wireframe", "wireframe"));
|
||||
terrainSection.appendChild(
|
||||
createCheckbox("Suspend LOD update", "suspendUpdates"),
|
||||
);
|
||||
terrainSection.appendChild(
|
||||
createCheckbox("Show tile coordinates", "tileCoordinates"),
|
||||
);
|
||||
|
||||
knockout.applyBindings(viewModel, this._element);
|
||||
}
|
||||
|
||||
Object.defineProperties(CesiumInspector.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof CesiumInspector.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof CesiumInspector.prototype
|
||||
*
|
||||
* @type {CesiumInspectorViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
CesiumInspector.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
CesiumInspector.prototype.destroy = function () {
|
||||
knockout.cleanNode(this._element);
|
||||
this._container.removeChild(this._element);
|
||||
this.viewModel.destroy();
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default CesiumInspector;
|
||||
@@ -0,0 +1,980 @@
|
||||
import {
|
||||
Cartesian3,
|
||||
defined,
|
||||
destroyObject,
|
||||
DebugModelMatrixPrimitive,
|
||||
DeveloperError,
|
||||
PerformanceDisplay,
|
||||
Ray,
|
||||
Rectangle,
|
||||
ScreenSpaceEventHandler,
|
||||
ScreenSpaceEventType,
|
||||
TileCoordinatesImageryProvider,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
function frustumStatisticsToString(statistics) {
|
||||
let str;
|
||||
if (defined(statistics)) {
|
||||
str = "Command Statistics";
|
||||
const com = statistics.commandsInFrustums;
|
||||
for (const n in com) {
|
||||
if (com.hasOwnProperty(n)) {
|
||||
let num = parseInt(n, 10);
|
||||
let s;
|
||||
if (num === 7) {
|
||||
s = "1, 2 and 3";
|
||||
} else {
|
||||
const f = [];
|
||||
for (let i = 2; i >= 0; i--) {
|
||||
const p = Math.pow(2, i);
|
||||
if (num >= p) {
|
||||
f.push(i + 1);
|
||||
num -= p;
|
||||
}
|
||||
}
|
||||
s = f.reverse().join(" and ");
|
||||
}
|
||||
str += `<br> ${com[n]} in frustum ${s}`;
|
||||
}
|
||||
}
|
||||
str += `<br>Total: ${statistics.totalCommands}`;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
function boundDepthFrustum(lower, upper, proposed) {
|
||||
let bounded = Math.min(proposed, upper);
|
||||
bounded = Math.max(bounded, lower);
|
||||
return bounded;
|
||||
}
|
||||
|
||||
const scratchPickRay = new Ray();
|
||||
const scratchPickCartesian = new Cartesian3();
|
||||
|
||||
/**
|
||||
* The view model for {@link CesiumInspector}.
|
||||
* @alias CesiumInspectorViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Scene} scene The scene instance to use.
|
||||
* @param {Element} performanceContainer The instance to use for performance container.
|
||||
*/
|
||||
function CesiumInspectorViewModel(scene, performanceContainer) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required");
|
||||
}
|
||||
|
||||
if (!defined(performanceContainer)) {
|
||||
throw new DeveloperError("performanceContainer is required");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const that = this;
|
||||
const canvas = scene.canvas;
|
||||
const eventHandler = new ScreenSpaceEventHandler(canvas);
|
||||
this._eventHandler = eventHandler;
|
||||
this._scene = scene;
|
||||
this._canvas = canvas;
|
||||
this._primitive = undefined;
|
||||
this._tile = undefined;
|
||||
this._modelMatrixPrimitive = undefined;
|
||||
this._performanceDisplay = undefined;
|
||||
this._performanceContainer = performanceContainer;
|
||||
|
||||
const globe = this._scene.globe;
|
||||
globe.depthTestAgainstTerrain = true;
|
||||
|
||||
/**
|
||||
* Gets or sets the show frustums state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.frustums = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show frustum planes state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.frustumPlanes = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show performance display state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.performance = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the shader cache text. This property is observable.
|
||||
* @type {string}
|
||||
* @default ''
|
||||
*/
|
||||
this.shaderCacheText = "";
|
||||
|
||||
/**
|
||||
* Gets or sets the show primitive bounding sphere state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.primitiveBoundingSphere = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show primitive reference frame state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.primitiveReferenceFrame = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the filter primitive state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.filterPrimitive = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show tile bounding sphere state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.tileBoundingSphere = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the filter tile state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.filterTile = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show wireframe state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.wireframe = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the index of the depth frustum to display. This property is observable.
|
||||
* @type {number}
|
||||
* @default 1
|
||||
*/
|
||||
this.depthFrustum = 1;
|
||||
this._numberOfFrustums = 1;
|
||||
|
||||
/**
|
||||
* Gets or sets the suspend updates state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.suspendUpdates = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the show tile coordinates state. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.tileCoordinates = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the frustum statistic text. This property is observable.
|
||||
* @type {string}
|
||||
* @default ''
|
||||
*/
|
||||
this.frustumStatisticText = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the selected tile information text. This property is observable.
|
||||
* @type {string}
|
||||
* @default ''
|
||||
*/
|
||||
this.tileText = "";
|
||||
|
||||
/**
|
||||
* Gets if a primitive has been selected. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.hasPickedPrimitive = false;
|
||||
|
||||
/**
|
||||
* Gets if a tile has been selected. This property is observable
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.hasPickedTile = false;
|
||||
|
||||
/**
|
||||
* Gets if the picking primitive command is active. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.pickPrimitiveActive = false;
|
||||
|
||||
/**
|
||||
* Gets if the picking tile command is active. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.pickTileActive = false;
|
||||
|
||||
/**
|
||||
* Gets or sets if the cesium inspector drop down is visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default true
|
||||
*/
|
||||
this.dropDownVisible = true;
|
||||
|
||||
/**
|
||||
* Gets or sets if the general section is visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default true
|
||||
*/
|
||||
this.generalVisible = true;
|
||||
|
||||
/**
|
||||
* Gets or sets if the primitive section is visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.primitivesVisible = false;
|
||||
|
||||
/**
|
||||
* Gets or sets if the terrain section is visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.terrainVisible = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the index of the depth frustum text. This property is observable.
|
||||
* @type {string}
|
||||
* @default ''
|
||||
*/
|
||||
this.depthFrustumText = "";
|
||||
|
||||
knockout.track(this, [
|
||||
"frustums",
|
||||
"frustumPlanes",
|
||||
"performance",
|
||||
"shaderCacheText",
|
||||
"primitiveBoundingSphere",
|
||||
"primitiveReferenceFrame",
|
||||
"filterPrimitive",
|
||||
"tileBoundingSphere",
|
||||
"filterTile",
|
||||
"wireframe",
|
||||
"depthFrustum",
|
||||
"suspendUpdates",
|
||||
"tileCoordinates",
|
||||
"frustumStatisticText",
|
||||
"tileText",
|
||||
"hasPickedPrimitive",
|
||||
"hasPickedTile",
|
||||
"pickPrimitiveActive",
|
||||
"pickTileActive",
|
||||
"dropDownVisible",
|
||||
"generalVisible",
|
||||
"primitivesVisible",
|
||||
"terrainVisible",
|
||||
"depthFrustumText",
|
||||
]);
|
||||
|
||||
this._toggleDropDown = createCommand(function () {
|
||||
that.dropDownVisible = !that.dropDownVisible;
|
||||
});
|
||||
|
||||
this._toggleGeneral = createCommand(function () {
|
||||
that.generalVisible = !that.generalVisible;
|
||||
});
|
||||
|
||||
this._togglePrimitives = createCommand(function () {
|
||||
that.primitivesVisible = !that.primitivesVisible;
|
||||
});
|
||||
|
||||
this._toggleTerrain = createCommand(function () {
|
||||
that.terrainVisible = !that.terrainVisible;
|
||||
});
|
||||
|
||||
this._frustumsSubscription = knockout
|
||||
.getObservable(this, "frustums")
|
||||
.subscribe(function (val) {
|
||||
that._scene.debugShowFrustums = val;
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._frustumPlanesSubscription = knockout
|
||||
.getObservable(this, "frustumPlanes")
|
||||
.subscribe(function (val) {
|
||||
that._scene.debugShowFrustumPlanes = val;
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._performanceSubscription = knockout
|
||||
.getObservable(this, "performance")
|
||||
.subscribe(function (val) {
|
||||
if (val) {
|
||||
that._performanceDisplay = new PerformanceDisplay({
|
||||
container: that._performanceContainer,
|
||||
});
|
||||
} else {
|
||||
that._performanceContainer.innerHTML = "";
|
||||
}
|
||||
});
|
||||
|
||||
this._showPrimitiveBoundingSphere = createCommand(function () {
|
||||
that._primitive.debugShowBoundingVolume = that.primitiveBoundingSphere;
|
||||
that._scene.requestRender();
|
||||
return true;
|
||||
});
|
||||
|
||||
this._primitiveBoundingSphereSubscription = knockout
|
||||
.getObservable(this, "primitiveBoundingSphere")
|
||||
.subscribe(function () {
|
||||
that._showPrimitiveBoundingSphere();
|
||||
});
|
||||
|
||||
this._showPrimitiveReferenceFrame = createCommand(function () {
|
||||
if (that.primitiveReferenceFrame) {
|
||||
const modelMatrix = that._primitive.modelMatrix;
|
||||
that._modelMatrixPrimitive = new DebugModelMatrixPrimitive({
|
||||
modelMatrix: modelMatrix,
|
||||
});
|
||||
that._scene.primitives.add(that._modelMatrixPrimitive);
|
||||
} else if (defined(that._modelMatrixPrimitive)) {
|
||||
that._scene.primitives.remove(that._modelMatrixPrimitive);
|
||||
that._modelMatrixPrimitive = undefined;
|
||||
}
|
||||
that._scene.requestRender();
|
||||
return true;
|
||||
});
|
||||
|
||||
this._primitiveReferenceFrameSubscription = knockout
|
||||
.getObservable(this, "primitiveReferenceFrame")
|
||||
.subscribe(function () {
|
||||
that._showPrimitiveReferenceFrame();
|
||||
});
|
||||
|
||||
this._doFilterPrimitive = createCommand(function () {
|
||||
if (that.filterPrimitive) {
|
||||
that._scene.debugCommandFilter = function (command) {
|
||||
if (
|
||||
defined(that._modelMatrixPrimitive) &&
|
||||
command.owner === that._modelMatrixPrimitive._primitive
|
||||
) {
|
||||
return true;
|
||||
} else if (defined(that._primitive)) {
|
||||
return (
|
||||
command.owner === that._primitive ||
|
||||
command.owner === that._primitive._billboardCollection ||
|
||||
command.owner.primitive === that._primitive
|
||||
);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
that._scene.debugCommandFilter = undefined;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this._filterPrimitiveSubscription = knockout
|
||||
.getObservable(this, "filterPrimitive")
|
||||
.subscribe(function () {
|
||||
that._doFilterPrimitive();
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._wireframeSubscription = knockout
|
||||
.getObservable(this, "wireframe")
|
||||
.subscribe(function (val) {
|
||||
globe._surface.tileProvider._debug.wireframe = val;
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._depthFrustumSubscription = knockout
|
||||
.getObservable(this, "depthFrustum")
|
||||
.subscribe(function (val) {
|
||||
that._scene.debugShowDepthFrustum = val;
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._incrementDepthFrustum = createCommand(function () {
|
||||
const next = that.depthFrustum + 1;
|
||||
that.depthFrustum = boundDepthFrustum(1, that._numberOfFrustums, next);
|
||||
that._scene.requestRender();
|
||||
return true;
|
||||
});
|
||||
|
||||
this._decrementDepthFrustum = createCommand(function () {
|
||||
const next = that.depthFrustum - 1;
|
||||
that.depthFrustum = boundDepthFrustum(1, that._numberOfFrustums, next);
|
||||
that._scene.requestRender();
|
||||
return true;
|
||||
});
|
||||
|
||||
this._suspendUpdatesSubscription = knockout
|
||||
.getObservable(this, "suspendUpdates")
|
||||
.subscribe(function (val) {
|
||||
globe._surface._debug.suspendLodUpdate = val;
|
||||
if (!val) {
|
||||
that.filterTile = false;
|
||||
}
|
||||
});
|
||||
|
||||
let tileBoundariesLayer;
|
||||
this._showTileCoordinates = createCommand(function () {
|
||||
if (that.tileCoordinates && !defined(tileBoundariesLayer)) {
|
||||
tileBoundariesLayer = scene.imageryLayers.addImageryProvider(
|
||||
new TileCoordinatesImageryProvider({
|
||||
tilingScheme: scene.terrainProvider.tilingScheme,
|
||||
}),
|
||||
);
|
||||
} else if (!that.tileCoordinates && defined(tileBoundariesLayer)) {
|
||||
scene.imageryLayers.remove(tileBoundariesLayer);
|
||||
tileBoundariesLayer = undefined;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this._tileCoordinatesSubscription = knockout
|
||||
.getObservable(this, "tileCoordinates")
|
||||
.subscribe(function () {
|
||||
that._showTileCoordinates();
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._tileBoundingSphereSubscription = knockout
|
||||
.getObservable(this, "tileBoundingSphere")
|
||||
.subscribe(function () {
|
||||
that._showTileBoundingSphere();
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
this._showTileBoundingSphere = createCommand(function () {
|
||||
if (that.tileBoundingSphere) {
|
||||
globe._surface.tileProvider._debug.boundingSphereTile = that._tile;
|
||||
} else {
|
||||
globe._surface.tileProvider._debug.boundingSphereTile = undefined;
|
||||
}
|
||||
that._scene.requestRender();
|
||||
return true;
|
||||
});
|
||||
|
||||
this._doFilterTile = createCommand(function () {
|
||||
if (!that.filterTile) {
|
||||
that.suspendUpdates = false;
|
||||
} else {
|
||||
that.suspendUpdates = true;
|
||||
|
||||
globe._surface._tilesToRender = [];
|
||||
|
||||
if (defined(that._tile) && that._tile.renderable) {
|
||||
globe._surface._tilesToRender.push(that._tile);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this._filterTileSubscription = knockout
|
||||
.getObservable(this, "filterTile")
|
||||
.subscribe(function () {
|
||||
that.doFilterTile();
|
||||
that._scene.requestRender();
|
||||
});
|
||||
|
||||
function pickPrimitive(e) {
|
||||
const newPick = that._scene.pick({
|
||||
x: e.position.x,
|
||||
y: e.position.y,
|
||||
});
|
||||
if (defined(newPick)) {
|
||||
that.primitive = defined(newPick.collection)
|
||||
? newPick.collection
|
||||
: newPick.primitive;
|
||||
}
|
||||
|
||||
that._scene.requestRender();
|
||||
that.pickPrimitiveActive = false;
|
||||
}
|
||||
|
||||
this._pickPrimitive = createCommand(function () {
|
||||
that.pickPrimitiveActive = !that.pickPrimitiveActive;
|
||||
});
|
||||
|
||||
this._pickPrimitiveActiveSubscription = knockout
|
||||
.getObservable(this, "pickPrimitiveActive")
|
||||
.subscribe(function (val) {
|
||||
if (val) {
|
||||
eventHandler.setInputAction(
|
||||
pickPrimitive,
|
||||
ScreenSpaceEventType.LEFT_CLICK,
|
||||
);
|
||||
} else {
|
||||
eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
|
||||
}
|
||||
});
|
||||
|
||||
function selectTile(e) {
|
||||
let selectedTile;
|
||||
const ellipsoid = globe.ellipsoid;
|
||||
|
||||
const ray = that._scene.camera.getPickRay(e.position, scratchPickRay);
|
||||
const cartesian = globe.pick(ray, that._scene, scratchPickCartesian);
|
||||
|
||||
if (defined(cartesian)) {
|
||||
const cartographic = ellipsoid.cartesianToCartographic(cartesian);
|
||||
const tilesRendered =
|
||||
globe._surface.tileProvider._tilesToRenderByTextureCount;
|
||||
for (
|
||||
let textureCount = 0;
|
||||
!selectedTile && textureCount < tilesRendered.length;
|
||||
++textureCount
|
||||
) {
|
||||
const tilesRenderedByTextureCount = tilesRendered[textureCount];
|
||||
if (!defined(tilesRenderedByTextureCount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (
|
||||
let tileIndex = 0;
|
||||
!selectedTile && tileIndex < tilesRenderedByTextureCount.length;
|
||||
++tileIndex
|
||||
) {
|
||||
const tile = tilesRenderedByTextureCount[tileIndex];
|
||||
if (Rectangle.contains(tile.rectangle, cartographic)) {
|
||||
selectedTile = tile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
that.tile = selectedTile;
|
||||
|
||||
that.pickTileActive = false;
|
||||
}
|
||||
|
||||
this._pickTile = createCommand(function () {
|
||||
that.pickTileActive = !that.pickTileActive;
|
||||
});
|
||||
|
||||
this._pickTileActiveSubscription = knockout
|
||||
.getObservable(this, "pickTileActive")
|
||||
.subscribe(function (val) {
|
||||
if (val) {
|
||||
eventHandler.setInputAction(
|
||||
selectTile,
|
||||
ScreenSpaceEventType.LEFT_CLICK,
|
||||
);
|
||||
} else {
|
||||
eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
|
||||
}
|
||||
});
|
||||
|
||||
this._removePostRenderEvent = scene.postRender.addEventListener(function () {
|
||||
that._update();
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperties(CesiumInspectorViewModel.prototype, {
|
||||
/**
|
||||
* Gets the scene to control.
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the container of the PerformanceDisplay
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
performanceContainer: {
|
||||
get: function () {
|
||||
return this._performanceContainer;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the visibility of the drop down.
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleDropDown: {
|
||||
get: function () {
|
||||
return this._toggleDropDown;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the visibility of a BoundingSphere for a primitive
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showPrimitiveBoundingSphere: {
|
||||
get: function () {
|
||||
return this._showPrimitiveBoundingSphere;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the visibility of a {@link DebugModelMatrixPrimitive} for the model matrix of a primitive
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showPrimitiveReferenceFrame: {
|
||||
get: function () {
|
||||
return this._showPrimitiveReferenceFrame;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle a filter that renders only a selected primitive
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
doFilterPrimitive: {
|
||||
get: function () {
|
||||
return this._doFilterPrimitive;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to increment the depth frustum index to be shown
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
incrementDepthFrustum: {
|
||||
get: function () {
|
||||
return this._incrementDepthFrustum;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to decrement the depth frustum index to be shown
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
decrementDepthFrustum: {
|
||||
get: function () {
|
||||
return this._decrementDepthFrustum;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the visibility of tile coordinates
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showTileCoordinates: {
|
||||
get: function () {
|
||||
return this._showTileCoordinates;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the visibility of a BoundingSphere for a selected tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showTileBoundingSphere: {
|
||||
get: function () {
|
||||
return this._showTileBoundingSphere;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle a filter that renders only a selected tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
doFilterTile: {
|
||||
get: function () {
|
||||
return this._doFilterTile;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to expand and collapse the general section
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleGeneral: {
|
||||
get: function () {
|
||||
return this._toggleGeneral;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to expand and collapse the primitives section
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
togglePrimitives: {
|
||||
get: function () {
|
||||
return this._togglePrimitives;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to expand and collapse the terrain section
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleTerrain: {
|
||||
get: function () {
|
||||
return this._toggleTerrain;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a primitive
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
pickPrimitive: {
|
||||
get: function () {
|
||||
return this._pickPrimitive;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
pickTile: {
|
||||
get: function () {
|
||||
return this._pickTile;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
selectParent: {
|
||||
get: function () {
|
||||
const that = this;
|
||||
return createCommand(function () {
|
||||
that.tile = that.tile.parent;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
selectNW: {
|
||||
get: function () {
|
||||
const that = this;
|
||||
return createCommand(function () {
|
||||
that.tile = that.tile.northwestChild;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
selectNE: {
|
||||
get: function () {
|
||||
const that = this;
|
||||
return createCommand(function () {
|
||||
that.tile = that.tile.northeastChild;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
selectSW: {
|
||||
get: function () {
|
||||
const that = this;
|
||||
return createCommand(function () {
|
||||
that.tile = that.tile.southwestChild;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to pick a tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
selectSE: {
|
||||
get: function () {
|
||||
const that = this;
|
||||
return createCommand(function () {
|
||||
that.tile = that.tile.southeastChild;
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the current selected primitive
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
primitive: {
|
||||
get: function () {
|
||||
return this._primitive;
|
||||
},
|
||||
set: function (newPrimitive) {
|
||||
const oldPrimitive = this._primitive;
|
||||
if (newPrimitive !== oldPrimitive) {
|
||||
this.hasPickedPrimitive = true;
|
||||
if (defined(oldPrimitive)) {
|
||||
oldPrimitive.debugShowBoundingVolume = false;
|
||||
}
|
||||
this._scene.debugCommandFilter = undefined;
|
||||
if (defined(this._modelMatrixPrimitive)) {
|
||||
this._scene.primitives.remove(this._modelMatrixPrimitive);
|
||||
this._modelMatrixPrimitive = undefined;
|
||||
}
|
||||
this._primitive = newPrimitive;
|
||||
newPrimitive.show = false;
|
||||
setTimeout(function () {
|
||||
newPrimitive.show = true;
|
||||
}, 50);
|
||||
this.showPrimitiveBoundingSphere();
|
||||
this.showPrimitiveReferenceFrame();
|
||||
this.doFilterPrimitive();
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the current selected tile
|
||||
* @memberof CesiumInspectorViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
tile: {
|
||||
get: function () {
|
||||
return this._tile;
|
||||
},
|
||||
set: function (newTile) {
|
||||
if (defined(newTile)) {
|
||||
this.hasPickedTile = true;
|
||||
const oldTile = this._tile;
|
||||
if (newTile !== oldTile) {
|
||||
this.tileText = `L: ${newTile.level} X: ${newTile.x} Y: ${newTile.y}`;
|
||||
this.tileText += `<br>SW corner: ${newTile.rectangle.west}, ${newTile.rectangle.south}`;
|
||||
this.tileText += `<br>NE corner: ${newTile.rectangle.east}, ${newTile.rectangle.north}`;
|
||||
const data = newTile.data;
|
||||
if (defined(data) && defined(data.tileBoundingRegion)) {
|
||||
this.tileText += `<br>Min: ${data.tileBoundingRegion.minimumHeight} Max: ${data.tileBoundingRegion.maximumHeight}`;
|
||||
} else {
|
||||
this.tileText += "<br>(Tile is not loaded)";
|
||||
}
|
||||
}
|
||||
this._tile = newTile;
|
||||
this.showTileBoundingSphere();
|
||||
this.doFilterTile();
|
||||
} else {
|
||||
this.hasPickedTile = false;
|
||||
this._tile = undefined;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the view model
|
||||
* @private
|
||||
*/
|
||||
CesiumInspectorViewModel.prototype._update = function () {
|
||||
if (this.frustums) {
|
||||
this.frustumStatisticText = frustumStatisticsToString(
|
||||
this._scene.debugFrustumStatistics,
|
||||
);
|
||||
}
|
||||
|
||||
// Determine the number of frustums being used.
|
||||
const numberOfFrustums = this._scene.numberOfFrustums;
|
||||
this._numberOfFrustums = numberOfFrustums;
|
||||
// Bound the frustum to be displayed.
|
||||
this.depthFrustum = boundDepthFrustum(1, numberOfFrustums, this.depthFrustum);
|
||||
// Update the displayed text.
|
||||
this.depthFrustumText = `${this.depthFrustum} of ${numberOfFrustums}`;
|
||||
|
||||
if (this.performance) {
|
||||
this._performanceDisplay.update();
|
||||
}
|
||||
if (this.primitiveReferenceFrame) {
|
||||
this._modelMatrixPrimitive.modelMatrix = this._primitive.modelMatrix;
|
||||
}
|
||||
|
||||
this.shaderCacheText = `Cached shaders: ${this._scene.context.shaderCache.numberOfShaders}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
CesiumInspectorViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
CesiumInspectorViewModel.prototype.destroy = function () {
|
||||
this._eventHandler.destroy();
|
||||
this._removePostRenderEvent();
|
||||
this._frustumsSubscription.dispose();
|
||||
this._frustumPlanesSubscription.dispose();
|
||||
this._performanceSubscription.dispose();
|
||||
this._primitiveBoundingSphereSubscription.dispose();
|
||||
this._primitiveReferenceFrameSubscription.dispose();
|
||||
this._filterPrimitiveSubscription.dispose();
|
||||
this._wireframeSubscription.dispose();
|
||||
this._depthFrustumSubscription.dispose();
|
||||
this._suspendUpdatesSubscription.dispose();
|
||||
this._tileCoordinatesSubscription.dispose();
|
||||
this._tileBoundingSphereSubscription.dispose();
|
||||
this._filterTileSubscription.dispose();
|
||||
this._pickPrimitiveActiveSubscription.dispose();
|
||||
this._pickTileActiveSubscription.dispose();
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default CesiumInspectorViewModel;
|
||||
@@ -0,0 +1,196 @@
|
||||
import {
|
||||
Clock,
|
||||
defined,
|
||||
destroyObject,
|
||||
EventHelper,
|
||||
JulianDate,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "./ThirdParty/knockout.js";
|
||||
|
||||
/**
|
||||
* A view model which exposes a {@link Clock} for user interfaces.
|
||||
* @alias ClockViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Clock} [clock] The clock object wrapped by this view model, if undefined a new instance will be created.
|
||||
*
|
||||
* @see Clock
|
||||
*/
|
||||
function ClockViewModel(clock) {
|
||||
if (!defined(clock)) {
|
||||
clock = new Clock();
|
||||
}
|
||||
this._clock = clock;
|
||||
|
||||
this._eventHelper = new EventHelper();
|
||||
this._eventHelper.add(clock.onTick, this.synchronize, this);
|
||||
|
||||
/**
|
||||
* Gets the current system time.
|
||||
* This property is observable.
|
||||
* @type {JulianDate}
|
||||
*/
|
||||
this.systemTime = knockout.observable(JulianDate.now());
|
||||
this.systemTime.equalityComparer = JulianDate.equals;
|
||||
|
||||
/**
|
||||
* Gets or sets the start time of the clock.
|
||||
* See {@link Clock#startTime}.
|
||||
* This property is observable.
|
||||
* @type {JulianDate}
|
||||
*/
|
||||
this.startTime = knockout.observable(clock.startTime);
|
||||
this.startTime.equalityComparer = JulianDate.equals;
|
||||
this.startTime.subscribe(function (value) {
|
||||
clock.startTime = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets the stop time of the clock.
|
||||
* See {@link Clock#stopTime}.
|
||||
* This property is observable.
|
||||
* @type {JulianDate}
|
||||
*/
|
||||
this.stopTime = knockout.observable(clock.stopTime);
|
||||
this.stopTime.equalityComparer = JulianDate.equals;
|
||||
this.stopTime.subscribe(function (value) {
|
||||
clock.stopTime = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets the current time.
|
||||
* See {@link Clock#currentTime}.
|
||||
* This property is observable.
|
||||
* @type {JulianDate}
|
||||
*/
|
||||
this.currentTime = knockout.observable(clock.currentTime);
|
||||
this.currentTime.equalityComparer = JulianDate.equals;
|
||||
this.currentTime.subscribe(function (value) {
|
||||
clock.currentTime = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets the clock multiplier.
|
||||
* See {@link Clock#multiplier}.
|
||||
* This property is observable.
|
||||
* @type {number}
|
||||
*/
|
||||
this.multiplier = knockout.observable(clock.multiplier);
|
||||
this.multiplier.subscribe(function (value) {
|
||||
clock.multiplier = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets the clock step setting.
|
||||
* See {@link Clock#clockStep}.
|
||||
* This property is observable.
|
||||
* @type {ClockStep}
|
||||
*/
|
||||
this.clockStep = knockout.observable(clock.clockStep);
|
||||
this.clockStep.subscribe(function (value) {
|
||||
clock.clockStep = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets the clock range setting.
|
||||
* See {@link Clock#clockRange}.
|
||||
* This property is observable.
|
||||
* @type {ClockRange}
|
||||
*/
|
||||
this.clockRange = knockout.observable(clock.clockRange);
|
||||
this.clockRange.subscribe(function (value) {
|
||||
clock.clockRange = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets whether the clock can animate.
|
||||
* See {@link Clock#canAnimate}.
|
||||
* This property is observable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.canAnimate = knockout.observable(clock.canAnimate);
|
||||
this.canAnimate.subscribe(function (value) {
|
||||
clock.canAnimate = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
/**
|
||||
* Gets or sets whether the clock should animate.
|
||||
* See {@link Clock#shouldAnimate}.
|
||||
* This property is observable.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.shouldAnimate = knockout.observable(clock.shouldAnimate);
|
||||
this.shouldAnimate.subscribe(function (value) {
|
||||
clock.shouldAnimate = value;
|
||||
this.synchronize();
|
||||
}, this);
|
||||
|
||||
knockout.track(this, [
|
||||
"systemTime",
|
||||
"startTime",
|
||||
"stopTime",
|
||||
"currentTime",
|
||||
"multiplier",
|
||||
"clockStep",
|
||||
"clockRange",
|
||||
"canAnimate",
|
||||
"shouldAnimate",
|
||||
]);
|
||||
}
|
||||
|
||||
Object.defineProperties(ClockViewModel.prototype, {
|
||||
/**
|
||||
* Gets the underlying Clock.
|
||||
* @memberof ClockViewModel.prototype
|
||||
* @type {Clock}
|
||||
*/
|
||||
clock: {
|
||||
get: function () {
|
||||
return this._clock;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the view model with the contents of the underlying clock.
|
||||
* Can be called to force an update of the viewModel if the underlying
|
||||
* clock has changed and <code>Clock.tick</code> has not yet been called.
|
||||
*/
|
||||
ClockViewModel.prototype.synchronize = function () {
|
||||
const clock = this._clock;
|
||||
|
||||
this.systemTime = JulianDate.now();
|
||||
this.startTime = clock.startTime;
|
||||
this.stopTime = clock.stopTime;
|
||||
this.currentTime = clock.currentTime;
|
||||
this.multiplier = clock.multiplier;
|
||||
this.clockStep = clock.clockStep;
|
||||
this.clockRange = clock.clockRange;
|
||||
this.canAnimate = clock.canAnimate;
|
||||
this.shouldAnimate = clock.shouldAnimate;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
ClockViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the view model. Should be called to
|
||||
* properly clean up the view model when it is no longer needed.
|
||||
*/
|
||||
ClockViewModel.prototype.destroy = function () {
|
||||
this._eventHelper.removeAll();
|
||||
|
||||
destroyObject(this);
|
||||
};
|
||||
export default ClockViewModel;
|
||||
@@ -0,0 +1,42 @@
|
||||
import { DeveloperError } from "@cesium/engine";
|
||||
|
||||
/**
|
||||
* A Command is a function with an extra <code>canExecute</code> observable property to determine
|
||||
* whether the command can be executed. When executed, a Command function will check the
|
||||
* value of <code>canExecute</code> and throw if false.
|
||||
*
|
||||
* This type describes an interface and is not intended to be instantiated directly.
|
||||
* See {@link createCommand} to create a command from a function.
|
||||
*
|
||||
* @alias Command
|
||||
* @constructor
|
||||
*/
|
||||
function Command() {
|
||||
/**
|
||||
* Gets whether this command can currently be executed. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default undefined
|
||||
*/
|
||||
this.canExecute = undefined;
|
||||
|
||||
/**
|
||||
* Gets an event which is raised before the command executes, the event
|
||||
* is raised with an object containing two properties: a <code>cancel</code> property,
|
||||
* which if set to false by the listener will prevent the command from being executed, and
|
||||
* an <code>args</code> property, which is the array of arguments being passed to the command.
|
||||
* @type {Event}
|
||||
* @default undefined
|
||||
*/
|
||||
this.beforeExecute = undefined;
|
||||
|
||||
/**
|
||||
* Gets an event which is raised after the command executes, the event
|
||||
* is raised with the return value of the command as its only parameter.
|
||||
* @type {Event}
|
||||
* @default undefined
|
||||
*/
|
||||
this.afterExecute = undefined;
|
||||
|
||||
DeveloperError.throwInstantiationError();
|
||||
}
|
||||
export default Command;
|
||||
@@ -0,0 +1,7 @@
|
||||
.cesium-button.cesium-fullscreenButton {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import FullscreenButtonViewModel from "./FullscreenButtonViewModel.js";
|
||||
|
||||
const enterFullScreenPath =
|
||||
"M 83.96875 17.5625 L 83.96875 17.59375 L 76.65625 24.875 L 97.09375 24.96875 L 76.09375 45.96875 L 81.9375 51.8125 L 102.78125 30.9375 L 102.875 51.15625 L 110.15625 43.875 L 110.1875 17.59375 L 83.96875 17.5625 z M 44.125 17.59375 L 17.90625 17.625 L 17.9375 43.90625 L 25.21875 51.1875 L 25.3125 30.96875 L 46.15625 51.8125 L 52 45.96875 L 31 25 L 51.4375 24.90625 L 44.125 17.59375 z M 46.0625 76.03125 L 25.1875 96.875 L 25.09375 76.65625 L 17.8125 83.9375 L 17.8125 110.21875 L 44 110.25 L 51.3125 102.9375 L 30.90625 102.84375 L 51.875 81.875 L 46.0625 76.03125 z M 82 76.15625 L 76.15625 82 L 97.15625 103 L 76.71875 103.0625 L 84.03125 110.375 L 110.25 110.34375 L 110.21875 84.0625 L 102.9375 76.8125 L 102.84375 97 L 82 76.15625 z";
|
||||
const exitFullScreenPath =
|
||||
"M 104.34375 17.5625 L 83.5 38.4375 L 83.40625 18.21875 L 76.125 25.5 L 76.09375 51.78125 L 102.3125 51.8125 L 102.3125 51.78125 L 109.625 44.5 L 89.1875 44.40625 L 110.1875 23.40625 L 104.34375 17.5625 z M 23.75 17.59375 L 17.90625 23.4375 L 38.90625 44.4375 L 18.5 44.53125 L 25.78125 51.8125 L 52 51.78125 L 51.96875 25.53125 L 44.6875 18.25 L 44.625 38.46875 L 23.75 17.59375 z M 25.6875 76.03125 L 18.375 83.3125 L 38.78125 83.40625 L 17.8125 104.40625 L 23.625 110.25 L 44.5 89.375 L 44.59375 109.59375 L 51.875 102.3125 L 51.875 76.0625 L 25.6875 76.03125 z M 102.375 76.15625 L 76.15625 76.1875 L 76.1875 102.4375 L 83.46875 109.71875 L 83.5625 89.53125 L 104.40625 110.375 L 110.25 104.53125 L 89.25 83.53125 L 109.6875 83.46875 L 102.375 76.15625 z";
|
||||
|
||||
/**
|
||||
* A single button widget for toggling fullscreen mode.
|
||||
*
|
||||
* @alias FullscreenButton
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Element|string} [fullscreenElement=document.body] The element or id to be placed into fullscreen mode.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*
|
||||
* @see Fullscreen
|
||||
*/
|
||||
function FullscreenButton(container, fullscreenElement) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const viewModel = new FullscreenButtonViewModel(fullscreenElement, container);
|
||||
|
||||
viewModel._exitFullScreenPath = exitFullScreenPath;
|
||||
viewModel._enterFullScreenPath = enterFullScreenPath;
|
||||
|
||||
const element = document.createElement("button");
|
||||
element.type = "button";
|
||||
element.className = "cesium-button cesium-fullscreenButton";
|
||||
element.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
attr: { title: tooltip },\
|
||||
click: command,\
|
||||
enable: isFullscreenEnabled,\
|
||||
cesiumSvgPath: { path: isFullscreen ? _exitFullScreenPath : _enterFullScreenPath, width: 128, height: 128 }",
|
||||
);
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
knockout.applyBindings(viewModel, element);
|
||||
|
||||
this._container = container;
|
||||
this._viewModel = viewModel;
|
||||
this._element = element;
|
||||
}
|
||||
|
||||
Object.defineProperties(FullscreenButton.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof FullscreenButton.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof FullscreenButton.prototype
|
||||
*
|
||||
* @type {FullscreenButtonViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
FullscreenButton.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
FullscreenButton.prototype.destroy = function () {
|
||||
this._viewModel.destroy();
|
||||
|
||||
knockout.cleanNode(this._element);
|
||||
this._container.removeChild(this._element);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default FullscreenButton;
|
||||
@@ -0,0 +1,144 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
Fullscreen,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link FullscreenButton}.
|
||||
* @alias FullscreenButtonViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} [fullscreenElement=document.body] The element or id to be placed into fullscreen mode.
|
||||
* @param {Element|string} [container] The DOM element or ID that will contain the widget.
|
||||
*/
|
||||
function FullscreenButtonViewModel(fullscreenElement, container) {
|
||||
if (!defined(container)) {
|
||||
container = document.body;
|
||||
}
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const that = this;
|
||||
|
||||
const tmpIsFullscreen = knockout.observable(Fullscreen.fullscreen);
|
||||
const tmpIsEnabled = knockout.observable(Fullscreen.enabled);
|
||||
const ownerDocument = container.ownerDocument;
|
||||
|
||||
/**
|
||||
* Gets whether or not fullscreen mode is active. This property is observable.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isFullscreen = undefined;
|
||||
knockout.defineProperty(this, "isFullscreen", {
|
||||
get: function () {
|
||||
return tmpIsFullscreen();
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets whether or not fullscreen functionality should be enabled. This property is observable.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @see Fullscreen.enabled
|
||||
*/
|
||||
this.isFullscreenEnabled = undefined;
|
||||
knockout.defineProperty(this, "isFullscreenEnabled", {
|
||||
get: function () {
|
||||
return tmpIsEnabled();
|
||||
},
|
||||
set: function (value) {
|
||||
tmpIsEnabled(value && Fullscreen.enabled);
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets the tooltip. This property is observable.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.tooltip = undefined;
|
||||
knockout.defineProperty(this, "tooltip", function () {
|
||||
if (!this.isFullscreenEnabled) {
|
||||
return "Full screen unavailable";
|
||||
}
|
||||
return tmpIsFullscreen() ? "Exit full screen" : "Full screen";
|
||||
});
|
||||
|
||||
this._command = createCommand(
|
||||
function () {
|
||||
if (Fullscreen.fullscreen) {
|
||||
Fullscreen.exitFullscreen();
|
||||
} else {
|
||||
Fullscreen.requestFullscreen(that._fullscreenElement);
|
||||
}
|
||||
},
|
||||
knockout.getObservable(this, "isFullscreenEnabled"),
|
||||
);
|
||||
|
||||
this._fullscreenElement = getElement(fullscreenElement) ?? ownerDocument.body;
|
||||
|
||||
this._callback = function () {
|
||||
tmpIsFullscreen(Fullscreen.fullscreen);
|
||||
};
|
||||
ownerDocument.addEventListener(Fullscreen.changeEventName, this._callback);
|
||||
}
|
||||
|
||||
Object.defineProperties(FullscreenButtonViewModel.prototype, {
|
||||
/**
|
||||
* Gets or sets the HTML element to place into fullscreen mode when the
|
||||
* corresponding button is pressed.
|
||||
* @memberof FullscreenButtonViewModel.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
fullscreenElement: {
|
||||
//TODO:@exception {DeveloperError} value must be a valid HTML Element.
|
||||
get: function () {
|
||||
return this._fullscreenElement;
|
||||
},
|
||||
set: function (value) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!(value instanceof Element)) {
|
||||
throw new DeveloperError("value must be a valid Element.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._fullscreenElement = value;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Command to toggle fullscreen mode.
|
||||
* @memberof FullscreenButtonViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
command: {
|
||||
get: function () {
|
||||
return this._command;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
FullscreenButtonViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the view model. Should be called to
|
||||
* properly clean up the view model when it is no longer needed.
|
||||
*/
|
||||
FullscreenButtonViewModel.prototype.destroy = function () {
|
||||
document.removeEventListener(Fullscreen.changeEventName, this._callback);
|
||||
destroyObject(this);
|
||||
};
|
||||
export default FullscreenButtonViewModel;
|
||||
@@ -0,0 +1,80 @@
|
||||
.cesium-viewer-geocoderContainer .cesium-geocoder-input {
|
||||
border: solid 1px #444;
|
||||
background-color: rgba(40, 40, 40, 0.7);
|
||||
color: white;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 0;
|
||||
height: 32px;
|
||||
margin: 0;
|
||||
padding: 0 32px 0 0;
|
||||
border-radius: 0;
|
||||
box-sizing: border-box;
|
||||
transition:
|
||||
width ease-in-out 0.25s,
|
||||
background-color 0.2s ease-in-out;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer:hover .cesium-geocoder-input {
|
||||
border-color: #aef;
|
||||
box-shadow: 0 0 8px #fff;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {
|
||||
border-color: #ea4;
|
||||
background-color: rgba(15, 15, 15, 0.9);
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer:hover .cesium-geocoder-input,
|
||||
.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus,
|
||||
.cesium-viewer-geocoderContainer .cesium-geocoder-input-wide {
|
||||
padding-left: 4px;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer .search-results {
|
||||
position: absolute;
|
||||
background-color: #000;
|
||||
color: #eee;
|
||||
overflow-y: auto;
|
||||
opacity: 0.8;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer .search-results ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer .search-results ul li {
|
||||
font-size: 14px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
.cesium-viewer-geocoderContainer .search-results ul li:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-viewer-geocoderContainer .search-results ul li.active {
|
||||
background: #48b;
|
||||
}
|
||||
|
||||
.cesium-geocoder-searchButton {
|
||||
background-color: #303336;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
width: 32px;
|
||||
top: 1px;
|
||||
right: 1px;
|
||||
height: 30px;
|
||||
vertical-align: middle;
|
||||
fill: #edffff;
|
||||
}
|
||||
|
||||
.cesium-geocoder-searchButton:hover {
|
||||
background-color: #48b;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import GeocoderViewModel from "./GeocoderViewModel.js";
|
||||
|
||||
const startSearchPath =
|
||||
"M29.772,26.433l-7.126-7.126c0.96-1.583,1.523-3.435,1.524-5.421C24.169,8.093,19.478,3.401,13.688,3.399C7.897,3.401,3.204,8.093,3.204,13.885c0,5.789,4.693,10.481,10.484,10.481c1.987,0,3.839-0.563,5.422-1.523l7.128,7.127L29.772,26.433zM7.203,13.885c0.006-3.582,2.903-6.478,6.484-6.486c3.579,0.008,6.478,2.904,6.484,6.486c-0.007,3.58-2.905,6.476-6.484,6.484C10.106,20.361,7.209,17.465,7.203,13.885z";
|
||||
const stopSearchPath =
|
||||
"M24.778,21.419 19.276,15.917 24.777,10.415 21.949,7.585 16.447,13.087 10.945,7.585 8.117,10.415 13.618,15.917 8.116,21.419 10.946,24.248 16.447,18.746 21.948,24.248z";
|
||||
|
||||
/**
|
||||
* A widget for finding addresses and landmarks, and flying the camera to them. Geocoding is
|
||||
* performed using {@link https://cesium.com/cesium-ion/|Cesium ion}.
|
||||
*
|
||||
* @alias Geocoder
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Element|string} options.container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} options.scene The Scene instance to use.
|
||||
* @param {GeocoderService[]} [options.geocoderServices] The geocoder services to be used
|
||||
* @param {boolean} [options.autoComplete = true] True if the geocoder should query as the user types to autocomplete
|
||||
* @param {number} [options.flightDuration=1.5] The duration of the camera flight to an entered location, in seconds.
|
||||
* @param {Geocoder.DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode. If not supplied, the default behavior is to fly the camera to the result destination.
|
||||
*/
|
||||
function Geocoder(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.container)) {
|
||||
throw new DeveloperError("options.container is required.");
|
||||
}
|
||||
if (!defined(options.scene)) {
|
||||
throw new DeveloperError("options.scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const container = getElement(options.container);
|
||||
const viewModel = new GeocoderViewModel(options);
|
||||
|
||||
viewModel._startSearchPath = startSearchPath;
|
||||
viewModel._stopSearchPath = stopSearchPath;
|
||||
|
||||
const form = document.createElement("form");
|
||||
form.setAttribute("data-bind", "submit: search");
|
||||
|
||||
const textBox = document.createElement("input");
|
||||
textBox.type = "search";
|
||||
textBox.className = "cesium-geocoder-input";
|
||||
textBox.setAttribute("placeholder", "Enter an address or landmark...");
|
||||
textBox.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
textInput: searchText,\
|
||||
disable: isSearchInProgress,\
|
||||
event: { keyup: handleKeyUp, keydown: handleKeyDown, mouseover: deselectSuggestion },\
|
||||
css: { "cesium-geocoder-input-wide" : keepExpanded || searchText.length > 0 },\
|
||||
hasFocus: _focusTextbox',
|
||||
);
|
||||
|
||||
this._onTextBoxFocus = function () {
|
||||
// as of 2016-10-19, setTimeout is required to ensure that the
|
||||
// text is focused on Safari 10
|
||||
setTimeout(function () {
|
||||
textBox.select();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
textBox.addEventListener("focus", this._onTextBoxFocus, false);
|
||||
form.appendChild(textBox);
|
||||
this._textBox = textBox;
|
||||
|
||||
const searchButton = document.createElement("span");
|
||||
searchButton.className = "cesium-geocoder-searchButton";
|
||||
searchButton.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
click: search,\
|
||||
cesiumSvgPath: { path: isSearchInProgress ? _stopSearchPath : _startSearchPath, width: 32, height: 32 }",
|
||||
);
|
||||
form.appendChild(searchButton);
|
||||
|
||||
container.appendChild(form);
|
||||
|
||||
const searchSuggestionsContainer = document.createElement("div");
|
||||
searchSuggestionsContainer.className = "search-results";
|
||||
searchSuggestionsContainer.setAttribute(
|
||||
"data-bind",
|
||||
"visible: _suggestionsVisible",
|
||||
);
|
||||
|
||||
const suggestionsList = document.createElement("ul");
|
||||
suggestionsList.setAttribute("data-bind", "foreach: _suggestions");
|
||||
const suggestions = document.createElement("li");
|
||||
suggestionsList.appendChild(suggestions);
|
||||
suggestions.setAttribute(
|
||||
"data-bind",
|
||||
"text: $data.displayName, \
|
||||
click: $parent.activateSuggestion, \
|
||||
event: { mouseover: $parent.handleMouseover}, \
|
||||
css: { active: $data === $parent._selectedSuggestion }",
|
||||
);
|
||||
|
||||
searchSuggestionsContainer.appendChild(suggestionsList);
|
||||
container.appendChild(searchSuggestionsContainer);
|
||||
|
||||
knockout.applyBindings(viewModel, form);
|
||||
knockout.applyBindings(viewModel, searchSuggestionsContainer);
|
||||
|
||||
this._container = container;
|
||||
this._searchSuggestionsContainer = searchSuggestionsContainer;
|
||||
this._viewModel = viewModel;
|
||||
this._form = form;
|
||||
|
||||
this._onInputBegin = function (e) {
|
||||
// e.target will not be correct if we are inside of the Shadow DOM
|
||||
// and contains will always fail. To retrieve the correct target,
|
||||
// we need to access the first element of the composedPath.
|
||||
// This allows us to use shadow DOM if it exists and fall
|
||||
// back to legacy behavior if its not being used.
|
||||
|
||||
let target = e.target;
|
||||
if (typeof e.composedPath === "function") {
|
||||
target = e.composedPath()[0];
|
||||
}
|
||||
|
||||
if (!container.contains(target)) {
|
||||
viewModel._focusTextbox = false;
|
||||
viewModel.hideSuggestions();
|
||||
}
|
||||
};
|
||||
|
||||
this._onInputEnd = function (e) {
|
||||
viewModel._focusTextbox = true;
|
||||
viewModel.showSuggestions();
|
||||
};
|
||||
|
||||
//We subscribe to both begin and end events in order to give the text box
|
||||
//focus no matter where on the widget is clicked.
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._onInputBegin, true);
|
||||
container.addEventListener("pointerup", this._onInputEnd, true);
|
||||
container.addEventListener("pointercancel", this._onInputEnd, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._onInputBegin, true);
|
||||
container.addEventListener("mouseup", this._onInputEnd, true);
|
||||
document.addEventListener("touchstart", this._onInputBegin, true);
|
||||
container.addEventListener("touchend", this._onInputEnd, true);
|
||||
container.addEventListener("touchcancel", this._onInputEnd, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(Geocoder.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
searchSuggestionsContainer: {
|
||||
get: function () {
|
||||
return this._searchSuggestionsContainer;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof Geocoder.prototype
|
||||
*
|
||||
* @type {GeocoderViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
Geocoder.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
Geocoder.prototype.destroy = function () {
|
||||
const container = this._container;
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._onInputBegin, true);
|
||||
container.removeEventListener("pointerup", this._onInputEnd, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._onInputBegin, true);
|
||||
container.removeEventListener("mouseup", this._onInputEnd, true);
|
||||
document.removeEventListener("touchstart", this._onInputBegin, true);
|
||||
container.removeEventListener("touchend", this._onInputEnd, true);
|
||||
}
|
||||
this._viewModel.destroy();
|
||||
knockout.cleanNode(this._form);
|
||||
knockout.cleanNode(this._searchSuggestionsContainer);
|
||||
container.removeChild(this._form);
|
||||
container.removeChild(this._searchSuggestionsContainer);
|
||||
this._textBox.removeEventListener("focus", this._onTextBoxFocus, false);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
|
||||
/**
|
||||
* A function that handles the result of a successful geocode.
|
||||
* @callback Geocoder.DestinationFoundFunction
|
||||
* @param {GeocoderViewModel} viewModel The view model.
|
||||
* @param {Cartesian3|Rectangle} destination The destination result of the geocode.
|
||||
*/
|
||||
export default Geocoder;
|
||||
@@ -0,0 +1,607 @@
|
||||
import {
|
||||
computeFlyToLocationForRectangle,
|
||||
defined,
|
||||
DeveloperError,
|
||||
destroyObject,
|
||||
Event,
|
||||
GeocoderService,
|
||||
GeocodeType,
|
||||
getElement,
|
||||
IonGeocoderService,
|
||||
Math as CesiumMath,
|
||||
Matrix4,
|
||||
Rectangle,
|
||||
sampleTerrainMostDetailed,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
// The height we use if geocoding to a specific point instead of an rectangle.
|
||||
const DEFAULT_HEIGHT = 1000;
|
||||
|
||||
/**
|
||||
* The view model for the {@link Geocoder} widget.
|
||||
* @alias GeocoderViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Scene} options.scene The Scene instance to use.
|
||||
* @param {GeocoderService[]} [options.geocoderServices] Geocoder services to use for geocoding queries.
|
||||
* If more than one are supplied, suggestions will be gathered for the geocoders that support it,
|
||||
* and if no suggestion is selected the result from the first geocoder service wil be used.
|
||||
* @param {number} [options.flightDuration] The duration of the camera flight to an entered location, in seconds.
|
||||
* @param {Geocoder.DestinationFoundFunction} [options.destinationFound=GeocoderViewModel.flyToDestination] A callback function that is called after a successful geocode. If not supplied, the default behavior is to fly the camera to the result destination.
|
||||
*/
|
||||
function GeocoderViewModel(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.scene)) {
|
||||
throw new DeveloperError("options.scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
if (defined(options.geocoderServices)) {
|
||||
this._geocoderServices = options.geocoderServices;
|
||||
} else {
|
||||
this._geocoderServices = [new IonGeocoderService({ scene: options.scene })];
|
||||
}
|
||||
|
||||
this._viewContainer = options.container;
|
||||
this._scene = options.scene;
|
||||
this._flightDuration = options.flightDuration;
|
||||
this._searchText = "";
|
||||
this._isSearchInProgress = false;
|
||||
this._wasGeocodeCancelled = false;
|
||||
this._previousCredits = [];
|
||||
this._complete = new Event();
|
||||
this._suggestions = [];
|
||||
this._selectedSuggestion = undefined;
|
||||
this._showSuggestions = true;
|
||||
|
||||
this._handleArrowDown = handleArrowDown;
|
||||
this._handleArrowUp = handleArrowUp;
|
||||
|
||||
const that = this;
|
||||
|
||||
this._suggestionsVisible = knockout.pureComputed(function () {
|
||||
const suggestions = knockout.getObservable(that, "_suggestions");
|
||||
const suggestionsNotEmpty = suggestions().length > 0;
|
||||
const showSuggestions = knockout.getObservable(that, "_showSuggestions")();
|
||||
return suggestionsNotEmpty && showSuggestions;
|
||||
});
|
||||
|
||||
this._searchCommand = createCommand(function (geocodeType) {
|
||||
geocodeType = geocodeType ?? GeocodeType.SEARCH;
|
||||
that._focusTextbox = false;
|
||||
if (defined(that._selectedSuggestion)) {
|
||||
that.activateSuggestion(that._selectedSuggestion);
|
||||
return false;
|
||||
}
|
||||
that.hideSuggestions();
|
||||
if (that.isSearchInProgress) {
|
||||
cancelGeocode(that);
|
||||
} else {
|
||||
return geocode(that, that._geocoderServices, geocodeType);
|
||||
}
|
||||
});
|
||||
|
||||
this.deselectSuggestion = function () {
|
||||
that._selectedSuggestion = undefined;
|
||||
};
|
||||
|
||||
this.handleKeyDown = function (data, event) {
|
||||
const downKey =
|
||||
event.key === "ArrowDown" || event.key === "Down" || event.keyCode === 40;
|
||||
const upKey =
|
||||
event.key === "ArrowUp" || event.key === "Up" || event.keyCode === 38;
|
||||
if (downKey || upKey) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.handleKeyUp = function (data, event) {
|
||||
const downKey =
|
||||
event.key === "ArrowDown" || event.key === "Down" || event.keyCode === 40;
|
||||
const upKey =
|
||||
event.key === "ArrowUp" || event.key === "Up" || event.keyCode === 38;
|
||||
const enterKey = event.key === "Enter" || event.keyCode === 13;
|
||||
if (upKey) {
|
||||
handleArrowUp(that);
|
||||
} else if (downKey) {
|
||||
handleArrowDown(that);
|
||||
} else if (enterKey) {
|
||||
that._searchCommand();
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.activateSuggestion = function (data) {
|
||||
that.hideSuggestions();
|
||||
that._searchText = data.displayName;
|
||||
const destination = data.destination;
|
||||
clearSuggestions(that);
|
||||
that.destinationFound(that, destination);
|
||||
};
|
||||
|
||||
this.hideSuggestions = function () {
|
||||
that._showSuggestions = false;
|
||||
that._selectedSuggestion = undefined;
|
||||
};
|
||||
|
||||
this.showSuggestions = function () {
|
||||
that._showSuggestions = true;
|
||||
};
|
||||
|
||||
this.handleMouseover = function (data, event) {
|
||||
if (data !== that._selectedSuggestion) {
|
||||
that._selectedSuggestion = data;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets or sets a value indicating if this instance should always show its text input field.
|
||||
*
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.keepExpanded = false;
|
||||
|
||||
/**
|
||||
* True if the geocoder should query as the user types to autocomplete
|
||||
* @type {boolean}
|
||||
* @default true
|
||||
*/
|
||||
this.autoComplete = options.autocomplete ?? true;
|
||||
|
||||
/**
|
||||
* Gets and sets the command called when a geocode destination is found
|
||||
* @type {Geocoder.DestinationFoundFunction}
|
||||
*/
|
||||
this.destinationFound =
|
||||
options.destinationFound ?? GeocoderViewModel.flyToDestination;
|
||||
|
||||
this._focusTextbox = false;
|
||||
|
||||
knockout.track(this, [
|
||||
"_searchText",
|
||||
"_isSearchInProgress",
|
||||
"keepExpanded",
|
||||
"_suggestions",
|
||||
"_selectedSuggestion",
|
||||
"_showSuggestions",
|
||||
"_focusTextbox",
|
||||
]);
|
||||
|
||||
const searchTextObservable = knockout.getObservable(this, "_searchText");
|
||||
searchTextObservable.extend({ rateLimit: { timeout: 500 } });
|
||||
this._suggestionSubscription = searchTextObservable.subscribe(function () {
|
||||
GeocoderViewModel._updateSearchSuggestions(that);
|
||||
});
|
||||
/**
|
||||
* Gets a value indicating whether a search is currently in progress. This property is observable.
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isSearchInProgress = undefined;
|
||||
knockout.defineProperty(this, "isSearchInProgress", {
|
||||
get: function () {
|
||||
return this._isSearchInProgress;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the text to search for. The text can be an address, or longitude, latitude,
|
||||
* and optional height, where longitude and latitude are in degrees and height is in meters.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.searchText = undefined;
|
||||
knockout.defineProperty(this, "searchText", {
|
||||
get: function () {
|
||||
if (this.isSearchInProgress) {
|
||||
return "Searching...";
|
||||
}
|
||||
|
||||
return this._searchText;
|
||||
},
|
||||
set: function (value) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (typeof value !== "string") {
|
||||
throw new DeveloperError("value must be a valid string.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
this._searchText = value;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the the duration of the camera flight in seconds.
|
||||
* A value of zero causes the camera to instantly switch to the geocoding location.
|
||||
* The duration will be computed based on the distance when undefined.
|
||||
*
|
||||
* @type {number|undefined}
|
||||
* @default undefined
|
||||
*/
|
||||
this.flightDuration = undefined;
|
||||
knockout.defineProperty(this, "flightDuration", {
|
||||
get: function () {
|
||||
return this._flightDuration;
|
||||
},
|
||||
set: function (value) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (defined(value) && value < 0) {
|
||||
throw new DeveloperError("value must be positive.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._flightDuration = value;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperties(GeocoderViewModel.prototype, {
|
||||
/**
|
||||
* Gets the event triggered on flight completion.
|
||||
* @memberof GeocoderViewModel.prototype
|
||||
*
|
||||
* @type {Event}
|
||||
*/
|
||||
complete: {
|
||||
get: function () {
|
||||
return this._complete;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the scene to control.
|
||||
* @memberof GeocoderViewModel.prototype
|
||||
*
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Command that is executed when the button is clicked.
|
||||
* @memberof GeocoderViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
search: {
|
||||
get: function () {
|
||||
return this._searchCommand;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the currently selected geocoder search suggestion
|
||||
* @memberof GeocoderViewModel.prototype
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
selectedSuggestion: {
|
||||
get: function () {
|
||||
return this._selectedSuggestion;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the list of geocoder search suggestions
|
||||
* @memberof GeocoderViewModel.prototype
|
||||
*
|
||||
* @type {object[]}
|
||||
*/
|
||||
suggestions: {
|
||||
get: function () {
|
||||
return this._suggestions;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function handleArrowUp(viewModel) {
|
||||
if (viewModel._suggestions.length === 0) {
|
||||
return;
|
||||
}
|
||||
const currentIndex = viewModel._suggestions.indexOf(
|
||||
viewModel._selectedSuggestion,
|
||||
);
|
||||
if (currentIndex === -1 || currentIndex === 0) {
|
||||
viewModel._selectedSuggestion = undefined;
|
||||
return;
|
||||
}
|
||||
const next = currentIndex - 1;
|
||||
viewModel._selectedSuggestion = viewModel._suggestions[next];
|
||||
GeocoderViewModel._adjustSuggestionsScroll(viewModel, next);
|
||||
}
|
||||
|
||||
function handleArrowDown(viewModel) {
|
||||
if (viewModel._suggestions.length === 0) {
|
||||
return;
|
||||
}
|
||||
const numberOfSuggestions = viewModel._suggestions.length;
|
||||
const currentIndex = viewModel._suggestions.indexOf(
|
||||
viewModel._selectedSuggestion,
|
||||
);
|
||||
const next = (currentIndex + 1) % numberOfSuggestions;
|
||||
viewModel._selectedSuggestion = viewModel._suggestions[next];
|
||||
|
||||
GeocoderViewModel._adjustSuggestionsScroll(viewModel, next);
|
||||
}
|
||||
|
||||
function computeFlyToLocationForCartographic(cartographic, terrainProvider) {
|
||||
const availability = defined(terrainProvider)
|
||||
? terrainProvider.availability
|
||||
: undefined;
|
||||
|
||||
if (!defined(availability)) {
|
||||
cartographic.height += DEFAULT_HEIGHT;
|
||||
return Promise.resolve(cartographic);
|
||||
}
|
||||
|
||||
return sampleTerrainMostDetailed(terrainProvider, [cartographic]).then(
|
||||
function (positionOnTerrain) {
|
||||
cartographic = positionOnTerrain[0];
|
||||
cartographic.height += DEFAULT_HEIGHT;
|
||||
return cartographic;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function flyToDestination(viewModel, destination) {
|
||||
const scene = viewModel._scene;
|
||||
const ellipsoid = scene.ellipsoid;
|
||||
|
||||
const camera = scene.camera;
|
||||
const terrainProvider = scene.terrainProvider;
|
||||
let finalDestination = destination;
|
||||
|
||||
let promise;
|
||||
if (destination instanceof Rectangle) {
|
||||
// Some geocoders return a Rectangle of zero width/height, treat it like a point instead.
|
||||
if (
|
||||
CesiumMath.equalsEpsilon(
|
||||
destination.south,
|
||||
destination.north,
|
||||
CesiumMath.EPSILON7,
|
||||
) &&
|
||||
CesiumMath.equalsEpsilon(
|
||||
destination.east,
|
||||
destination.west,
|
||||
CesiumMath.EPSILON7,
|
||||
)
|
||||
) {
|
||||
// destination is now a Cartographic
|
||||
destination = Rectangle.center(destination);
|
||||
} else {
|
||||
promise = computeFlyToLocationForRectangle(destination, scene);
|
||||
}
|
||||
} else {
|
||||
// destination is a Cartesian3
|
||||
destination = ellipsoid.cartesianToCartographic(destination);
|
||||
}
|
||||
|
||||
if (!defined(promise)) {
|
||||
promise = computeFlyToLocationForCartographic(destination, terrainProvider);
|
||||
}
|
||||
|
||||
return promise
|
||||
.then(function (result) {
|
||||
finalDestination = ellipsoid.cartographicToCartesian(result);
|
||||
})
|
||||
.finally(function () {
|
||||
// Whether terrain querying succeeded or not, fly to the destination.
|
||||
camera.flyTo({
|
||||
destination: finalDestination,
|
||||
complete: function () {
|
||||
viewModel._complete.raiseEvent();
|
||||
},
|
||||
duration: viewModel._flightDuration,
|
||||
endTransform: Matrix4.IDENTITY,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function attemptGeocode(geocoderService, query, geocodeType) {
|
||||
try {
|
||||
const result = await geocoderService.geocode(query, geocodeType);
|
||||
return {
|
||||
state: "fulfilled",
|
||||
value: result,
|
||||
credits: geocoderService.credit,
|
||||
};
|
||||
} catch (error) {
|
||||
return { state: "rejected", reason: error };
|
||||
}
|
||||
}
|
||||
|
||||
async function geocode(viewModel, geocoderServices, geocodeType) {
|
||||
const query = viewModel._searchText;
|
||||
|
||||
if (hasOnlyWhitespace(query)) {
|
||||
viewModel.showSuggestions();
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel._isSearchInProgress = true;
|
||||
viewModel._wasGeocodeCancelled = false;
|
||||
|
||||
let i;
|
||||
let result;
|
||||
for (i = 0; i < geocoderServices.length; i++) {
|
||||
if (viewModel._wasGeocodeCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
result = await attemptGeocode(geocoderServices[i], query, geocodeType);
|
||||
if (
|
||||
defined(result) &&
|
||||
result.state === "fulfilled" &&
|
||||
result.value.length > 0
|
||||
) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (viewModel._wasGeocodeCancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel._isSearchInProgress = false;
|
||||
clearCredits(viewModel);
|
||||
|
||||
const geocoderResults = result.value;
|
||||
if (
|
||||
result.state === "fulfilled" &&
|
||||
defined(geocoderResults) &&
|
||||
geocoderResults.length > 0
|
||||
) {
|
||||
viewModel._searchText = geocoderResults[0].displayName;
|
||||
viewModel.destinationFound(viewModel, geocoderResults[0].destination);
|
||||
const credits = updateCredits(
|
||||
viewModel,
|
||||
GeocoderService.getCreditsFromResult(geocoderResults[0]),
|
||||
);
|
||||
// If the result does not contain any credits, default to the service credit.
|
||||
if (!defined(credits)) {
|
||||
updateCredit(viewModel, geocoderServices[i].credit);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel._searchText = `${query} (not found)`;
|
||||
}
|
||||
|
||||
function updateCredit(viewModel, credit) {
|
||||
if (
|
||||
defined(credit) &&
|
||||
!viewModel._scene.isDestroyed() &&
|
||||
!viewModel._scene.frameState.creditDisplay.isDestroyed()
|
||||
) {
|
||||
viewModel._scene.frameState.creditDisplay.addStaticCredit(credit);
|
||||
viewModel._previousCredits.push(credit);
|
||||
}
|
||||
}
|
||||
|
||||
function updateCredits(viewModel, credits) {
|
||||
if (defined(credits)) {
|
||||
credits.forEach((credit) => updateCredit(viewModel, credit));
|
||||
}
|
||||
|
||||
return credits;
|
||||
}
|
||||
|
||||
function clearCredits(viewModel) {
|
||||
if (
|
||||
!viewModel._scene.isDestroyed() &&
|
||||
!viewModel._scene.frameState.creditDisplay.isDestroyed()
|
||||
) {
|
||||
viewModel._previousCredits.forEach((credit) => {
|
||||
viewModel._scene.frameState.creditDisplay.removeStaticCredit(credit);
|
||||
});
|
||||
}
|
||||
|
||||
viewModel._previousCredits.length = 0;
|
||||
}
|
||||
|
||||
function adjustSuggestionsScroll(viewModel, focusedItemIndex) {
|
||||
const container = getElement(viewModel._viewContainer);
|
||||
const searchResults = container.getElementsByClassName("search-results")[0];
|
||||
const listItems = container.getElementsByTagName("li");
|
||||
const element = listItems[focusedItemIndex];
|
||||
|
||||
if (focusedItemIndex === 0) {
|
||||
searchResults.scrollTop = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const offsetTop = element.offsetTop;
|
||||
if (offsetTop + element.clientHeight > searchResults.clientHeight) {
|
||||
searchResults.scrollTop = offsetTop + element.clientHeight;
|
||||
} else if (offsetTop < searchResults.scrollTop) {
|
||||
searchResults.scrollTop = offsetTop;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelGeocode(viewModel) {
|
||||
if (viewModel._isSearchInProgress) {
|
||||
viewModel._isSearchInProgress = false;
|
||||
viewModel._wasGeocodeCancelled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function hasOnlyWhitespace(string) {
|
||||
return /^\s*$/.test(string);
|
||||
}
|
||||
|
||||
function clearSuggestions(viewModel) {
|
||||
knockout.getObservable(viewModel, "_suggestions").removeAll();
|
||||
}
|
||||
|
||||
async function updateSearchSuggestions(viewModel) {
|
||||
if (!viewModel.autoComplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
const query = viewModel._searchText;
|
||||
|
||||
clearSuggestions(viewModel);
|
||||
clearCredits(viewModel);
|
||||
|
||||
if (hasOnlyWhitespace(query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const service of viewModel._geocoderServices) {
|
||||
const newResults = await service.geocode(query, GeocodeType.AUTOCOMPLETE);
|
||||
viewModel._suggestions = viewModel._suggestions.concat(newResults);
|
||||
if (newResults.length > 0) {
|
||||
let useDefaultCredit = true;
|
||||
newResults.forEach((result) => {
|
||||
const credits = GeocoderService.getCreditsFromResult(result);
|
||||
useDefaultCredit = useDefaultCredit && !defined(credits);
|
||||
updateCredits(viewModel, credits);
|
||||
});
|
||||
|
||||
// Use the service credit if there were no attributions in the results
|
||||
if (useDefaultCredit) {
|
||||
updateCredit(viewModel, service.credit);
|
||||
}
|
||||
}
|
||||
|
||||
if (viewModel._suggestions.length >= 5) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function to fly to the destination found by a successful geocode.
|
||||
* @type {Geocoder.DestinationFoundFunction}
|
||||
*/
|
||||
GeocoderViewModel.flyToDestination = flyToDestination;
|
||||
|
||||
//exposed for testing
|
||||
GeocoderViewModel._updateSearchSuggestions = updateSearchSuggestions;
|
||||
GeocoderViewModel._adjustSuggestionsScroll = adjustSuggestionsScroll;
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
GeocoderViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
GeocoderViewModel.prototype.destroy = function () {
|
||||
this._suggestionSubscription.dispose();
|
||||
clearCredits(this);
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default GeocoderViewModel;
|
||||
@@ -0,0 +1,19 @@
|
||||
.cesium-lighter .cesium-geocoder-input {
|
||||
border: solid 1px #759dc0;
|
||||
background-color: rgba(240, 240, 240, 0.9);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-viewer-geocoderContainer:hover .cesium-geocoder-input {
|
||||
border-color: #aef;
|
||||
box-shadow: 0 0 8px #fff;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-geocoder-searchButton {
|
||||
background-color: #e2f0ff;
|
||||
fill: #111;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-geocoder-searchButton:hover {
|
||||
background-color: #a6d2ff;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import HomeButtonViewModel from "./HomeButtonViewModel.js";
|
||||
|
||||
/**
|
||||
* A single button widget for returning to the default camera view of the current scene.
|
||||
*
|
||||
* @alias HomeButton
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene The Scene instance to use.
|
||||
* @param {number} [duration] The time, in seconds, it takes to complete the camera flight home.
|
||||
*/
|
||||
function HomeButton(container, scene, duration) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const viewModel = new HomeButtonViewModel(scene, duration);
|
||||
|
||||
viewModel._svgPath =
|
||||
"M14,4l-10,8.75h20l-4.25-3.7188v-4.6562h-2.812v2.1875l-2.938-2.5625zm-7.0938,9.906v10.094h14.094v-10.094h-14.094zm2.1876,2.313h3.3122v4.25h-3.3122v-4.25zm5.8442,1.281h3.406v6.438h-3.406v-6.438z";
|
||||
|
||||
const element = document.createElement("button");
|
||||
element.type = "button";
|
||||
element.className = "cesium-button cesium-toolbar-button cesium-home-button";
|
||||
element.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
attr: { title: tooltip },\
|
||||
click: command,\
|
||||
cesiumSvgPath: { path: _svgPath, width: 28, height: 28 }",
|
||||
);
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
knockout.applyBindings(viewModel, element);
|
||||
|
||||
this._container = container;
|
||||
this._viewModel = viewModel;
|
||||
this._element = element;
|
||||
}
|
||||
|
||||
Object.defineProperties(HomeButton.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof HomeButton.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof HomeButton.prototype
|
||||
*
|
||||
* @type {HomeButtonViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
HomeButton.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
HomeButton.prototype.destroy = function () {
|
||||
knockout.cleanNode(this._element);
|
||||
this._container.removeChild(this._element);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default HomeButton;
|
||||
@@ -0,0 +1,86 @@
|
||||
import { defined, DeveloperError } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link HomeButton}.
|
||||
* @alias HomeButtonViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Scene} scene The scene instance to use.
|
||||
* @param {number} [duration] The duration of the camera flight in seconds.
|
||||
*/
|
||||
function HomeButtonViewModel(scene, duration) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._scene = scene;
|
||||
this._duration = duration;
|
||||
|
||||
const that = this;
|
||||
this._command = createCommand(function () {
|
||||
that._scene.camera.flyHome(that._duration);
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the tooltip. This property is observable.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.tooltip = "View Home";
|
||||
|
||||
knockout.track(this, ["tooltip"]);
|
||||
}
|
||||
|
||||
Object.defineProperties(HomeButtonViewModel.prototype, {
|
||||
/**
|
||||
* Gets the scene to control.
|
||||
* @memberof HomeButtonViewModel.prototype
|
||||
*
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Command that is executed when the button is clicked.
|
||||
* @memberof HomeButtonViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
command: {
|
||||
get: function () {
|
||||
return this._command;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the the duration of the camera flight in seconds.
|
||||
* A value of zero causes the camera to instantly switch to home view.
|
||||
* The duration will be computed based on the distance when undefined.
|
||||
* @memberof HomeButtonViewModel.prototype
|
||||
*
|
||||
* @type {number|undefined}
|
||||
*/
|
||||
duration: {
|
||||
get: function () {
|
||||
return this._duration;
|
||||
},
|
||||
set: function (value) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (defined(value) && value < 0) {
|
||||
throw new DeveloperError("value must be positive.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._duration = value;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default HomeButtonViewModel;
|
||||
@@ -0,0 +1,31 @@
|
||||
.cesium-viewer-i3s-explorer ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.cesium-viewer-i3s-explorer .layersList {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cesium-viewer-i3s-explorer input {
|
||||
margin: 0 3px 0 0;
|
||||
}
|
||||
.cesium-viewer-i3s-explorer .expandItem {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.cesium-viewer-i3s-explorer .nested,
|
||||
.cesium-viewer-i3s-explorer #bsl-wrapper {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-viewer-i3s-explorer .active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cesium-viewer-i3s-explorer .li-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
import { Check, defined } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import I3SBuildingSceneLayerExplorerViewModel from "./I3SBuildingSceneLayerExplorerViewModel.js";
|
||||
|
||||
/**
|
||||
* I3S Building Scene Layer widget
|
||||
*
|
||||
* @alias I3SBuildingSceneLayerExplorer
|
||||
* @constructor
|
||||
*
|
||||
* @param {string} containerId The DOM element ID that will contain the widget.
|
||||
* @param {I3SDataProvider} i3sProvider I3S Data provider instance.
|
||||
*
|
||||
* @demo {@link https://sandcastle.cesium.com/index.html?id=i3s-building-scene-layer|I3S Building Scene Layer}
|
||||
*/
|
||||
function I3SBuildingSceneLayerExplorer(containerId, i3sProvider) {
|
||||
const container = document.getElementById(containerId);
|
||||
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.defined("container", container);
|
||||
Check.defined("i3sProvider", i3sProvider);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const htmlWrapper = document.createElement("div");
|
||||
htmlWrapper.classList.add("cesium-viewer-i3s-explorer");
|
||||
htmlWrapper.innerHTML = `
|
||||
<h3>Building explorer</h3>
|
||||
<select
|
||||
data-bind="options: topLayers, optionsText: 'name', optionsAfterRender: setOptionDisable, value: currentLayer"
|
||||
></select>
|
||||
<div id="bsl-wrapper">
|
||||
<h3>Select Level</h3>
|
||||
<select data-bind="options: levels, value: currentLevel"></select>
|
||||
<h3>Disciplines & Categories</h3>
|
||||
<ul class="layersList" data-bind="foreach: sublayers">
|
||||
<ul class="layersList" data-bind="foreach: sublayers.sort(function (l, r) { return l.name.localeCompare(r.name) })">
|
||||
<li>
|
||||
<div class="li-wrapper">
|
||||
<span
|
||||
class="expandItem"
|
||||
data-bind="click: $root.expandClickHandler"
|
||||
>+</span
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
data-bind="checked: visibility, valueUpdate: 'input', attr: { id: name}"
|
||||
/>
|
||||
<label data-bind="attr: { for: name}">
|
||||
<span data-bind="text: name"></span>
|
||||
</label>
|
||||
</div>
|
||||
<ul class="nested" data-bind="attr: { id: name + '-expander'}">
|
||||
<li data-bind="foreach: sublayers.sort(function (l, r) { return l.name.localeCompare(r.name) })">
|
||||
<div class="li-wrapper">
|
||||
<input
|
||||
type="checkbox"
|
||||
data-bind="checked: visibility, valueUpdate: 'input', attr: { id: name}"
|
||||
/>
|
||||
<label data-bind="attr: { for: name}">
|
||||
<span data-bind="text: name"></span>
|
||||
</label>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>`;
|
||||
container.appendChild(htmlWrapper);
|
||||
|
||||
const viewModel = new I3SBuildingSceneLayerExplorerViewModel(i3sProvider);
|
||||
|
||||
knockout.track(viewModel);
|
||||
knockout.applyBindings(viewModel, container);
|
||||
|
||||
if (defined(viewModel.defaultLayer)) {
|
||||
// Select a model by default
|
||||
viewModel.currentLayer = viewModel.defaultLayer;
|
||||
}
|
||||
}
|
||||
export default I3SBuildingSceneLayerExplorer;
|
||||
@@ -0,0 +1,173 @@
|
||||
import { defined } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
|
||||
function expandItemsHandler(data, event) {
|
||||
const nestedList =
|
||||
event.currentTarget.parentElement.parentElement.querySelector(
|
||||
`#${data.name}-expander`,
|
||||
);
|
||||
nestedList.classList.toggle("active");
|
||||
event.currentTarget.textContent =
|
||||
event.currentTarget.textContent === "+" ? "-" : "+";
|
||||
}
|
||||
|
||||
function trackSublayer(sublayer, viewModel) {
|
||||
knockout.track(sublayer);
|
||||
|
||||
for (let i = 0; i < sublayer.sublayers.length; i++) {
|
||||
trackSublayer(sublayer.sublayers[i], viewModel);
|
||||
}
|
||||
}
|
||||
|
||||
function isFullModel(layer) {
|
||||
return layer.modelName === "FullModel";
|
||||
}
|
||||
|
||||
function isOverview(layer) {
|
||||
return layer.modelName === "Overview";
|
||||
}
|
||||
|
||||
function isTopLayer(layer) {
|
||||
return isOverview(layer) || isFullModel(layer);
|
||||
}
|
||||
|
||||
function addTopLayer(layer, viewModel) {
|
||||
if (isTopLayer(layer)) {
|
||||
layer.visibility = false;
|
||||
for (let i = 0; i < layer.sublayers.length; i++) {
|
||||
layer.sublayers[i].visibility = true;
|
||||
}
|
||||
|
||||
const topLayer = {
|
||||
name: layer.name,
|
||||
modelName: layer.modelName,
|
||||
disable: knockout.observable(false),
|
||||
index: viewModel.sublayers.length,
|
||||
};
|
||||
viewModel.topLayers.push(topLayer);
|
||||
viewModel.sublayers.push(layer);
|
||||
return topLayer;
|
||||
}
|
||||
}
|
||||
|
||||
function handleTopLayerSelector(layer, viewModel) {
|
||||
if (isTopLayer(layer)) {
|
||||
viewModel.sublayers.forEach((elem) => (elem.visibility = false));
|
||||
viewModel.sublayers[layer.index].visibility = true;
|
||||
const bsl = document.getElementById("bsl-wrapper");
|
||||
if (isFullModel(layer)) {
|
||||
viewModel.currentLevel = viewModel.selectedLevel;
|
||||
bsl.style.display = "block";
|
||||
} else {
|
||||
viewModel.selectedLevel = viewModel.currentLevel;
|
||||
viewModel.currentLevel = "All";
|
||||
bsl.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function setLevels(i3sProvider, levels) {
|
||||
try {
|
||||
const attributes = i3sProvider.getAttributeNames();
|
||||
for (let index = 0; index < attributes.length; index++) {
|
||||
if (attributes[index] === "BldgLevel") {
|
||||
const values = i3sProvider.getAttributeValues(attributes[index]);
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
levels.push(values[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
levels.sort((a, b) => a - b);
|
||||
levels.unshift("All");
|
||||
} catch (error) {
|
||||
console.log(`There was an error getting attributes: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The view model for {@link I3SBuildingSceneLayerExplorer}.
|
||||
* @alias I3sBslExplorerViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {I3SDataProvider} i3sProvider I3S Data provider instance.
|
||||
*/
|
||||
function I3SBuildingSceneLayerExplorerViewModel(i3sProvider) {
|
||||
const that = this;
|
||||
this.levels = [];
|
||||
this.viewModel = {
|
||||
sublayers: [],
|
||||
levels: this.levels,
|
||||
currentLevel: knockout.observable(),
|
||||
selectedLevel: "All",
|
||||
topLayers: [
|
||||
{
|
||||
name: "Select a layer to explore...",
|
||||
disable: knockout.observable(true),
|
||||
index: -1,
|
||||
},
|
||||
],
|
||||
currentLayer: knockout.observable(),
|
||||
expandClickHandler: expandItemsHandler,
|
||||
setOptionDisable: function (option, item) {
|
||||
knockout.applyBindingsToNode(option, { disable: item.disable }, item);
|
||||
},
|
||||
defaultLayer: undefined,
|
||||
};
|
||||
|
||||
// Handling change of a layer for exploring
|
||||
this.viewModel.currentLayer.subscribe(function (layer) {
|
||||
handleTopLayerSelector(layer, that.viewModel);
|
||||
});
|
||||
|
||||
// Setting a sublayers tree to the viewModel
|
||||
const sublayers = i3sProvider.sublayers;
|
||||
for (let i = 0; i < sublayers.length; i++) {
|
||||
trackSublayer(sublayers[i], this.viewModel);
|
||||
const topLayer = addTopLayer(sublayers[i], this.viewModel);
|
||||
if (
|
||||
defined(topLayer) &&
|
||||
(isOverview(topLayer) ||
|
||||
(!defined(this.viewModel.defaultLayer) && isFullModel(topLayer)))
|
||||
) {
|
||||
this.viewModel.defaultLayer = topLayer;
|
||||
}
|
||||
}
|
||||
// There is no Full Model and/or Overview
|
||||
if (this.viewModel.topLayers.length === 1 && sublayers.length > 0) {
|
||||
i3sProvider.show = false;
|
||||
const fullModel = {
|
||||
name: "Full Model",
|
||||
modelName: "FullModel",
|
||||
visibility: i3sProvider.show,
|
||||
sublayers: i3sProvider.sublayers,
|
||||
};
|
||||
this.viewModel.defaultLayer = addTopLayer(fullModel, this.viewModel);
|
||||
this.viewModel.currentLayer.subscribe(function (layer) {
|
||||
i3sProvider.show = isFullModel(layer);
|
||||
});
|
||||
} else if (this.viewModel.topLayers.length === 1) {
|
||||
this.viewModel.topLayers[0].name = "Building layers not found";
|
||||
}
|
||||
|
||||
// Setting levels to the viewModel
|
||||
setLevels(i3sProvider, this.levels);
|
||||
|
||||
// Filtering by levels
|
||||
this.viewModel.currentLevel.subscribe(function (newValue) {
|
||||
if (newValue !== "All") {
|
||||
i3sProvider.filterByAttributes([
|
||||
{
|
||||
name: "BldgLevel",
|
||||
values: [newValue],
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
i3sProvider.filterByAttributes();
|
||||
}
|
||||
});
|
||||
|
||||
return this.viewModel;
|
||||
}
|
||||
|
||||
export default I3SBuildingSceneLayerExplorerViewModel;
|
||||
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 9.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="29.6875"
|
||||
height="40.625095"
|
||||
viewBox="0 0 29.6875 40.625095"
|
||||
enable-background="new 0 0 64 64"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="Mouse.svg"><metadata
|
||||
id="metadata21"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs19" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="747"
|
||||
inkscape:window-height="596"
|
||||
id="namedview17"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.84375"
|
||||
inkscape:cx="-37.919388"
|
||||
inkscape:cy="92.305679"
|
||||
inkscape:window-x="266"
|
||||
inkscape:window-y="72"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:snap-center="false"
|
||||
inkscape:snap-page="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<g
|
||||
id="g3"
|
||||
transform="translate(-17.15625,-19.531154)">
|
||||
<g
|
||||
id="g5"
|
||||
style="fill:#4d4d4d;stroke:#4d4d4d">
|
||||
<path
|
||||
d="M 31.9335,20.041 C 24.639,20.034 17.653,20.318 17.653,44.617 c 0,10.951 8.799,15.032 14.347,15.032 5.545,0 14.347,-4.081 14.347,-15.032 0,-24.27 -7.119,-24.569 -14.4135,-24.576 z m 0.7515,1.358 c 5.643,0.012 10.927,0.236 12.063,16.153 -3.86,1.805 -7.916,2.765 -12.063,2.86 l 0,-2.966 c 0.845,-0.162 1.481,-0.909 1.481,-1.782 l 0,-8.956 c 0,-0.876 -0.637,-1.621 -1.481,-1.784 z m -1.027,4.855 0.685,0 c 0.249,0 0.453,0.205 0.453,0.454 l 0,8.956 c 0,0.249 -0.204,0.449 -0.453,0.449 l -0.685,0 c -0.249,0 -0.452,-0.2 -0.452,-0.449 l 0,-8.956 c 0,-0.249 0.203,-0.454 0.452,-0.454 z m -0.345,-4.855 0,3.525 c -0.845,0.163 -1.479,0.91 -1.479,1.784 l 0,8.956 c 0,0.873 0.634,1.62 1.479,1.782 l 0,2.966 C 25.002,40.264 20.408,38.16 19.25,37.573 20.381,21.633 25.668,21.411 31.313,21.399 z M 32,58.274 c -5.016,0 -12.976,-3.707 -12.976,-13.658 0,-1.983 0.045,-3.853 0.134,-5.563 2.003,0.929 6.696,2.74 12.868,2.74 4.394,0 8.704,-0.934 12.813,-2.771 0.089,1.718 0.135,3.6 0.135,5.595 0,9.95 -7.958,13.657 -12.974,13.657 z"
|
||||
id="path7"
|
||||
style="fill:#4d4d4d;stroke:#4d4d4d"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cssscccccssccsssssssssccssccccsscscss" />
|
||||
</g>
|
||||
|
||||
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 32.922034,38.950793 c 0,-1.135825 0.114919,-1.458045 0.677966,-1.900938 l 0.677966,-0.533288 0,-5.28078 c 0,-5.271249 -0.0012,-5.282003 -0.677966,-5.958745 -0.557439,-0.557439 -0.677966,-0.940935 -0.677966,-2.157165 l 0,-1.479199 1.535487,0 c 5.657554,0 8.584338,3.728529 9.71855,12.380791 0.498434,3.802265 0.50348,3.525731 -0.0676,3.704572 -0.261017,0.08174 -1.528694,0.512016 -2.817059,0.956167 -2.037206,0.702306 -4.048032,1.113044 -7.488026,1.529528 l -0.881356,0.106707 0,-1.36765 z"
|
||||
id="path3768"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 31.485081,35.842143 c -0.104591,-0.104591 -0.190166,-2.231347 -0.190166,-4.726123 0,-3.983994 0.05502,-4.557071 0.452127,-4.709456 0.24867,-0.09542 0.556802,-0.06882 0.684738,0.05912 0.127937,0.127936 0.199056,2.296481 0.158043,4.818988 -0.06319,3.886405 -0.13867,4.598683 -0.494572,4.667009 -0.231003,0.04435 -0.505579,-0.0049 -0.61017,-0.109533 l 0,0 z"
|
||||
id="path3770"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 30.440433,57.945316 c -3.064053,-0.42113 -6.77723,-2.474953 -8.457621,-4.67806 -2.1588,-2.830333 -3.113918,-6.737716 -2.769592,-11.330385 l 0.193121,-2.575872 2.07988,0.735628 c 3.527026,1.247466 6.337701,1.719068 10.215474,1.71405 4.171771,-0.0054 6.642981,-0.38868 10.25836,-1.591058 2.178973,-0.724668 2.692193,-0.815856 2.813444,-0.499883 0.08157,0.21256 0.08664,2.119864 0.01127,4.238453 -0.106217,2.98581 -0.266531,4.212938 -0.712935,5.457208 -1.450217,4.042206 -4.401118,6.844156 -8.437938,8.012017 -2.314747,0.669661 -3.34314,0.772215 -5.193465,0.517902 z"
|
||||
id="path3772"
|
||||
inkscape:connector-curvature="0" /></g>
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644;stroke-opacity:1"
|
||||
d="M 11.584306,20.532528 C 9.1265112,20.247533 6.2927846,19.555647 4.1047676,18.706316 c -0.969492,-0.376332 -1.792939,-0.704961 -1.829884,-0.730287 -0.152564,-0.104584 0.766016,-6.242541 1.16801,-7.804656 1.421191,-5.5226316 4.304477,-8.0618496 9.1542404,-8.0618496 l 1.541531,0 0,1.627119 c 0,1.237125 -0.09381,1.627118 -0.391402,1.627118 -0.215271,0 -0.581373,0.271221 -0.813559,0.602714 -0.345889,0.493826 -0.422157,1.5275241 -0.422157,5.7217066 l 0,5.118992 0.813559,0.759978 c 0.675846,0.631335 0.813559,0.971083 0.813559,2.007108 0,0.835921 -0.111771,1.235378 -0.338983,1.211489 -0.18644,-0.0196 -1.18336,-0.133551 -2.215376,-0.25322 l 0,0 z"
|
||||
id="path3766"
|
||||
inkscape:connector-curvature="0" /></svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="64px"
|
||||
height="64px"
|
||||
viewBox="0 0 64 64"
|
||||
enable-background="new 0 0 64 64"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="MouseLeft.svg"><metadata
|
||||
id="metadata21"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs19" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1282"
|
||||
inkscape:window-height="886"
|
||||
id="namedview17"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.6875"
|
||||
inkscape:cx="-10.305085"
|
||||
inkscape:cy="32"
|
||||
inkscape:window-x="104"
|
||||
inkscape:window-y="136"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g3" />
|
||||
<g
|
||||
id="g3">
|
||||
<g
|
||||
id="g5"
|
||||
style="fill:#4d4d4d;stroke:#4d4d4d">
|
||||
<path
|
||||
fill="#020202"
|
||||
d="M32.854,20.028c-0.015-1.274,0.576-2.269,1.151-3.236c0.758-1.278,1.543-2.6,0.997-4.417 c-0.555-1.667-1.607-2.485-2.539-3.212c-1.254-0.973-2.159-1.676-1.687-4.343l0.041-0.229l-1.35-0.238L29.427,4.58 c-0.615,3.484,0.878,4.643,2.195,5.666c0.85,0.663,1.653,1.288,2.072,2.542c0.366,1.224-0.18,2.143-0.869,3.306 c-0.641,1.081-1.366,2.3-1.349,3.933c-6.837,0.007-13.823,0.291-13.823,24.59c0,10.951,8.799,15.032,14.347,15.032 c5.545,0,14.347-4.081,14.347-15.032C46.347,20.347,39.228,20.048,32.854,20.028z M32.685,21.399 c5.643,0.012,10.927,0.236,12.063,16.153c-3.86,1.805-7.916,2.765-12.063,2.86v-2.966c0.845-0.162,1.481-0.909,1.481-1.782v-8.956 c0-0.876-0.637-1.621-1.481-1.784V21.399z M31.658,26.254h0.685c0.249,0,0.453,0.205,0.453,0.454v8.956 c0,0.249-0.204,0.449-0.453,0.449h-0.685c-0.249,0-0.452-0.2-0.452-0.449v-8.956C31.206,26.459,31.409,26.254,31.658,26.254z M31.313,21.399v3.525c-0.845,0.163-1.479,0.91-1.479,1.784v8.956c0,0.873,0.634,1.62,1.479,1.782v2.966 c-6.311-0.148-10.905-2.252-12.063-2.839C20.381,21.633,25.668,21.411,31.313,21.399z M32,58.274 c-5.016,0-12.976-3.707-12.976-13.658c0-1.983,0.045-3.853,0.134-5.563c2.003,0.929,6.696,2.74,12.868,2.74 c4.394,0,8.704-0.934,12.813-2.771c0.089,1.718,0.135,3.6,0.135,5.595C44.974,54.567,37.016,58.274,32,58.274z"
|
||||
id="path7"
|
||||
style="fill:#4d4d4d;stroke:#4d4d4d" />
|
||||
</g>
|
||||
|
||||
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 32.922034,38.950793 c 0,-1.135825 0.114919,-1.458045 0.677966,-1.900938 l 0.677966,-0.533288 0,-5.28078 c 0,-5.271249 -0.0012,-5.282003 -0.677966,-5.958745 -0.557439,-0.557439 -0.677966,-0.940935 -0.677966,-2.157165 l 0,-1.479199 1.535487,0 c 5.657554,0 8.584338,3.728529 9.71855,12.380791 0.498434,3.802265 0.50348,3.525731 -0.0676,3.704572 -0.261017,0.08174 -1.528694,0.512016 -2.817059,0.956167 -2.037206,0.702306 -4.048032,1.113044 -7.488026,1.529528 l -0.881356,0.106707 0,-1.36765 z"
|
||||
id="path3768"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 31.485081,35.842143 c -0.104591,-0.104591 -0.190166,-2.231347 -0.190166,-4.726123 0,-3.983994 0.05502,-4.557071 0.452127,-4.709456 0.24867,-0.09542 0.556802,-0.06882 0.684738,0.05912 0.127937,0.127936 0.199056,2.296481 0.158043,4.818988 -0.06319,3.886405 -0.13867,4.598683 -0.494572,4.667009 -0.231003,0.04435 -0.505579,-0.0049 -0.61017,-0.109533 l 0,0 z"
|
||||
id="path3770"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 30.440433,57.945316 c -3.064053,-0.42113 -6.77723,-2.474953 -8.457621,-4.67806 -2.1588,-2.830333 -3.113918,-6.737716 -2.769592,-11.330385 l 0.193121,-2.575872 2.07988,0.735628 c 3.527026,1.247466 6.337701,1.719068 10.215474,1.71405 4.171771,-0.0054 6.642981,-0.38868 10.25836,-1.591058 2.178973,-0.724668 2.692193,-0.815856 2.813444,-0.499883 0.08157,0.21256 0.08664,2.119864 0.01127,4.238453 -0.106217,2.98581 -0.266531,4.212938 -0.712935,5.457208 -1.450217,4.042206 -4.401118,6.844156 -8.437938,8.012017 -2.314747,0.669661 -3.34314,0.772215 -5.193465,0.517902 z"
|
||||
id="path3772"
|
||||
inkscape:connector-curvature="0" /></g>
|
||||
<path
|
||||
style="fill:#66CCFF;stroke:#66CCFF;stroke-width:0.27118643999999997"
|
||||
d="m 28.740556,40.063682 c -2.457795,-0.284995 -5.291522,-0.976881 -7.479539,-1.826212 -0.969492,-0.376332 -1.792939,-0.704961 -1.829884,-0.730287 -0.152564,-0.104584 0.766016,-6.242541 1.16801,-7.804656 1.421191,-5.522631 4.304477,-8.061849 9.154241,-8.061849 l 1.541531,0 0,1.627119 c 0,1.237125 -0.09381,1.627118 -0.391402,1.627118 -0.215271,0 -0.581373,0.271221 -0.813559,0.602714 -0.345889,0.493826 -0.422157,1.527524 -0.422157,5.721706 l 0,5.118992 0.813559,0.759978 c 0.675846,0.631335 0.813559,0.971083 0.813559,2.007108 0,0.835921 -0.111771,1.235378 -0.338983,1.211489 -0.18644,-0.0196 -1.18336,-0.133551 -2.215376,-0.25322 l 0,0 z"
|
||||
id="path3766"
|
||||
inkscape:connector-curvature="0" /></svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="64px"
|
||||
height="64px"
|
||||
viewBox="0 0 64 64"
|
||||
enable-background="new 0 0 64 64"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="MouseMiddle.svg"><metadata
|
||||
id="metadata21"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs19" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1282"
|
||||
inkscape:window-height="886"
|
||||
id="namedview17"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.6875"
|
||||
inkscape:cx="-10.305085"
|
||||
inkscape:cy="32"
|
||||
inkscape:window-x="31"
|
||||
inkscape:window-y="15"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g3" />
|
||||
<g
|
||||
id="g3">
|
||||
<g
|
||||
id="g5"
|
||||
style="stroke:#4d4d4d;fill:#4d4d4d">
|
||||
<path
|
||||
fill="#020202"
|
||||
d="M32.854,20.028c-0.015-1.274,0.576-2.269,1.151-3.236c0.758-1.278,1.543-2.6,0.997-4.417 c-0.555-1.667-1.607-2.485-2.539-3.212c-1.254-0.973-2.159-1.676-1.687-4.343l0.041-0.229l-1.35-0.238L29.427,4.58 c-0.615,3.484,0.878,4.643,2.195,5.666c0.85,0.663,1.653,1.288,2.072,2.542c0.366,1.224-0.18,2.143-0.869,3.306 c-0.641,1.081-1.366,2.3-1.349,3.933c-6.837,0.007-13.823,0.291-13.823,24.59c0,10.951,8.799,15.032,14.347,15.032 c5.545,0,14.347-4.081,14.347-15.032C46.347,20.347,39.228,20.048,32.854,20.028z M32.685,21.399 c5.643,0.012,10.927,0.236,12.063,16.153c-3.86,1.805-7.916,2.765-12.063,2.86v-2.966c0.845-0.162,1.481-0.909,1.481-1.782v-8.956 c0-0.876-0.637-1.621-1.481-1.784V21.399z M31.658,26.254h0.685c0.249,0,0.453,0.205,0.453,0.454v8.956 c0,0.249-0.204,0.449-0.453,0.449h-0.685c-0.249,0-0.452-0.2-0.452-0.449v-8.956C31.206,26.459,31.409,26.254,31.658,26.254z M31.313,21.399v3.525c-0.845,0.163-1.479,0.91-1.479,1.784v8.956c0,0.873,0.634,1.62,1.479,1.782v2.966 c-6.311-0.148-10.905-2.252-12.063-2.839C20.381,21.633,25.668,21.411,31.313,21.399z M32,58.274 c-5.016,0-12.976-3.707-12.976-13.658c0-1.983,0.045-3.853,0.134-5.563c2.003,0.929,6.696,2.74,12.868,2.74 c4.394,0,8.704-0.934,12.813-2.771c0.089,1.718,0.135,3.6,0.135,5.595C44.974,54.567,37.016,58.274,32,58.274z"
|
||||
id="path7"
|
||||
style="stroke:#4d4d4d;fill:#4d4d4d" />
|
||||
</g>
|
||||
|
||||
|
||||
<path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118643999999997"
|
||||
d="m 32.922034,38.950793 c 0,-1.135825 0.114919,-1.458045 0.677966,-1.900938 l 0.677966,-0.533288 0,-5.28078 c 0,-5.271249 -0.0012,-5.282003 -0.677966,-5.958745 -0.557439,-0.557439 -0.677966,-0.940935 -0.677966,-2.157165 l 0,-1.479199 1.535487,0 c 5.657554,0 8.584338,3.728529 9.71855,12.380791 0.498434,3.802265 0.50348,3.525731 -0.0676,3.704572 -0.261017,0.08174 -1.528694,0.512016 -2.817059,0.956167 -2.037206,0.702306 -4.048032,1.113044 -7.488026,1.529528 l -0.881356,0.106707 0,-1.36765 z"
|
||||
id="path3768"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 30.440433,57.945316 c -3.064053,-0.42113 -6.77723,-2.474953 -8.457621,-4.67806 -2.1588,-2.830333 -3.113918,-6.737716 -2.769592,-11.330385 l 0.193121,-2.575872 2.07988,0.735628 c 3.527026,1.247466 6.337701,1.719068 10.215474,1.71405 4.171771,-0.0054 6.642981,-0.38868 10.25836,-1.591058 2.178973,-0.724668 2.692193,-0.815856 2.813444,-0.499883 0.08157,0.21256 0.08664,2.119864 0.01127,4.238453 -0.106217,2.98581 -0.266531,4.212938 -0.712935,5.457208 -1.450217,4.042206 -4.401118,6.844156 -8.437938,8.012017 -2.314747,0.669661 -3.34314,0.772215 -5.193465,0.517902 z"
|
||||
id="path3772"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 28.740556,40.063682 c -2.457795,-0.284995 -5.291522,-0.976881 -7.479539,-1.826212 -0.969492,-0.376332 -1.792939,-0.704961 -1.829884,-0.730287 -0.152564,-0.104584 0.766016,-6.242541 1.16801,-7.804656 1.421191,-5.522631 4.304477,-8.061849 9.154241,-8.061849 l 1.541531,0 0,1.627119 c 0,1.237125 -0.09381,1.627118 -0.391402,1.627118 -0.215271,0 -0.581373,0.271221 -0.813559,0.602714 -0.345889,0.493826 -0.422157,1.527524 -0.422157,5.721706 l 0,5.118992 0.813559,0.759978 c 0.675846,0.631335 0.813559,0.971083 0.813559,2.007108 0,0.835921 -0.111771,1.235378 -0.338983,1.211489 -0.18644,-0.0196 -1.18336,-0.133551 -2.215376,-0.25322 l 0,0 z"
|
||||
id="path3778"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffd800;stroke:#ffd800;stroke-width:0.33870965"
|
||||
d="m 31.356243,35.809264 c -0.164314,-0.103856 -0.298753,-2.215682 -0.298753,-4.692945 0,-3.956026 0.08644,-4.52508 0.710296,-4.676395 0.390663,-0.09475 0.87474,-0.06834 1.075729,0.0587 0.200991,0.127038 0.312719,2.28036 0.248288,4.785159 -0.09927,3.859122 -0.217853,4.566401 -0.776977,4.634247 -0.362909,0.04404 -0.79427,-0.0049 -0.958583,-0.108765 l 0,0 z"
|
||||
id="path3770"
|
||||
inkscape:connector-curvature="0" /></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="64px"
|
||||
height="64px"
|
||||
viewBox="0 0 64 64"
|
||||
enable-background="new 0 0 64 64"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="MouseRight.svg"><metadata
|
||||
id="metadata21"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs19" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1282"
|
||||
inkscape:window-height="886"
|
||||
id="namedview17"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.6875"
|
||||
inkscape:cx="32"
|
||||
inkscape:cy="32"
|
||||
inkscape:window-x="31"
|
||||
inkscape:window-y="15"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g3" />
|
||||
<g
|
||||
id="g3">
|
||||
<g
|
||||
id="g5"
|
||||
style="stroke:#4d4d4d;fill:#4d4d4d">
|
||||
<path
|
||||
fill="#020202"
|
||||
d="M32.854,20.028c-0.015-1.274,0.576-2.269,1.151-3.236c0.758-1.278,1.543-2.6,0.997-4.417 c-0.555-1.667-1.607-2.485-2.539-3.212c-1.254-0.973-2.159-1.676-1.687-4.343l0.041-0.229l-1.35-0.238L29.427,4.58 c-0.615,3.484,0.878,4.643,2.195,5.666c0.85,0.663,1.653,1.288,2.072,2.542c0.366,1.224-0.18,2.143-0.869,3.306 c-0.641,1.081-1.366,2.3-1.349,3.933c-6.837,0.007-13.823,0.291-13.823,24.59c0,10.951,8.799,15.032,14.347,15.032 c5.545,0,14.347-4.081,14.347-15.032C46.347,20.347,39.228,20.048,32.854,20.028z M32.685,21.399 c5.643,0.012,10.927,0.236,12.063,16.153c-3.86,1.805-7.916,2.765-12.063,2.86v-2.966c0.845-0.162,1.481-0.909,1.481-1.782v-8.956 c0-0.876-0.637-1.621-1.481-1.784V21.399z M31.658,26.254h0.685c0.249,0,0.453,0.205,0.453,0.454v8.956 c0,0.249-0.204,0.449-0.453,0.449h-0.685c-0.249,0-0.452-0.2-0.452-0.449v-8.956C31.206,26.459,31.409,26.254,31.658,26.254z M31.313,21.399v3.525c-0.845,0.163-1.479,0.91-1.479,1.784v8.956c0,0.873,0.634,1.62,1.479,1.782v2.966 c-6.311-0.148-10.905-2.252-12.063-2.839C20.381,21.633,25.668,21.411,31.313,21.399z M32,58.274 c-5.016,0-12.976-3.707-12.976-13.658c0-1.983,0.045-3.853,0.134-5.563c2.003,0.929,6.696,2.74,12.868,2.74 c4.394,0,8.704-0.934,12.813-2.771c0.089,1.718,0.135,3.6,0.135,5.595C44.974,54.567,37.016,58.274,32,58.274z"
|
||||
id="path7"
|
||||
style="stroke:#4d4d4d;fill:#4d4d4d" />
|
||||
</g>
|
||||
|
||||
|
||||
<path
|
||||
style="fill:#65FD00;stroke:#65FD00;stroke-width:0.27118643999999997"
|
||||
d="m 32.922034,38.950793 c 0,-1.135825 0.114919,-1.458045 0.677966,-1.900938 l 0.677966,-0.533288 0,-5.28078 c 0,-5.271249 -0.0012,-5.282003 -0.677966,-5.958745 -0.557439,-0.557439 -0.677966,-0.940935 -0.677966,-2.157165 l 0,-1.479199 1.535487,0 c 5.657554,0 8.584338,3.728529 9.71855,12.380791 0.498434,3.802265 0.50348,3.525731 -0.0676,3.704572 -0.261017,0.08174 -1.528694,0.512016 -2.817059,0.956167 -2.037206,0.702306 -4.048032,1.113044 -7.488026,1.529528 l -0.881356,0.106707 0,-1.36765 z"
|
||||
id="path3768"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 31.485081,35.842143 c -0.104591,-0.104591 -0.190166,-2.231347 -0.190166,-4.726123 0,-3.983994 0.05502,-4.557071 0.452127,-4.709456 0.24867,-0.09542 0.556802,-0.06882 0.684738,0.05912 0.127937,0.127936 0.199056,2.296481 0.158043,4.818988 -0.06319,3.886405 -0.13867,4.598683 -0.494572,4.667009 -0.231003,0.04435 -0.505579,-0.0049 -0.61017,-0.109533 l 0,0 z"
|
||||
id="path3770"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 30.440433,57.945316 c -3.064053,-0.42113 -6.77723,-2.474953 -8.457621,-4.67806 -2.1588,-2.830333 -3.113918,-6.737716 -2.769592,-11.330385 l 0.193121,-2.575872 2.07988,0.735628 c 3.527026,1.247466 6.337701,1.719068 10.215474,1.71405 4.171771,-0.0054 6.642981,-0.38868 10.25836,-1.591058 2.178973,-0.724668 2.692193,-0.815856 2.813444,-0.499883 0.08157,0.21256 0.08664,2.119864 0.01127,4.238453 -0.106217,2.98581 -0.266531,4.212938 -0.712935,5.457208 -1.450217,4.042206 -4.401118,6.844156 -8.437938,8.012017 -2.314747,0.669661 -3.34314,0.772215 -5.193465,0.517902 z"
|
||||
id="path3772"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ffffff;stroke:#ffffff;stroke-width:0.27118644"
|
||||
d="m 28.740556,40.063682 c -2.457795,-0.284995 -5.291522,-0.976881 -7.479539,-1.826212 -0.969492,-0.376332 -1.792939,-0.704961 -1.829884,-0.730287 -0.152564,-0.104584 0.766016,-6.242541 1.16801,-7.804656 1.421191,-5.522631 4.304477,-8.061849 9.154241,-8.061849 l 1.541531,0 0,1.627119 c 0,1.237125 -0.09381,1.627118 -0.391402,1.627118 -0.215271,0 -0.581373,0.271221 -0.813559,0.602714 -0.345889,0.493826 -0.422157,1.527524 -0.422157,5.721706 l 0,5.118992 0.813559,0.759978 c 0.675846,0.631335 0.813559,0.971083 0.813559,2.007108 0,0.835921 -0.111771,1.235378 -0.338983,1.211489 -0.18644,-0.0196 -1.18336,-0.133551 -2.215376,-0.25322 l 0,0 z"
|
||||
id="path3778"
|
||||
inkscape:connector-curvature="0" /></g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="76.664284"
|
||||
height="128.25087"
|
||||
viewBox="0 0 76.664283 128.25086"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="Touch.svg"><metadata
|
||||
id="metadata3468"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3466" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="920"
|
||||
inkscape:window-height="780"
|
||||
id="namedview3464"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.7688899"
|
||||
inkscape:cx="-0.07794217"
|
||||
inkscape:cy="94.239301"
|
||||
inkscape:window-x="1529"
|
||||
inkscape:window-y="186"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g3428"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<g
|
||||
id="g3428"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
|
||||
<path
|
||||
d="M 76.151,80.896 C 77.465,66.89 62.145,65.577 62.145,65.577 57.771,52.885 46.39,59.45 46.39,59.45 40.701,46.758 29.322,55.511 29.322,55.511 27.912,55.092 25.613,11.796 24.414,11.604 23.44,7.068 14.011,-1.728 12.511,14.772 c 0,36.5 -1.135,47.304 -1.135,47.304 C 9.188,67.328 5.31,80.458 5.31,80.458 -3.006,89.649 0.933,96.214 0.933,96.214 c 7.002,12.255 21.385,28.449 21.385,28.449 6.129,5.252 2.627,8.316 2.627,8.316 l 42.455,0.438 2.334,-7.878 c 9.628,-18.382 6.417,-44.643 6.417,-44.643 z"
|
||||
id="path3432"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccc"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g3434"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3436"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3438"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3440"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3442"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3444"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3446"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3448"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3450"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3452"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3454"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3456"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3458"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3460"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
<g
|
||||
id="g3462"
|
||||
transform="translate(-7.9878665e-4,-5.1661327)">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
@@ -0,0 +1,129 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="76.664284"
|
||||
height="133.41701"
|
||||
viewBox="0 0 76.664283 133.417"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="TouchDrag.svg"><metadata
|
||||
id="metadata3468"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3466" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="920"
|
||||
inkscape:window-height="780"
|
||||
id="namedview3464"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.7688899"
|
||||
inkscape:cx="-0.077942171"
|
||||
inkscape:cy="94.239298"
|
||||
inkscape:window-x="161"
|
||||
inkscape:window-y="225"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="g3428"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<g
|
||||
id="g3428"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="M 18.653,0 C 12.359,0 7.258,5.102 7.258,11.395 c 0,6.293 5.102,11.395 11.396,11.395 6.293,0 11.395,-5.102 11.395,-11.395 C 30.048,5.102 24.946,0 18.653,0 z m 0,20.43 c -4.989,0 -9.036,-4.046 -9.036,-9.036 0,-4.989 4.047,-9.035 9.036,-9.035 4.989,0 9.035,4.046 9.035,9.035 0,4.99 -4.045,9.036 -9.035,9.036 z"
|
||||
id="path3430"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 76.151,80.896 C 77.465,66.89 62.145,65.577 62.145,65.577 57.771,52.885 46.39,59.45 46.39,59.45 40.701,46.758 29.322,55.511 29.322,55.511 27.912,55.092 25.613,11.796 24.414,11.604 23.44,7.068 14.011,-1.728 12.511,14.772 c 0,36.5 -1.135,47.304 -1.135,47.304 C 9.188,67.328 5.31,80.458 5.31,80.458 -3.006,89.649 0.933,96.214 0.933,96.214 c 7.002,12.255 21.385,28.449 21.385,28.449 6.129,5.252 2.627,8.316 2.627,8.316 l 42.455,0.438 2.334,-7.878 c 9.628,-18.382 6.417,-44.643 6.417,-44.643 z"
|
||||
id="path3432"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccc"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
d="m 65.247258,98.823749 c -0.681067,0.71969 -7.149935,7.376421 -7.149935,7.376421 0,0 -0.86404,0.92222 -0.86404,-0.29705 0.0013,-1.22468 0.0013,-3.17039 0.0013,-3.17039 0,0 -0.498094,0.003 -1.261753,0.002 -2.35324,0.002 -6.936466,0.002 -8.692502,0.002 0,0 -0.07751,-0.007 -0.162642,-0.0472 0,0.0378 0,0.0972 0,0.13232 0.01652,0.0891 0.0013,0.16068 0,0.16608 0,0.0149 0,0.0419 0,0.0554 0,0 0.01779,0.077 0,0.17013 0,2.02673 0,6.49066 0,8.99672 0.0013,0.90332 0,1.49203 0,1.49203 0,0 2.283354,0.002 3.229986,0 0.942821,0 0.07751,0.87225 0.07751,0.87225 l -7.121981,7.36157 c 0,0 -0.470139,0.5833 -0.963151,0.0607 -0.677255,-0.72374 -6.941548,-7.59515 -6.941548,-7.59515 0,0 -0.867853,-0.91952 0.280812,-0.91952 1.151207,0.002 2.983481,0.002 2.983481,0.002 0,0 -0.0026,-0.52929 -0.0013,-1.34079 -0.0013,-2.50067 -0.0013,-7.37102 -0.0013,-9.23572 l 0,-0.004 c 0,-0.0567 0,-0.14582 0,-0.21333 -0.08259,0.0392 -0.15883,0.0459 -0.15883,0.0459 -1.756036,0 -6.339262,0 -8.696314,-0.002 -0.759847,0.002 -1.260482,0 -1.260482,0 0,0 0.0026,1.94706 0.0026,3.17039 -0.0013,1.21793 -0.864041,0.29975 -0.864041,0.29975 0,0 -6.467597,-6.655381 -7.147393,-7.377761 -0.493012,-0.52525 0.05464,-1.02484 0.05464,-1.02484 l 6.927571,-7.566801 c 0,0 0.82338,-0.92357 0.82211,0.08236 0.0026,1.004586 0.0026,3.432334 0.0026,3.432334 0,0 0.552732,-0.0014 1.402796,-0.0041 2.439643,0.0041 6.872933,0.0027 8.678524,0.0014 0,0 0.116899,-0.03106 0.23634,0.027 0,-4.084505 0,-8.204115 0.0013,-9.436893 -0.0013,-0.807449 0,-1.339448 0,-1.339448 0,0 -1.832274,0.0027 -2.983481,0.0027 -1.146124,-0.0014 -0.280813,-0.918169 -0.280813,-0.918169 0,0 6.261752,-6.872771 6.942819,-7.596505 0.494283,-0.522547 0.964422,0.05806 0.964422,0.05806 l 7.12071,7.361561 c 0,0 0.869123,0.874963 -0.07624,0.872261 -0.945362,0.0027 -3.229987,0.0027 -3.229987,0.0027 0,0 0.0013,0.587358 0.0038,1.492025 -0.0013,1.284087 -0.0026,5.419901 -0.0026,9.503056 0.120712,-0.06211 0.240153,-0.02835 0.240153,-0.02835 1.804319,0 6.237609,0 8.675982,0 0.851334,-0.0014 1.404066,0 1.404066,0 0,0 0.0013,-2.426399 0,-3.430985 0,-1.003235 0.820838,-0.08236 0.820838,-0.08236 l 6.927572,7.566803 c 0,0.001 0.546378,0.50094 0.05845,1.02484 z"
|
||||
id="path3238"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccccccsscccccccccccccccccccccccccccccccc"
|
||||
style="fill:#66ccff;fill-opacity:1" /></g>
|
||||
<g
|
||||
id="g3434"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3436"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3438"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3440"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3442"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3444"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3446"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3448"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3450"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3452"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3454"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3456"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3458"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3460"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
<g
|
||||
id="g3462"
|
||||
transform="translate(-7.9878665e-4,-2.9265169e-6)">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="99.001816"
|
||||
height="101.57817"
|
||||
viewBox="0 0 99.001814 101.57817"
|
||||
enable-background="new 0 0 100.775 118.638"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="TouchRotate.svg"><metadata
|
||||
id="metadata3382"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3380" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1105"
|
||||
inkscape:window-height="739"
|
||||
id="namedview3378"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.9873603"
|
||||
inkscape:cx="11.856691"
|
||||
inkscape:cy="15.112094"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="152"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Capa_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 48.832974,0 c -5.85006,0 -10.591269,4.862311 -10.591269,10.85967 0,5.997358 4.742138,10.859669 10.592198,10.859669 5.849132,0 10.59127,-4.862311 10.59127,-10.859669 C 59.42425,4.862311 54.682106,0 48.832974,0 z m 0,19.47021 c -4.637107,0 -8.398657,-3.855921 -8.398657,-8.611493 0,-4.754621 3.76155,-8.610543 8.398657,-8.610543 4.637107,0 8.397729,3.855922 8.397729,8.610543 0,4.755572 -3.759691,8.611493 -8.397729,8.611493 z"
|
||||
id="path3430" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 27.154761,39.321738 c -5.457398,0 -9.88037,4.703155 -9.88037,10.504205 0,5.801049 4.423839,10.504204 9.881237,10.504204 5.456532,0 9.880371,-4.703155 9.880371,-10.504204 -8.67e-4,-5.80105 -4.424707,-10.504205 -9.881238,-10.504205 z m 0,18.8329 c -4.325859,0 -7.834929,-3.729707 -7.834929,-8.329617 0,-4.598989 3.50907,-8.328696 7.834929,-8.328696 4.32586,0 7.834063,3.729707 7.834063,8.328696 0,4.59991 -3.507336,8.329617 -7.834063,8.329617 z"
|
||||
id="path3430-5" /><path
|
||||
d="M 93.394891,94.930552 91.5074,101.57817 52.728925,101.21032 c 8.08e-4,-8.5e-4 2.829619,-2.585988 -2.124439,-7.016318 0,0 -10.822746,-5.22596 -18.506953,-18.0968 0,0 -6.310236,-6.742109 -6.091889,-9.206596 -0.583067,-4.408398 -1.209805,-6.954724 -1.715239,-8.534999 -1.063849,-4.039774 -1.553525,-2.844172 -1.553525,-7.228104 2.452812,-14.333817 10.869455,1.810623 12.764445,5.488368 0,0 6.305384,7.578229 9.063029,9.283373 8.851152,-2.291524 3.039071,-22.109494 3.660956,-23.668675 0,0 -1.25024,-10.043558 -2.822341,-23.064577 -3.9949,-15.561935 8.286796,-19.626706 11.636292,-3.093053 1.545414,7.344522 3.686834,19.52689 4.483397,19.774098 0,0 8.395048,-7.385018 12.995707,3.323385 0,0 9.202125,-5.538975 12.741777,5.170273 0,0 12.387573,1.10695 11.326563,12.923992 0,0 2.595085,22.156743 -5.191814,37.665865 z"
|
||||
id="path3376"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccc"
|
||||
style="fill:#ffffff" /><path
|
||||
d="m 36.857901,10.534807 -5.731265,12.511815 c 0,0 -0.666487,1.516584 -1.19043,0.316343 -0.52908,-1.19559 -1.800413,-4.092683 -1.800413,-4.092683 0,0 -0.774356,0.279126 -1.962218,0.711771 -3.412049,1.225827 -9.61846,3.462323 -12.145716,4.370646 0,0 -0.609983,0.412873 -1.019633,-0.532666 -0.419926,-0.944375 -3.7806092,-8.602891 -4.0798222,-9.279772 -0.294076,-0.674552 0.288938,-0.867615 0.288938,-0.867615 2.4553422,-0.886224 8.8659382,-3.19599 12.1688342,-4.381112 1.05816,-0.382636 1.763171,-0.631523 1.763171,-0.631523 0,0 -1.02734,-2.324887 -1.664289,-3.782156 -0.636951,-1.454944 1.049169,-0.79202 1.049169,-0.79202 0,0 12.534822,4.676522 13.866509,5.195231 0.963131,0.382636 0.457165,1.253741 0.457165,1.253741 z"
|
||||
id="path9"
|
||||
style="fill:#d800d8;fill-opacity:1"
|
||||
inkscape:connector-curvature="0" /><g
|
||||
id="g2997"
|
||||
transform="matrix(0,-1,1,0,-0.01316643,45.882166)"
|
||||
inkscape:transform-center-x="-4.9812271"
|
||||
inkscape:transform-center-y="-4.2696251"><path
|
||||
id="path2999"
|
||||
d="M 6.6614176,0.14173229 19.48819,5.5984253 c 0,0 1.559055,0.6377953 0.354331,1.1338583 -1.240158,0.5314961 -4.181103,1.7716536 -4.181103,1.7716536 0,0 0.283465,0.7440945 0.744095,1.9133858 1.27559,3.259843 3.57874,9.248032 4.535433,11.692914 0,0 0.425197,0.566929 -0.566929,0.992126 -0.956693,0.389764 -8.751969,3.685039 -9.460631,4.003937 -0.673228,0.283464 -0.885827,-0.283465 -0.885827,-0.283465 C 9.1062996,24.448819 6.6968507,18.283465 5.4921262,15.094489 5.0669294,14.066929 4.8188979,13.393701 4.8188979,13.393701 c 0,0 -2.3740159,0.992126 -3.86220494,1.629921 -1.48818905,0.637796 -0.81496067,-0.992126 -0.81496067,-0.992126 0,0 4.71259861,-12.1535432 5.24409471,-13.42913378 0.3897638,-0.95669294 1.2755906,-0.46062993 1.2755906,-0.46062993 z"
|
||||
style="fill:#d800d8;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /></g></svg>
|
||||
|
After Width: | Height: | Size: 5.5 KiB |
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="76.663582"
|
||||
height="140.44"
|
||||
viewBox="0 0 76.663581 140.44"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="TouchTilt.svg"><metadata
|
||||
id="metadata3364"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3362" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="766"
|
||||
inkscape:window-height="480"
|
||||
id="namedview3360"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.6804329"
|
||||
inkscape:cx="6.1930652"
|
||||
inkscape:cy="74.717535"
|
||||
inkscape:window-x="343"
|
||||
inkscape:window-y="203"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Capa_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<g
|
||||
id="g3322"
|
||||
style="fill:#ffffff"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 12.622,5.815 c -6.294,0 -11.396,5.102 -11.396,11.395 0,6.293 5.102,11.395 11.396,11.395 6.293,0 11.395,-5.102 11.395,-11.395 0,-6.293 -5.102,-11.395 -11.395,-11.395 z m 0,20.431 c -4.99,0 -9.036,-4.046 -9.036,-9.036 0,-4.989 4.046,-9.035 9.036,-9.035 4.988,0 9.035,4.046 9.035,9.035 0,4.99 -4.047,9.036 -9.035,9.036 z"
|
||||
id="path3324"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 43.793,0 c -6.294,0 -11.396,5.102 -11.396,11.395 0,6.293 5.102,11.395 11.396,11.395 6.293,0 11.395,-5.102 11.395,-11.395 C 55.188,5.102 50.086,0 43.793,0 z m 0,20.43 c -4.99,0 -9.036,-4.046 -9.036,-9.036 0,-4.989 4.046,-9.035 9.036,-9.035 4.988,0 9.035,4.046 9.035,9.035 0,4.99 -4.047,9.036 -9.035,9.036 z"
|
||||
id="path3326"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="M 76.151,87.918 C 77.464,73.913 62.146,72.6 62.146,72.6 57.769,59.907 47.556,66.472 47.556,66.472 c 0,0 2.262,-49.025 1.395,-54.713 -0.51,-3.331 -6.383,-10.562 -9.998,-1.684 -2.137,6.166 -5.59,60.75 -9.465,56.874 C 24.984,62.447 20.611,18.817 19.414,18.626 18.438,14.09 9.011,5.294 7.511,21.794 c 3,39.5 3.865,47.304 3.865,47.304 C 9.187,74.35 5.31,87.481 5.31,87.481 c -8.316,9.191 -4.377,15.756 -4.377,15.756 7.002,12.255 21.385,28.449 21.385,28.449 6.127,5.252 2.625,8.316 2.625,8.316 l 42.455,0.438 2.334,-7.879 c 9.628,-18.382 6.419,-44.643 6.419,-44.643 z"
|
||||
id="path3328"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccc"
|
||||
style="fill:#ffffff" />
|
||||
</g>
|
||||
<g
|
||||
id="g3330"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3332"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3334"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3336"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3338"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3340"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3342"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3344"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3346"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3348"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3350"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3352"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3354"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3356"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<g
|
||||
id="g3358"
|
||||
transform="translate(-7.9878665e-4,-3.8214145e-7)">
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 52.342987,124.78465 -8.980622,9.44613 c 0,0 -0.592129,0.74692 -1.214412,0.0786 -0.853927,-0.92772 -8.753091,-9.74549 -8.753091,-9.74549 0,0 -1.096535,-1.17966 0.352262,-1.17818 1.454279,10e-4 3.762485,10e-4 3.762485,10e-4 0,0 -0.0027,-0.67875 -0.0014,-1.72058 -0.0014,-3.20848 -0.0014,-9.4565 -0.0027,-11.8499 0,0 -0.01233,-0.56315 0.655179,-0.56019 0.672999,0 8.298029,0 9.238308,-0.003 0.937537,0.003 0.774428,0.66985 0.774428,0.66985 0,2.45861 0,8.50359 -0.0027,11.82767 0.0041,1.16039 0.0027,1.91472 0.0027,1.91472 0,0 2.879775,0.003 4.070886,0 1.192483,-10e-4 0.09869,1.11889 0.09869,1.11889 z m -0.09869,-37.828986 c -1.191111,0.003 -4.073627,0.003 -4.073627,0.003 0,0 0.0027,0.752845 0.0041,1.914716 -0.0041,3.327041 -0.0041,9.370556 -0.0014,11.83064 0,0 0.16174,0.66393 -0.774427,0.66096 -0.943021,0.006 -8.563939,0.003 -9.235567,0.004 -0.670257,-0.003 -0.65655,-0.56167 -0.65655,-0.56167 -0.0014,-2.393393 -0.0014,-8.642902 0.0014,-11.855831 -0.0014,-1.034421 0,-1.717613 0,-1.717613 0,0 -2.312318,0.003 -3.762486,0.0044 -1.444685,-0.003 -0.355003,-1.178173 -0.355003,-1.178173 0,0 7.896422,-8.81777 8.755832,-9.745488 0.622284,-0.671338 1.215783,0.07558 1.215783,0.07558 l 8.979252,9.444648 c 0,0 1.096534,1.121857 -0.09732,1.120375 z"
|
||||
id="path3432"
|
||||
sodipodi:nodetypes="ccccsccccccccccccccccccccccccc"
|
||||
style="fill:#ffd800;fill-opacity:1" /></svg>
|
||||
|
After Width: | Height: | Size: 5.7 KiB |
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 17.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Capa_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="95.087433"
|
||||
height="118.43173"
|
||||
viewBox="0 0 95.087431 118.43173"
|
||||
enable-background="new 0 0 100.775 118.638"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="TouchZoom.svg"><metadata
|
||||
id="metadata3382"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs3380" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1105"
|
||||
inkscape:window-height="739"
|
||||
id="namedview3378"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.8132167"
|
||||
inkscape:cx="10.565593"
|
||||
inkscape:cy="72.192791"
|
||||
inkscape:window-x="67"
|
||||
inkscape:window-y="152"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="Capa_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
|
||||
<path
|
||||
d="m 0.0436199,84.941029 c 0,0 -0.2799964,-1.323641 0.578786,-0.720397 0.8621957,0.601498 2.9536375,2.059778 2.9536375,2.059778 0,0 0.3431801,-0.517567 0.8707286,-1.316651 1.521209,-2.28009 4.281925,-6.427623 5.405325,-8.116707 0,0 0.187721,-0.53855 0.863902,-0.06295 0.682926,0.472104 6.206065,4.329377 6.692655,4.668591 0.483157,0.340966 0.220227,0.718649 0.220227,0.718649 -1.094368,1.641877 -3.948985,5.929292 -5.418977,8.132449 -0.469526,0.711655 -0.783654,1.178514 -0.783654,1.178514 0,0 1.678274,1.168023 2.728271,1.900661 1.043172,0.732637 -0.28341,0.987925 -0.28341,0.987925 0,0 -9.7470195,2.05628 -10.7936043,2.25911 -0.756328,0.145111 -0.8468168,-0.666198 -0.8468168,-0.666198 z"
|
||||
id="path3376-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccc"
|
||||
style="fill:#65ff00;fill-opacity:1" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 44.918594,16.853557 c -5.85006,0 -10.591269,4.862311 -10.591269,10.85967 0,5.997358 4.742138,10.859669 10.592198,10.859669 5.849132,0 10.59127,-4.862311 10.59127,-10.859669 -9.23e-4,-5.997359 -4.743067,-10.85967 -10.592199,-10.85967 z m 0,19.47021 c -4.637107,0 -8.398657,-3.855921 -8.398657,-8.611493 0,-4.754621 3.76155,-8.610543 8.398657,-8.610543 4.637107,0 8.397729,3.855922 8.397729,8.610543 0,4.755572 -3.759691,8.611493 -8.397729,8.611493 z"
|
||||
id="path3430" /><path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd"
|
||||
d="m 23.240381,56.175295 c -5.457398,0 -9.88037,4.703155 -9.88037,10.504205 0,5.801049 4.423839,10.504204 9.881237,10.504204 5.456532,0 9.880371,-4.703155 9.880371,-10.504204 -8.67e-4,-5.80105 -4.424707,-10.504205 -9.881238,-10.504205 z m 0,18.8329 c -4.325859,0 -7.834929,-3.729707 -7.834929,-8.329617 0,-4.598989 3.50907,-8.328696 7.834929,-8.328696 4.32586,0 7.834063,3.729707 7.834063,8.328696 0,4.59991 -3.507336,8.329617 -7.834063,8.329617 z"
|
||||
id="path3430-5" /><path
|
||||
d="m 89.480511,111.78411 -1.887491,6.64762 -38.778475,-0.36785 c 8.08e-4,-8.5e-4 2.829619,-2.58599 -2.124439,-7.01632 0,0 -10.822746,-5.22596 -18.506953,-18.096801 0,0 -6.310236,-6.742109 -6.091889,-9.206596 C 21.508197,79.335765 20.881459,76.789439 20.376025,75.209164 19.312176,71.16939 18.8225,72.364992 18.8225,67.98106 c 2.452812,-14.333817 10.869455,1.810623 12.764445,5.488368 0,0 6.305384,7.578229 9.063029,9.283373 8.851152,-2.291524 3.039071,-22.109494 3.660956,-23.668675 0,0 -1.25024,-10.043558 -2.822341,-23.064577 -3.9949,-15.561935 8.286796,-19.626706 11.636292,-3.093053 1.545414,7.344522 3.686834,19.52689 4.483397,19.774098 0,0 8.395048,-7.385018 12.995707,3.323385 0,0 9.202125,-5.538975 12.741777,5.170273 0,0 12.387573,1.10695 11.326563,12.923992 0,0 2.59509,22.156743 -5.191814,37.665866 z"
|
||||
id="path3376"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccccccccccc"
|
||||
style="fill:#ffffff" /><path
|
||||
d="m 49.854025,14.903508 c 0.696314,0.466948 6.359531,4.268019 6.858144,4.604015 0.491619,0.334273 0.748797,-0.05343 0.748797,-0.05343 1.121449,-1.617954 4.044902,-5.844621 5.545997,-8.013953 0.488115,-0.703007 0.803031,-1.164787 0.803031,-1.164787 0,0 1.714536,1.152726 2.792243,1.876411 1.07596,0.721961 0.813533,-0.620302 0.813533,-0.620302 0,0 -1.732034,-9.8989818 -1.933227,-10.95349441 -0.150463,-0.7615853 -0.939496,-0.5513731 -0.939496,-0.5513731 L 53.458049,1.9374693 c 0,0 -1.336636,0.2136595 -0.454876,0.8046693 0.88876,0.5927325 3.02493,2.0297666 3.02493,2.0297666 0,0 -0.355152,0.5083037 -0.895757,1.2940169 -1.558825,2.2468717 -4.387811,6.3339699 -5.538999,7.9984459 -0.0018,0.0017 -0.433883,0.370456 0.260678,0.83914 z"
|
||||
id="path3376-7-4"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccccccccc"
|
||||
style="fill:#65ff00;fill-opacity:1" /></svg>
|
||||
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 781 B |
|
After Width: | Height: | Size: 723 B |
@@ -0,0 +1,103 @@
|
||||
.cesium-infoBox {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
width: 40%;
|
||||
max-width: 480px;
|
||||
background: rgba(38, 38, 38, 0.95);
|
||||
color: #edffff;
|
||||
border: 1px solid #444;
|
||||
border-right: none;
|
||||
border-top-left-radius: 7px;
|
||||
border-bottom-left-radius: 7px;
|
||||
box-shadow: 0 0 10px 1px #000;
|
||||
transform: translate(100%, 0);
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
visibility 0s 0.2s,
|
||||
opacity 0.2s ease-in,
|
||||
transform 0.2s ease-in;
|
||||
}
|
||||
|
||||
.cesium-infoBox-visible {
|
||||
transform: translate(0, 0);
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition:
|
||||
opacity 0.2s ease-out,
|
||||
transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.cesium-infoBox-title {
|
||||
display: block;
|
||||
height: 20px;
|
||||
padding: 5px 30px 5px 25px;
|
||||
background: rgba(84, 84, 84, 1);
|
||||
border-top-left-radius: 7px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.cesium-infoBox-bodyless .cesium-infoBox-title {
|
||||
border-bottom-left-radius: 7px;
|
||||
}
|
||||
|
||||
button.cesium-infoBox-camera {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
background: transparent;
|
||||
border-color: transparent;
|
||||
border-radius: 3px;
|
||||
padding: 0 5px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
button.cesium-infoBox-close {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
height: 20px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
padding: 0 5px;
|
||||
margin: 0;
|
||||
color: #edffff;
|
||||
}
|
||||
|
||||
button.cesium-infoBox-close:focus {
|
||||
background: rgba(238, 136, 0, 0.44);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
button.cesium-infoBox-close:hover {
|
||||
background: #888;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
button.cesium-infoBox-close:active {
|
||||
background: #a00;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.cesium-infoBox-bodyless .cesium-infoBox-iframe {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-infoBox-iframe {
|
||||
border: none;
|
||||
width: 100%; /* Fallback */
|
||||
width: calc(100% - 2px);
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import {
|
||||
buildModuleUrl,
|
||||
Check,
|
||||
Color,
|
||||
defined,
|
||||
destroyObject,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import subscribeAndEvaluate from "../subscribeAndEvaluate.js";
|
||||
import InfoBoxViewModel from "./InfoBoxViewModel.js";
|
||||
|
||||
/**
|
||||
* A widget for displaying information or a description.
|
||||
*
|
||||
* @alias InfoBox
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*/
|
||||
function InfoBox(container) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.defined("container", container);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const infoElement = document.createElement("div");
|
||||
infoElement.className = "cesium-infoBox";
|
||||
infoElement.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-infoBox-visible" : showInfo, "cesium-infoBox-bodyless" : _bodyless }',
|
||||
);
|
||||
container.appendChild(infoElement);
|
||||
|
||||
const titleElement = document.createElement("div");
|
||||
titleElement.className = "cesium-infoBox-title";
|
||||
titleElement.setAttribute("data-bind", "text: titleText");
|
||||
infoElement.appendChild(titleElement);
|
||||
|
||||
const cameraElement = document.createElement("button");
|
||||
cameraElement.type = "button";
|
||||
cameraElement.className = "cesium-button cesium-infoBox-camera";
|
||||
cameraElement.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
attr: { title: "Focus camera on object" },\
|
||||
click: function () { cameraClicked.raiseEvent(this); },\
|
||||
enable: enableCamera,\
|
||||
cesiumSvgPath: { path: cameraIconPath, width: 32, height: 32 }',
|
||||
);
|
||||
infoElement.appendChild(cameraElement);
|
||||
|
||||
const closeElement = document.createElement("button");
|
||||
closeElement.type = "button";
|
||||
closeElement.className = "cesium-infoBox-close";
|
||||
closeElement.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
click: function () { closeClicked.raiseEvent(this); }",
|
||||
);
|
||||
closeElement.innerHTML = "×";
|
||||
infoElement.appendChild(closeElement);
|
||||
|
||||
const frame = document.createElement("iframe");
|
||||
frame.className = "cesium-infoBox-iframe";
|
||||
frame.setAttribute("sandbox", "allow-same-origin allow-popups allow-forms"); //allow-pointer-lock allow-scripts allow-top-navigation
|
||||
frame.setAttribute(
|
||||
"data-bind",
|
||||
"style : { maxHeight : maxHeightOffset(40) }",
|
||||
);
|
||||
frame.setAttribute("allowfullscreen", true);
|
||||
infoElement.appendChild(frame);
|
||||
|
||||
const viewModel = new InfoBoxViewModel();
|
||||
knockout.applyBindings(viewModel, infoElement);
|
||||
|
||||
this._container = container;
|
||||
this._element = infoElement;
|
||||
this._frame = frame;
|
||||
this._viewModel = viewModel;
|
||||
this._descriptionSubscription = undefined;
|
||||
|
||||
const that = this;
|
||||
//We can't actually add anything into the frame until the load event is fired
|
||||
frame.addEventListener("load", function () {
|
||||
const frameDocument = frame.contentDocument;
|
||||
|
||||
//We inject default css into the content iframe,
|
||||
//end users can remove it or add their own via the exposed frame property.
|
||||
const cssLink = frameDocument.createElement("link");
|
||||
cssLink.href = buildModuleUrl("Widgets/InfoBox/InfoBoxDescription.css");
|
||||
cssLink.rel = "stylesheet";
|
||||
cssLink.type = "text/css";
|
||||
|
||||
//div to use for description content.
|
||||
const frameContent = frameDocument.createElement("div");
|
||||
frameContent.className = "cesium-infoBox-description";
|
||||
|
||||
frameDocument.head.appendChild(cssLink);
|
||||
frameDocument.body.appendChild(frameContent);
|
||||
|
||||
//We manually subscribe to the description event rather than through a binding for two reasons.
|
||||
//1. It's an easy way to ensure order of operation so that we can adjust the height.
|
||||
//2. Knockout does not bind to elements inside of an iFrame, so we would have to apply a second binding
|
||||
// model anyway.
|
||||
that._descriptionSubscription = subscribeAndEvaluate(
|
||||
viewModel,
|
||||
"description",
|
||||
function (value) {
|
||||
// Set the frame to small height, force vertical scroll bar to appear, and text to wrap accordingly.
|
||||
frame.style.height = "5px";
|
||||
frameContent.innerHTML = value;
|
||||
|
||||
//If the snippet is a single element, then use its background
|
||||
//color for the body of the InfoBox. This makes the padding match
|
||||
//the content and produces much nicer results.
|
||||
let background = null;
|
||||
const firstElementChild = frameContent.firstElementChild;
|
||||
if (
|
||||
firstElementChild !== null &&
|
||||
frameContent.childNodes.length === 1
|
||||
) {
|
||||
const style = window.getComputedStyle(firstElementChild);
|
||||
if (style !== null) {
|
||||
const backgroundColor = style["background-color"];
|
||||
const color = Color.fromCssColorString(backgroundColor);
|
||||
if (defined(color) && color.alpha !== 0) {
|
||||
background = style["background-color"];
|
||||
}
|
||||
}
|
||||
}
|
||||
infoElement.style["background-color"] = background;
|
||||
|
||||
// Measure and set the new custom height, based on text wrapped above.
|
||||
const height = frameContent.getBoundingClientRect().height;
|
||||
frame.style.height = `${height}px`;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
//Chrome does not send the load event unless we explicitly set a src
|
||||
frame.setAttribute("src", "about:blank");
|
||||
}
|
||||
|
||||
Object.defineProperties(InfoBox.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof InfoBox.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof InfoBox.prototype
|
||||
*
|
||||
* @type {InfoBoxViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the iframe used to display the description.
|
||||
* @memberof InfoBox.prototype
|
||||
*
|
||||
* @type {HTMLIFrameElement}
|
||||
*/
|
||||
frame: {
|
||||
get: function () {
|
||||
return this._frame;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
InfoBox.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
InfoBox.prototype.destroy = function () {
|
||||
const container = this._container;
|
||||
knockout.cleanNode(this._element);
|
||||
container.removeChild(this._element);
|
||||
|
||||
if (defined(this._descriptionSubscription)) {
|
||||
this._descriptionSubscription.dispose();
|
||||
}
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default InfoBox;
|
||||
@@ -0,0 +1,90 @@
|
||||
@import url(../shared.css);
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description {
|
||||
font-family: sans-serif;
|
||||
font-size: 13px;
|
||||
padding: 4px 10px;
|
||||
margin-right: 4px;
|
||||
color: #edffff;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description a:link,
|
||||
.cesium-infoBox-description a:visited,
|
||||
.cesium-infoBox-description a:hover,
|
||||
.cesium-infoBox-description a:active {
|
||||
color: #edffff;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description table {
|
||||
color: #edffff;
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable {
|
||||
width: 100%;
|
||||
color: #edffff;
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable tr:nth-child(odd) {
|
||||
background-color: rgba(84, 84, 84, 0.8);
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable tr:nth-child(even) {
|
||||
background-color: rgba(84, 84, 84, 0.25);
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable th {
|
||||
font-weight: normal;
|
||||
padding: 3px;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable td {
|
||||
padding: 3px;
|
||||
vertical-align: middle;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description-lighter {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description-lighter a:link,
|
||||
.cesium-infoBox-description-lighter a:visited,
|
||||
.cesium-infoBox-description-lighter a:hover,
|
||||
.cesium-infoBox-description-lighter a:active {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cesium-infoBox-description-lighter table {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable-lighter {
|
||||
width: 100%;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable-lighter tr:nth-child(odd) {
|
||||
background-color: rgba(179, 179, 179, 0.8);
|
||||
}
|
||||
|
||||
.cesium-infoBox-defaultTable-lighter tr:nth-child(even) {
|
||||
background-color: rgba(179, 179, 179, 0.25);
|
||||
}
|
||||
|
||||
.cesium-infoBox-loadingContainer {
|
||||
margin: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cesium-infoBox-loading {
|
||||
display: inline-block;
|
||||
background-image: url(../Images/info-loading.gif);
|
||||
width: 16px;
|
||||
height: 11px;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import { defined, Event } from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
|
||||
const cameraEnabledPath =
|
||||
"M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4853444 22.104033 11.423165 24.0625 13.84375 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 8.975298 28.305952 7.03125 25.875 7.03125 L 13.84375 7.03125 z";
|
||||
const cameraDisabledPath =
|
||||
"M 27.34375 1.65625 L 5.28125 27.9375 L 8.09375 30.3125 L 30.15625 4.03125 L 27.34375 1.65625 z M 13.84375 7.03125 C 11.412798 7.03125 9.46875 8.975298 9.46875 11.40625 L 9.46875 11.59375 L 2.53125 7.21875 L 2.53125 24.0625 L 9.46875 19.6875 C 9.4724893 20.232036 9.5676108 20.7379 9.75 21.21875 L 21.65625 7.03125 L 13.84375 7.03125 z M 28.21875 7.71875 L 14.53125 24.0625 L 25.875 24.0625 C 28.305952 24.0625 30.28125 22.087202 30.28125 19.65625 L 30.28125 11.40625 C 30.28125 9.8371439 29.456025 8.4902779 28.21875 7.71875 z";
|
||||
|
||||
/**
|
||||
* The view model for {@link InfoBox}.
|
||||
* @alias InfoBoxViewModel
|
||||
* @constructor
|
||||
*/
|
||||
function InfoBoxViewModel() {
|
||||
this._cameraClicked = new Event();
|
||||
this._closeClicked = new Event();
|
||||
|
||||
/**
|
||||
* Gets or sets the maximum height of the info box in pixels. This property is observable.
|
||||
* @type {number}
|
||||
*/
|
||||
this.maxHeight = 500;
|
||||
|
||||
/**
|
||||
* Gets or sets whether the camera tracking icon is enabled.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.enableCamera = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the status of current camera tracking of the selected object.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isCameraTracking = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the visibility of the info box.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.showInfo = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the title text in the info box.
|
||||
* @type {string}
|
||||
*/
|
||||
this.titleText = "";
|
||||
|
||||
/**
|
||||
* Gets or sets the description HTML for the info box.
|
||||
* @type {string}
|
||||
*/
|
||||
this.description = "";
|
||||
|
||||
knockout.track(this, [
|
||||
"showInfo",
|
||||
"titleText",
|
||||
"description",
|
||||
"maxHeight",
|
||||
"enableCamera",
|
||||
"isCameraTracking",
|
||||
]);
|
||||
|
||||
this._loadingIndicatorHtml =
|
||||
'<div class="cesium-infoBox-loadingContainer"><span class="cesium-infoBox-loading"></span></div>';
|
||||
|
||||
/**
|
||||
* Gets the SVG path of the camera icon, which can change to be "crossed out" or not.
|
||||
* @type {string}
|
||||
*/
|
||||
this.cameraIconPath = undefined;
|
||||
knockout.defineProperty(this, "cameraIconPath", {
|
||||
get: function () {
|
||||
return !this.enableCamera || this.isCameraTracking
|
||||
? cameraDisabledPath
|
||||
: cameraEnabledPath;
|
||||
},
|
||||
});
|
||||
|
||||
knockout.defineProperty(this, "_bodyless", {
|
||||
get: function () {
|
||||
return !defined(this.description) || this.description.length === 0;
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the maximum height of sections within the info box, minus an offset, in CSS-ready form.
|
||||
* @param {number} offset The offset in pixels.
|
||||
* @returns {string}
|
||||
*/
|
||||
InfoBoxViewModel.prototype.maxHeightOffset = function (offset) {
|
||||
return `${this.maxHeight - offset}px`;
|
||||
};
|
||||
|
||||
Object.defineProperties(InfoBoxViewModel.prototype, {
|
||||
/**
|
||||
* Gets an {@link Event} that is fired when the user clicks the camera icon.
|
||||
* @memberof InfoBoxViewModel.prototype
|
||||
* @type {Event}
|
||||
*/
|
||||
cameraClicked: {
|
||||
get: function () {
|
||||
return this._cameraClicked;
|
||||
},
|
||||
},
|
||||
/**
|
||||
* Gets an {@link Event} that is fired when the user closes the info box.
|
||||
* @memberof InfoBoxViewModel.prototype
|
||||
* @type {Event}
|
||||
*/
|
||||
closeClicked: {
|
||||
get: function () {
|
||||
return this._closeClicked;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default InfoBoxViewModel;
|
||||
@@ -0,0 +1,213 @@
|
||||
import { Check, defined } from "@cesium/engine";
|
||||
|
||||
/**
|
||||
* A static class with helper functions used by CesiumInspector, Cesium3DTilesInspector, and VoxelInspector
|
||||
* @private
|
||||
*/
|
||||
const InspectorShared = {};
|
||||
|
||||
/**
|
||||
* Creates a checkbox component
|
||||
* @param {string} labelText The text to display in the checkbox label
|
||||
* @param {string} checkedBinding The name of the variable used for checked binding
|
||||
* @param {string} [enableBinding] The name of the variable used for enable binding
|
||||
* @return {Element}
|
||||
*/
|
||||
InspectorShared.createCheckbox = function (
|
||||
labelText,
|
||||
checkedBinding,
|
||||
enableBinding,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.string("labelText", labelText);
|
||||
Check.typeOf.string("checkedBinding", checkedBinding);
|
||||
//>>includeEnd('debug');
|
||||
const checkboxContainer = document.createElement("div");
|
||||
const checkboxLabel = document.createElement("label");
|
||||
const checkboxInput = document.createElement("input");
|
||||
checkboxInput.type = "checkbox";
|
||||
|
||||
let binding = `checked: ${checkedBinding}`;
|
||||
if (defined(enableBinding)) {
|
||||
binding += `, enable: ${enableBinding}`;
|
||||
}
|
||||
checkboxInput.setAttribute("data-bind", binding);
|
||||
checkboxLabel.appendChild(checkboxInput);
|
||||
checkboxLabel.appendChild(document.createTextNode(labelText));
|
||||
checkboxContainer.appendChild(checkboxLabel);
|
||||
return checkboxContainer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a section element
|
||||
* @param {Element} panel The parent element
|
||||
* @param {string} headerText The text to display at the top of the section
|
||||
* @param {string} sectionVisibleBinding The name of the variable used for visible binding
|
||||
* @param {string} toggleSectionVisibilityBinding The name of the function used to toggle visibility
|
||||
* @return {Element}
|
||||
*/
|
||||
InspectorShared.createSection = function (
|
||||
panel,
|
||||
headerText,
|
||||
sectionVisibleBinding,
|
||||
toggleSectionVisibilityBinding,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.defined("panel", panel);
|
||||
Check.typeOf.string("headerText", headerText);
|
||||
Check.typeOf.string("sectionVisibleBinding", sectionVisibleBinding);
|
||||
Check.typeOf.string(
|
||||
"toggleSectionVisibilityBinding",
|
||||
toggleSectionVisibilityBinding,
|
||||
);
|
||||
//>>includeEnd('debug');
|
||||
const section = document.createElement("div");
|
||||
section.className = "cesium-cesiumInspector-section";
|
||||
section.setAttribute(
|
||||
"data-bind",
|
||||
`css: { "cesium-cesiumInspector-section-collapsed": !${sectionVisibleBinding} }`,
|
||||
);
|
||||
panel.appendChild(section);
|
||||
|
||||
const sectionHeader = document.createElement("h3");
|
||||
sectionHeader.className = "cesium-cesiumInspector-sectionHeader";
|
||||
sectionHeader.appendChild(document.createTextNode(headerText));
|
||||
sectionHeader.setAttribute(
|
||||
"data-bind",
|
||||
`click: ${toggleSectionVisibilityBinding}`,
|
||||
);
|
||||
section.appendChild(sectionHeader);
|
||||
|
||||
const sectionContent = document.createElement("div");
|
||||
sectionContent.className = "cesium-cesiumInspector-sectionContent";
|
||||
section.appendChild(sectionContent);
|
||||
return sectionContent;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a range input
|
||||
* @param {string} rangeText The text to display
|
||||
* @param {string} sliderValueBinding The name of the variable used for slider value binding
|
||||
* @param {number} min The minimum value
|
||||
* @param {number} max The maximum value
|
||||
* @param {number} [step] The step size. Defaults to "any".
|
||||
* @param {string} [inputValueBinding] The name of the variable used for input value binding
|
||||
* @return {Element}
|
||||
*/
|
||||
InspectorShared.createRangeInput = function (
|
||||
rangeText,
|
||||
sliderValueBinding,
|
||||
min,
|
||||
max,
|
||||
step,
|
||||
inputValueBinding,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.string("rangeText", rangeText);
|
||||
Check.typeOf.string("sliderValueBinding", sliderValueBinding);
|
||||
Check.typeOf.number("min", min);
|
||||
Check.typeOf.number("max", max);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
inputValueBinding = inputValueBinding ?? sliderValueBinding;
|
||||
const input = document.createElement("input");
|
||||
input.setAttribute("data-bind", `value: ${inputValueBinding}`);
|
||||
input.type = "number";
|
||||
|
||||
const slider = document.createElement("input");
|
||||
slider.type = "range";
|
||||
slider.min = min;
|
||||
slider.max = max;
|
||||
slider.step = step ?? "any";
|
||||
slider.setAttribute(
|
||||
"data-bind",
|
||||
`valueUpdate: "input", value: ${sliderValueBinding}`,
|
||||
);
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.appendChild(slider);
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.className = "cesium-cesiumInspector-slider";
|
||||
container.appendChild(document.createTextNode(rangeText));
|
||||
container.appendChild(input);
|
||||
container.appendChild(wrapper);
|
||||
|
||||
return container;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a range input
|
||||
* @param {string} rangeText The text to display
|
||||
* @param {string} sliderValueBinding The name of the variable used for slider value binding
|
||||
* @param {number} [step] The step size. Defaults to "any".
|
||||
* @param {string} [inputValueBinding] The name of the variable used for input value binding
|
||||
* @return {Element}
|
||||
*/
|
||||
InspectorShared.createRangeInputWithDynamicMinMax = function (
|
||||
rangeText,
|
||||
sliderValueBinding,
|
||||
step,
|
||||
inputValueBinding,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.string("rangeText", rangeText);
|
||||
Check.typeOf.string("sliderValueBinding", sliderValueBinding);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
inputValueBinding = inputValueBinding ?? sliderValueBinding;
|
||||
const input = document.createElement("input");
|
||||
input.setAttribute("data-bind", `value: ${inputValueBinding}`);
|
||||
input.type = "number";
|
||||
|
||||
const slider = document.createElement("input");
|
||||
slider.type = "range";
|
||||
slider.step = step ?? "any";
|
||||
slider.setAttribute(
|
||||
"data-bind",
|
||||
`valueUpdate: "input", value: ${sliderValueBinding}, attr: { min: ${sliderValueBinding}Min, max: ${sliderValueBinding}Max }`,
|
||||
);
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.appendChild(slider);
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.className = "cesium-cesiumInspector-slider";
|
||||
container.appendChild(document.createTextNode(rangeText));
|
||||
container.appendChild(input);
|
||||
container.appendChild(wrapper);
|
||||
|
||||
return container;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a button component
|
||||
* @param {string} buttonText The button text
|
||||
* @param {string} clickedBinding The name of the variable used for clicked binding
|
||||
* @param {string} [activeBinding] The name of the variable used for active binding
|
||||
* @return {Element}
|
||||
*/
|
||||
InspectorShared.createButton = function (
|
||||
buttonText,
|
||||
clickedBinding,
|
||||
activeBinding,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
Check.typeOf.string("buttonText", buttonText);
|
||||
Check.typeOf.string("clickedBinding", clickedBinding);
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.textContent = buttonText;
|
||||
button.className = "cesium-cesiumInspector-pickButton";
|
||||
let binding = `click: ${clickedBinding}`;
|
||||
if (defined(activeBinding)) {
|
||||
binding += `, css: {"cesium-cesiumInspector-pickButtonHighlight" : ${activeBinding}}`;
|
||||
}
|
||||
button.setAttribute("data-bind", binding);
|
||||
|
||||
return button;
|
||||
};
|
||||
|
||||
export default InspectorShared;
|
||||
@@ -0,0 +1,114 @@
|
||||
.cesium-navigationHelpButton-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cesium-navigation-help {
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 38px;
|
||||
right: 2px;
|
||||
width: 250px;
|
||||
border-radius: 10px;
|
||||
transform: scale(0.01);
|
||||
transform-origin: 234px -10px;
|
||||
transition:
|
||||
visibility 0s 0.25s,
|
||||
transform 0.25s ease-in;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-visible {
|
||||
visibility: visible;
|
||||
transform: scale(1);
|
||||
transition: transform 0.25s ease-out;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-instructions {
|
||||
border: 1px solid #444;
|
||||
background-color: rgba(38, 38, 38, 0.75);
|
||||
padding-bottom: 5px;
|
||||
border-radius: 0 0 10px 10px;
|
||||
}
|
||||
|
||||
.cesium-click-navigation-help {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-touch-navigation-help {
|
||||
display: none;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.cesium-click-navigation-help-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cesium-touch-navigation-help-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-pan {
|
||||
color: #66ccff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-zoom {
|
||||
color: #65fd00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-rotate {
|
||||
color: #ffd800;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-tilt {
|
||||
color: #d800d8;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-navigation-help-details {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.cesium-navigation-button {
|
||||
color: #fff;
|
||||
background-color: transparent;
|
||||
border-bottom: none;
|
||||
border-top: 1px solid #444;
|
||||
border-right: 1px solid #444;
|
||||
margin: 0;
|
||||
width: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cesium-navigation-button-icon {
|
||||
vertical-align: middle;
|
||||
padding: 5px 1px;
|
||||
}
|
||||
|
||||
.cesium-navigation-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.cesium-navigation-button-left {
|
||||
border-radius: 10px 0 0 0;
|
||||
border-left: 1px solid #444;
|
||||
}
|
||||
|
||||
.cesium-navigation-button-right {
|
||||
border-radius: 0 10px 0 0;
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.cesium-navigation-button-selected {
|
||||
background-color: rgba(38, 38, 38, 0.75);
|
||||
}
|
||||
|
||||
.cesium-navigation-button-unselected {
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
.cesium-navigation-button-unselected:hover {
|
||||
background-color: rgba(76, 76, 76, 0.75);
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
import {
|
||||
buildModuleUrl,
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import NavigationHelpButtonViewModel from "./NavigationHelpButtonViewModel.js";
|
||||
|
||||
/**
|
||||
* <p>The NavigationHelpButton is a single button widget for displaying instructions for
|
||||
* navigating the globe with the mouse.</p><p style="clear: both;"></p><br/>
|
||||
*
|
||||
* @alias NavigationHelpButton
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} options Object with the following properties:
|
||||
* @param {Element|string} options.container The DOM element or ID that will contain the widget.
|
||||
* @param {boolean} [options.instructionsInitiallyVisible=false] True if the navigation instructions should initially be visible; otherwise, false.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*
|
||||
* @example
|
||||
* // In HTML head, include a link to the NavigationHelpButton.css stylesheet,
|
||||
* // and in the body, include: <div id="navigationHelpButtonContainer"></div>
|
||||
*
|
||||
* const navigationHelpButton = new Cesium.NavigationHelpButton({
|
||||
* container : 'navigationHelpButtonContainer'
|
||||
* });
|
||||
*/
|
||||
function NavigationHelpButton(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.container)) {
|
||||
throw new DeveloperError("options.container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const container = getElement(options.container);
|
||||
|
||||
const viewModel = new NavigationHelpButtonViewModel();
|
||||
|
||||
const showInsructionsDefault = options.instructionsInitiallyVisible ?? false;
|
||||
viewModel.showInstructions = showInsructionsDefault;
|
||||
|
||||
viewModel._svgPath =
|
||||
"M16,1.466C7.973,1.466,1.466,7.973,1.466,16c0,8.027,6.507,14.534,14.534,14.534c8.027,0,14.534-6.507,14.534-14.534C30.534,7.973,24.027,1.466,16,1.466z M17.328,24.371h-2.707v-2.596h2.707V24.371zM17.328,19.003v0.858h-2.707v-1.057c0-3.19,3.63-3.696,3.63-5.963c0-1.034-0.924-1.826-2.134-1.826c-1.254,0-2.354,0.924-2.354,0.924l-1.541-1.915c0,0,1.519-1.584,4.137-1.584c2.487,0,4.796,1.54,4.796,4.136C21.156,16.208,17.328,16.627,17.328,19.003z";
|
||||
|
||||
const wrapper = document.createElement("span");
|
||||
wrapper.className = "cesium-navigationHelpButton-wrapper";
|
||||
container.appendChild(wrapper);
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className =
|
||||
"cesium-button cesium-toolbar-button cesium-navigation-help-button";
|
||||
button.setAttribute(
|
||||
"data-bind",
|
||||
"\
|
||||
attr: { title: tooltip },\
|
||||
click: command,\
|
||||
cesiumSvgPath: { path: _svgPath, width: 32, height: 32 }",
|
||||
);
|
||||
wrapper.appendChild(button);
|
||||
|
||||
const instructionContainer = document.createElement("div");
|
||||
instructionContainer.className = "cesium-navigation-help";
|
||||
instructionContainer.setAttribute(
|
||||
"data-bind",
|
||||
'css: { "cesium-navigation-help-visible" : showInstructions}',
|
||||
);
|
||||
wrapper.appendChild(instructionContainer);
|
||||
|
||||
const mouseButton = document.createElement("button");
|
||||
mouseButton.type = "button";
|
||||
mouseButton.className =
|
||||
"cesium-navigation-button cesium-navigation-button-left";
|
||||
mouseButton.setAttribute(
|
||||
"data-bind",
|
||||
'click: showClick, css: {"cesium-navigation-button-selected": !_touch, "cesium-navigation-button-unselected": _touch}',
|
||||
);
|
||||
const mouseIcon = document.createElement("img");
|
||||
mouseIcon.src = buildModuleUrl("Widgets/Images/NavigationHelp/Mouse.svg");
|
||||
mouseIcon.className = "cesium-navigation-button-icon";
|
||||
mouseIcon.style.width = "25px";
|
||||
mouseIcon.style.height = "25px";
|
||||
mouseButton.appendChild(mouseIcon);
|
||||
mouseButton.appendChild(document.createTextNode("Mouse"));
|
||||
|
||||
const touchButton = document.createElement("button");
|
||||
touchButton.type = "button";
|
||||
touchButton.className =
|
||||
"cesium-navigation-button cesium-navigation-button-right";
|
||||
touchButton.setAttribute(
|
||||
"data-bind",
|
||||
'click: showTouch, css: {"cesium-navigation-button-selected": _touch, "cesium-navigation-button-unselected": !_touch}',
|
||||
);
|
||||
const touchIcon = document.createElement("img");
|
||||
touchIcon.src = buildModuleUrl("Widgets/Images/NavigationHelp/Touch.svg");
|
||||
touchIcon.className = "cesium-navigation-button-icon";
|
||||
touchIcon.style.width = "25px";
|
||||
touchIcon.style.height = "25px";
|
||||
touchButton.appendChild(touchIcon);
|
||||
touchButton.appendChild(document.createTextNode("Touch"));
|
||||
|
||||
instructionContainer.appendChild(mouseButton);
|
||||
instructionContainer.appendChild(touchButton);
|
||||
|
||||
const clickInstructions = document.createElement("div");
|
||||
clickInstructions.className =
|
||||
"cesium-click-navigation-help cesium-navigation-help-instructions";
|
||||
clickInstructions.setAttribute(
|
||||
"data-bind",
|
||||
'css: { "cesium-click-navigation-help-visible" : !_touch}',
|
||||
);
|
||||
clickInstructions.innerHTML = `\
|
||||
<table>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/MouseLeft.svg",
|
||||
)}" width="48" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-pan">Pan view</div>\
|
||||
<div class="cesium-navigation-help-details">Left click + drag</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/MouseRight.svg",
|
||||
)}" width="48" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-zoom">Zoom view</div>\
|
||||
<div class="cesium-navigation-help-details">Right click + drag, or</div>\
|
||||
<div class="cesium-navigation-help-details">Mouse wheel scroll</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/MouseMiddle.svg",
|
||||
)}" width="48" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-rotate">Rotate view</div>\
|
||||
<div class="cesium-navigation-help-details">Middle click + drag, or</div>\
|
||||
<div class="cesium-navigation-help-details">CTRL + Left/Right click + drag</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
</table>`;
|
||||
|
||||
instructionContainer.appendChild(clickInstructions);
|
||||
|
||||
const touchInstructions = document.createElement("div");
|
||||
touchInstructions.className =
|
||||
"cesium-touch-navigation-help cesium-navigation-help-instructions";
|
||||
touchInstructions.setAttribute(
|
||||
"data-bind",
|
||||
'css: { "cesium-touch-navigation-help-visible" : _touch}',
|
||||
);
|
||||
touchInstructions.innerHTML = `\
|
||||
<table>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/TouchDrag.svg",
|
||||
)}" width="70" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-pan">Pan view</div>\
|
||||
<div class="cesium-navigation-help-details">One finger drag</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/TouchZoom.svg",
|
||||
)}" width="70" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-zoom">Zoom view</div>\
|
||||
<div class="cesium-navigation-help-details">Two finger pinch</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/TouchTilt.svg",
|
||||
)}" width="70" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-rotate">Tilt view</div>\
|
||||
<div class="cesium-navigation-help-details">Two finger drag, same direction</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><img src="${buildModuleUrl(
|
||||
"Widgets/Images/NavigationHelp/TouchRotate.svg",
|
||||
)}" width="70" height="48" /></td>\
|
||||
<td>\
|
||||
<div class="cesium-navigation-help-tilt">Rotate view</div>\
|
||||
<div class="cesium-navigation-help-details">Two finger drag, opposite direction</div>\
|
||||
</td>\
|
||||
</tr>\
|
||||
</table>`;
|
||||
|
||||
instructionContainer.appendChild(touchInstructions);
|
||||
|
||||
knockout.applyBindings(viewModel, wrapper);
|
||||
|
||||
this._container = container;
|
||||
this._viewModel = viewModel;
|
||||
this._wrapper = wrapper;
|
||||
|
||||
this._closeInstructions = function (e) {
|
||||
if (!wrapper.contains(e.target)) {
|
||||
viewModel.showInstructions = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._closeInstructions, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._closeInstructions, true);
|
||||
document.addEventListener("touchstart", this._closeInstructions, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(NavigationHelpButton.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof NavigationHelpButton.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof NavigationHelpButton.prototype
|
||||
*
|
||||
* @type {NavigationHelpButtonViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
NavigationHelpButton.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
NavigationHelpButton.prototype.destroy = function () {
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._closeInstructions, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._closeInstructions, true);
|
||||
document.removeEventListener("touchstart", this._closeInstructions, true);
|
||||
}
|
||||
|
||||
knockout.cleanNode(this._wrapper);
|
||||
this._container.removeChild(this._wrapper);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default NavigationHelpButton;
|
||||
@@ -0,0 +1,77 @@
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link NavigationHelpButton}.
|
||||
* @alias NavigationHelpButtonViewModel
|
||||
* @constructor
|
||||
*/
|
||||
function NavigationHelpButtonViewModel() {
|
||||
/**
|
||||
* Gets or sets whether the instructions are currently shown. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.showInstructions = false;
|
||||
|
||||
const that = this;
|
||||
this._command = createCommand(function () {
|
||||
that.showInstructions = !that.showInstructions;
|
||||
});
|
||||
this._showClick = createCommand(function () {
|
||||
that._touch = false;
|
||||
});
|
||||
this._showTouch = createCommand(function () {
|
||||
that._touch = true;
|
||||
});
|
||||
|
||||
this._touch = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the tooltip. This property is observable.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.tooltip = "Navigation Instructions";
|
||||
|
||||
knockout.track(this, ["tooltip", "showInstructions", "_touch"]);
|
||||
}
|
||||
|
||||
Object.defineProperties(NavigationHelpButtonViewModel.prototype, {
|
||||
/**
|
||||
* Gets the Command that is executed when the button is clicked.
|
||||
* @memberof NavigationHelpButtonViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
command: {
|
||||
get: function () {
|
||||
return this._command;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Command that is executed when the mouse instructions should be shown.
|
||||
* @memberof NavigationHelpButtonViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showClick: {
|
||||
get: function () {
|
||||
return this._showClick;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the Command that is executed when the touch instructions should be shown.
|
||||
* @memberof NavigationHelpButtonViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
showTouch: {
|
||||
get: function () {
|
||||
return this._showTouch;
|
||||
},
|
||||
},
|
||||
});
|
||||
export default NavigationHelpButtonViewModel;
|
||||
@@ -0,0 +1,46 @@
|
||||
.cesium-lighter .cesium-navigation-help-instructions {
|
||||
border: 1px solid #759dc0;
|
||||
background-color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-help-pan {
|
||||
color: #66ccee;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-help-zoom {
|
||||
color: #65ec00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-help-rotate {
|
||||
color: #eec722;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-help-tilt {
|
||||
color: #d800d8;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-help-details {
|
||||
color: #222222;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-button {
|
||||
color: #222222;
|
||||
border-top: 1px solid #759dc0;
|
||||
border-right: 1px solid #759dc0;
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-button-selected {
|
||||
background-color: rgba(196, 225, 255, 0.9);
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-button-unselected {
|
||||
background-color: rgba(226, 240, 255, 0.9);
|
||||
}
|
||||
|
||||
.cesium-lighter .cesium-navigation-button-unselected:hover {
|
||||
background-color: rgba(166, 210, 255, 0.9);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
.cesium-performance-watchdog-message-area {
|
||||
position: relative;
|
||||
background-color: yellow;
|
||||
color: black;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.cesium-performance-watchdog-message {
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.cesium-performance-watchdog-message-dismiss {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin: 0 10px 0 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import PerformanceWatchdogViewModel from "./PerformanceWatchdogViewModel.js";
|
||||
|
||||
/**
|
||||
* Monitors performance of the application and displays a message if poor performance is detected.
|
||||
*
|
||||
* @alias PerformanceWatchdog
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {Element|string} options.container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} options.scene The {@link Scene} for which to monitor performance.
|
||||
* @param {string} [options.lowFrameRateMessage='This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.'] The
|
||||
* message to display when a low frame rate is detected. The message is interpeted as HTML, so make sure
|
||||
* it comes from a trusted source so that your application is not vulnerable to cross-site scripting attacks.
|
||||
*/
|
||||
function PerformanceWatchdog(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.container)) {
|
||||
throw new DeveloperError("options.container is required.");
|
||||
}
|
||||
if (!defined(options.scene)) {
|
||||
throw new DeveloperError("options.scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
const container = getElement(options.container);
|
||||
|
||||
const viewModel = new PerformanceWatchdogViewModel(options);
|
||||
|
||||
const element = document.createElement("div");
|
||||
element.className = "cesium-performance-watchdog-message-area";
|
||||
element.setAttribute("data-bind", "visible: showingLowFrameRateMessage");
|
||||
|
||||
const dismissButton = document.createElement("button");
|
||||
dismissButton.setAttribute("type", "button");
|
||||
dismissButton.className = "cesium-performance-watchdog-message-dismiss";
|
||||
dismissButton.innerHTML = "×";
|
||||
dismissButton.setAttribute("data-bind", "click: dismissMessage");
|
||||
element.appendChild(dismissButton);
|
||||
|
||||
const message = document.createElement("div");
|
||||
message.className = "cesium-performance-watchdog-message";
|
||||
message.setAttribute("data-bind", "html: lowFrameRateMessage");
|
||||
element.appendChild(message);
|
||||
|
||||
container.appendChild(element);
|
||||
|
||||
knockout.applyBindings(viewModel, element);
|
||||
|
||||
this._container = container;
|
||||
this._viewModel = viewModel;
|
||||
this._element = element;
|
||||
}
|
||||
|
||||
Object.defineProperties(PerformanceWatchdog.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof PerformanceWatchdog.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof PerformanceWatchdog.prototype
|
||||
*
|
||||
* @type {PerformanceWatchdogViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @memberof PerformanceWatchdog
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
PerformanceWatchdog.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
* @memberof PerformanceWatchdog
|
||||
*/
|
||||
PerformanceWatchdog.prototype.destroy = function () {
|
||||
this._viewModel.destroy();
|
||||
knockout.cleanNode(this._element);
|
||||
this._container.removeChild(this._element);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default PerformanceWatchdog;
|
||||
@@ -0,0 +1,112 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FrameRateMonitor,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link PerformanceWatchdog}.
|
||||
*
|
||||
* @alias PerformanceWatchdogViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {object} [options] Object with the following properties:
|
||||
* @param {Scene} options.scene The Scene instance for which to monitor performance.
|
||||
* @param {string} [options.lowFrameRateMessage='This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.'] The
|
||||
* message to display when a low frame rate is detected. The message is interpeted as HTML, so make sure
|
||||
* it comes from a trusted source so that your application is not vulnerable to cross-site scripting attacks.
|
||||
*/
|
||||
function PerformanceWatchdogViewModel(options) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(options) || !defined(options.scene)) {
|
||||
throw new DeveloperError("options.scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._scene = options.scene;
|
||||
|
||||
/**
|
||||
* Gets or sets the message to display when a low frame rate is detected. This string will be interpreted as HTML.
|
||||
* @type {string}
|
||||
*/
|
||||
this.lowFrameRateMessage =
|
||||
options.lowFrameRateMessage ??
|
||||
"This application appears to be performing poorly on your system. Please try using a different web browser or updating your video drivers.";
|
||||
|
||||
/**
|
||||
* Gets or sets a value indicating whether the low frame rate message has previously been dismissed by the user. If it has
|
||||
* been dismissed, the message will not be redisplayed, no matter the frame rate.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.lowFrameRateMessageDismissed = false;
|
||||
|
||||
/**
|
||||
* Gets or sets a value indicating whether the low frame rate message is currently being displayed.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.showingLowFrameRateMessage = false;
|
||||
|
||||
knockout.track(this, [
|
||||
"lowFrameRateMessage",
|
||||
"lowFrameRateMessageDismissed",
|
||||
"showingLowFrameRateMessage",
|
||||
]);
|
||||
|
||||
const that = this;
|
||||
this._dismissMessage = createCommand(function () {
|
||||
that.showingLowFrameRateMessage = false;
|
||||
that.lowFrameRateMessageDismissed = true;
|
||||
});
|
||||
|
||||
const monitor = FrameRateMonitor.fromScene(options.scene);
|
||||
|
||||
this._unsubscribeLowFrameRate = monitor.lowFrameRate.addEventListener(
|
||||
function () {
|
||||
if (!that.lowFrameRateMessageDismissed) {
|
||||
that.showingLowFrameRateMessage = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
this._unsubscribeNominalFrameRate = monitor.nominalFrameRate.addEventListener(
|
||||
function () {
|
||||
that.showingLowFrameRateMessage = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Object.defineProperties(PerformanceWatchdogViewModel.prototype, {
|
||||
/**
|
||||
* Gets the {@link Scene} instance for which to monitor performance.
|
||||
* @memberof PerformanceWatchdogViewModel.prototype
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a command that dismisses the low frame rate message. Once it is dismissed, the message
|
||||
* will not be redisplayed.
|
||||
* @memberof PerformanceWatchdogViewModel.prototype
|
||||
* @type {Command}
|
||||
*/
|
||||
dismissMessage: {
|
||||
get: function () {
|
||||
return this._dismissMessage;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
PerformanceWatchdogViewModel.prototype.destroy = function () {
|
||||
this._unsubscribeLowFrameRate();
|
||||
this._unsubscribeNominalFrameRate();
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default PerformanceWatchdogViewModel;
|
||||
@@ -0,0 +1,53 @@
|
||||
span.cesium-projectionPicker-wrapper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-visible {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s linear;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-hidden {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
visibility 0s 0.25s,
|
||||
opacity 0.25s linear;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper .cesium-projectionPicker-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper .cesium-projectionPicker-dropDown-icon {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper .cesium-projectionPicker-buttonPerspective,
|
||||
.cesium-projectionPicker-wrapper .cesium-projectionPicker-buttonOrthographic {
|
||||
margin: 0 0 3px 0;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper
|
||||
.cesium-projectionPicker-buttonPerspective
|
||||
.cesium-projectionPicker-iconOrthographic {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper
|
||||
.cesium-projectionPicker-buttonOrthographic
|
||||
.cesium-projectionPicker-iconPerspective {
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.cesium-projectionPicker-wrapper .cesium-projectionPicker-selected {
|
||||
border-color: #2e2;
|
||||
box-shadow:
|
||||
0 0 8px #fff,
|
||||
0 0 8px #fff;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import ProjectionPickerViewModel from "./ProjectionPickerViewModel.js";
|
||||
|
||||
const perspectivePath =
|
||||
"M 28.15625,10.4375 9.125,13.21875 13.75,43.25 41.75,55.09375 50.8125,37 54.5,11.9375 z m 0.125,3 19.976451,0.394265 L 43.03125,16.875 22.6875,14.28125 z M 50.971746,15.705477 47.90625,36.03125 42.53125,46 44.84375,19.3125 z M 12.625,16.03125 l 29.15625,3.6875 -2.65625,31 L 16.4375,41.125 z";
|
||||
const orthographicPath =
|
||||
"m 31.560594,6.5254438 -20.75,12.4687502 0.1875,24.5625 22.28125,11.8125 19.5,-12 0.65625,-0.375 0,-0.75 0.0312,-23.21875 z m 0.0625,3.125 16.65625,9.5000002 -16.125,10.28125 -17.34375,-9.71875 z m 18.96875,11.1875002 0.15625,20.65625 -17.46875,10.59375 0.15625,-20.28125 z m -37.0625,1.25 17.21875,9.625 -0.15625,19.21875 -16.9375,-9 z";
|
||||
|
||||
/**
|
||||
* The ProjectionPicker is a single button widget for switching between perspective and orthographic projections.
|
||||
*
|
||||
* @alias ProjectionPicker
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene The Scene instance to use.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*
|
||||
* @example
|
||||
* // In HTML head, include a link to the ProjectionPicker.css stylesheet,
|
||||
* // and in the body, include: <div id="projectionPickerContainer"></div>
|
||||
* // Note: This code assumes you already have a Scene instance.
|
||||
*
|
||||
* const projectionPicker = new Cesium.ProjectionPicker('projectionPickerContainer', scene);
|
||||
*/
|
||||
function ProjectionPicker(container, scene) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const viewModel = new ProjectionPickerViewModel(scene);
|
||||
|
||||
viewModel._perspectivePath = perspectivePath;
|
||||
viewModel._orthographicPath = orthographicPath;
|
||||
|
||||
const wrapper = document.createElement("span");
|
||||
wrapper.className = "cesium-projectionPicker-wrapper cesium-toolbar-button";
|
||||
container.appendChild(wrapper);
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "cesium-button cesium-toolbar-button";
|
||||
button.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-projectionPicker-buttonPerspective": !_orthographic,\
|
||||
"cesium-projectionPicker-buttonOrthographic": _orthographic,\
|
||||
"cesium-button-disabled" : sceneMode === _sceneMode.SCENE2D || _flightInProgress, \
|
||||
"cesium-projectionPicker-selected": dropDownVisible },\
|
||||
attr: { title: selectedTooltip },\
|
||||
click: toggleDropDown',
|
||||
);
|
||||
button.innerHTML =
|
||||
'\
|
||||
<!-- ko cesiumSvgPath: { path: _perspectivePath, width: 64, height: 64, css: "cesium-projectionPicker-iconPerspective" } --><!-- /ko -->\
|
||||
<!-- ko cesiumSvgPath: { path: _orthographicPath, width: 64, height: 64, css: "cesium-projectionPicker-iconOrthographic" } --><!-- /ko -->';
|
||||
wrapper.appendChild(button);
|
||||
|
||||
const perspectiveButton = document.createElement("button");
|
||||
perspectiveButton.type = "button";
|
||||
perspectiveButton.className =
|
||||
"cesium-button cesium-toolbar-button cesium-projectionPicker-dropDown-icon";
|
||||
perspectiveButton.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-projectionPicker-visible" : (dropDownVisible && _orthographic),\
|
||||
"cesium-projectionPicker-none" : !_orthographic,\
|
||||
"cesium-projectionPicker-hidden" : !dropDownVisible },\
|
||||
attr: { title: tooltipPerspective },\
|
||||
click: switchToPerspective,\
|
||||
cesiumSvgPath: { path: _perspectivePath, width: 64, height: 64 }',
|
||||
);
|
||||
wrapper.appendChild(perspectiveButton);
|
||||
|
||||
const orthographicButton = document.createElement("button");
|
||||
orthographicButton.type = "button";
|
||||
orthographicButton.className =
|
||||
"cesium-button cesium-toolbar-button cesium-projectionPicker-dropDown-icon";
|
||||
orthographicButton.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-projectionPicker-visible" : (dropDownVisible && !_orthographic),\
|
||||
"cesium-projectionPicker-none" : _orthographic,\
|
||||
"cesium-projectionPicker-hidden" : !dropDownVisible},\
|
||||
attr: { title: tooltipOrthographic },\
|
||||
click: switchToOrthographic,\
|
||||
cesiumSvgPath: { path: _orthographicPath, width: 64, height: 64 }',
|
||||
);
|
||||
wrapper.appendChild(orthographicButton);
|
||||
|
||||
knockout.applyBindings(viewModel, wrapper);
|
||||
|
||||
this._viewModel = viewModel;
|
||||
this._container = container;
|
||||
this._wrapper = wrapper;
|
||||
|
||||
this._closeDropDown = function (e) {
|
||||
if (!wrapper.contains(e.target)) {
|
||||
viewModel.dropDownVisible = false;
|
||||
}
|
||||
};
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._closeDropDown, true);
|
||||
document.addEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(ProjectionPicker.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof ProjectionPicker.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof ProjectionPicker.prototype
|
||||
*
|
||||
* @type {ProjectionPickerViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
ProjectionPicker.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
ProjectionPicker.prototype.destroy = function () {
|
||||
this._viewModel.destroy();
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._closeDropDown, true);
|
||||
document.removeEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
|
||||
knockout.cleanNode(this._wrapper);
|
||||
this._container.removeChild(this._wrapper);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default ProjectionPicker;
|
||||
@@ -0,0 +1,201 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
EventHelper,
|
||||
OrthographicFrustum,
|
||||
SceneMode,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link ProjectionPicker}.
|
||||
* @alias ProjectionPickerViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Scene} scene The Scene to switch projections.
|
||||
*/
|
||||
function ProjectionPickerViewModel(scene) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._scene = scene;
|
||||
this._orthographic = scene.camera.frustum instanceof OrthographicFrustum;
|
||||
this._flightInProgress = false;
|
||||
|
||||
/**
|
||||
* Gets or sets whether the button drop-down is currently visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.dropDownVisible = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the perspective projection tooltip. This property is observable.
|
||||
* @type {string}
|
||||
* @default 'Perspective Projection'
|
||||
*/
|
||||
this.tooltipPerspective = "Perspective Projection";
|
||||
|
||||
/**
|
||||
* Gets or sets the orthographic projection tooltip. This property is observable.
|
||||
* @type {string}
|
||||
* @default 'Orthographic Projection'
|
||||
*/
|
||||
this.tooltipOrthographic = "Orthographic Projection";
|
||||
|
||||
/**
|
||||
* Gets the currently active tooltip. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.selectedTooltip = undefined;
|
||||
|
||||
/**
|
||||
* Gets or sets the current SceneMode. This property is observable.
|
||||
* @type {SceneMode}
|
||||
*/
|
||||
this.sceneMode = scene.mode;
|
||||
|
||||
knockout.track(this, [
|
||||
"_orthographic",
|
||||
"_flightInProgress",
|
||||
"sceneMode",
|
||||
"dropDownVisible",
|
||||
"tooltipPerspective",
|
||||
"tooltipOrthographic",
|
||||
]);
|
||||
|
||||
const that = this;
|
||||
knockout.defineProperty(this, "selectedTooltip", function () {
|
||||
if (that._orthographic) {
|
||||
return that.tooltipOrthographic;
|
||||
}
|
||||
return that.tooltipPerspective;
|
||||
});
|
||||
|
||||
this._toggleDropDown = createCommand(function () {
|
||||
if (that.sceneMode === SceneMode.SCENE2D || that._flightInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
that.dropDownVisible = !that.dropDownVisible;
|
||||
});
|
||||
|
||||
this._eventHelper = new EventHelper();
|
||||
this._eventHelper.add(
|
||||
scene.morphComplete,
|
||||
function (transitioner, oldMode, newMode, isMorphing) {
|
||||
that.sceneMode = newMode;
|
||||
that._orthographic =
|
||||
newMode === SceneMode.SCENE2D ||
|
||||
that._scene.camera.frustum instanceof OrthographicFrustum;
|
||||
},
|
||||
);
|
||||
this._eventHelper.add(scene.preRender, function () {
|
||||
that._flightInProgress = defined(scene.camera._currentFlight);
|
||||
});
|
||||
|
||||
this._switchToPerspective = createCommand(function () {
|
||||
if (that.sceneMode === SceneMode.SCENE2D) {
|
||||
return;
|
||||
}
|
||||
|
||||
that._scene.camera.switchToPerspectiveFrustum();
|
||||
that._orthographic = false;
|
||||
that.dropDownVisible = false;
|
||||
});
|
||||
|
||||
this._switchToOrthographic = createCommand(function () {
|
||||
if (that.sceneMode === SceneMode.SCENE2D) {
|
||||
return;
|
||||
}
|
||||
|
||||
that._scene.camera.switchToOrthographicFrustum();
|
||||
that._orthographic = true;
|
||||
that.dropDownVisible = false;
|
||||
});
|
||||
|
||||
//Used by knockout
|
||||
this._sceneMode = SceneMode;
|
||||
}
|
||||
|
||||
Object.defineProperties(ProjectionPickerViewModel.prototype, {
|
||||
/**
|
||||
* Gets the scene
|
||||
* @memberof ProjectionPickerViewModel.prototype
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the drop down box.
|
||||
* @memberof ProjectionPickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleDropDown: {
|
||||
get: function () {
|
||||
return this._toggleDropDown;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to switch to a perspective projection.
|
||||
* @memberof ProjectionPickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
switchToPerspective: {
|
||||
get: function () {
|
||||
return this._switchToPerspective;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to switch to orthographic projection.
|
||||
* @memberof ProjectionPickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
switchToOrthographic: {
|
||||
get: function () {
|
||||
return this._switchToOrthographic;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets whether the scene is currently using an orthographic projection.
|
||||
* @memberof ProjectionPickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
isOrthographicProjection: {
|
||||
get: function () {
|
||||
return this._orthographic;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
ProjectionPickerViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the view model.
|
||||
*/
|
||||
ProjectionPickerViewModel.prototype.destroy = function () {
|
||||
this._eventHelper.removeAll();
|
||||
destroyObject(this);
|
||||
};
|
||||
export default ProjectionPickerViewModel;
|
||||
@@ -0,0 +1,84 @@
|
||||
span.cesium-sceneModePicker-wrapper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-visible {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.25s linear;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-hidden {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
visibility 0s 0.25s,
|
||||
opacity 0.25s linear;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-slide-svg {
|
||||
transition: left 2s;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 3px 0;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-button3D,
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-buttonColumbusView,
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-button2D {
|
||||
margin: 0 0 3px 0;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-button3D
|
||||
.cesium-sceneModePicker-icon2D {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-button3D
|
||||
.cesium-sceneModePicker-iconColumbusView {
|
||||
left: 200%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-buttonColumbusView
|
||||
.cesium-sceneModePicker-icon3D {
|
||||
left: -200%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-buttonColumbusView
|
||||
.cesium-sceneModePicker-icon2D {
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-button2D
|
||||
.cesium-sceneModePicker-icon3D {
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper
|
||||
.cesium-sceneModePicker-button2D
|
||||
.cesium-sceneModePicker-iconColumbusView {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-selected {
|
||||
border-color: #2e2;
|
||||
box-shadow:
|
||||
0 0 8px #fff,
|
||||
0 0 8px #fff;
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
FeatureDetection,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import SceneModePickerViewModel from "./SceneModePickerViewModel.js";
|
||||
|
||||
const globePath =
|
||||
"m 32.401392,4.9330437 c -7.087603,0 -14.096095,2.884602 -19.10793,7.8946843 -5.0118352,5.010083 -7.9296167,11.987468 -7.9296167,19.072999 0,7.085531 2.9177815,14.097848 7.9296167,19.107931 4.837653,4.835961 11.541408,7.631372 18.374354,7.82482 0.05712,0.01231 0.454119,0.139729 0.454119,0.139729 l 0.03493,-0.104797 c 0.08246,7.84e-4 0.162033,0.03493 0.244525,0.03493 0.08304,0 0.161515,-0.03414 0.244526,-0.03493 l 0.03493,0.104797 c 0,0 0.309474,-0.129487 0.349323,-0.139729 6.867765,-0.168094 13.582903,-2.965206 18.444218,-7.82482 2.558195,-2.5573 4.551081,-5.638134 5.903547,-8.977584 1.297191,-3.202966 2.02607,-6.661489 2.02607,-10.130347 0,-6.237309 -2.366261,-12.31219 -6.322734,-17.116794 -0.0034,-0.02316 0.0049,-0.04488 0,-0.06986 -0.01733,-0.08745 -0.104529,-0.278855 -0.104797,-0.279458 -5.31e-4,-0.0012 -0.522988,-0.628147 -0.523984,-0.62878 \
|
||||
-3.47e-4,-2.2e-4 -0.133444,-0.03532 -0.244525,-0.06987 C 51.944299,13.447603 51.751076,13.104317 51.474391,12.827728 46.462556,7.8176457 39.488996,4.9330437 32.401392,4.9330437 z m -2.130866,3.5281554 0.104797,9.6762289 c -4.111695,-0.08361 -7.109829,-0.423664 -9.257041,-0.943171 1.198093,-2.269271 2.524531,-4.124404 3.91241,-5.414496 2.167498,-2.0147811 3.950145,-2.8540169 5.239834,-3.3185619 z m 2.794579,0 c 1.280302,0.4754953 3.022186,1.3285948 5.065173,3.2486979 1.424667,1.338973 2.788862,3.303645 3.982275,5.728886 -2.29082,0.403367 -5.381258,0.621049 -8.942651,0.698645 L 33.065105,8.4611991 z m 5.728886,0.2445256 c 4.004072,1.1230822 7.793098,3.1481363 10.724195,6.0782083 0.03468,0.03466 0.07033,0.06991 0.104797,0.104797 -0.45375,0.313891 -0.923054,0.663002 -1.956205,1.082899 -0.647388,0.263114 -1.906242,0.477396 -2.829511,0.733577 -1.382296,-2.988132 \
|
||||
-3.027146,-5.368585 -4.785716,-7.0213781 -0.422866,-0.397432 -0.835818,-0.6453247 -1.25756,-0.9781032 z m -15.33525,0.7685092 c -0.106753,0.09503 -0.207753,0.145402 -0.31439,0.244526 -1.684973,1.5662541 -3.298068,3.8232211 -4.680919,6.5672591 -0.343797,-0.14942 -1.035052,-0.273198 -1.292493,-0.419186 -0.956528,-0.542427 -1.362964,-1.022024 -1.537018,-1.292493 -0.0241,-0.03745 -0.01868,-0.0401 -0.03493,-0.06986 2.250095,-2.163342 4.948824,-3.869984 7.859752,-5.0302421 z m -9.641296,7.0912431 c 0.464973,0.571618 0.937729,1.169056 1.956205,1.746612 0.349907,0.198425 1.107143,0.335404 1.537018,0.523983 -1.20166,3.172984 -1.998037,7.051901 -2.165798,11.772162 C 14.256557,30.361384 12.934823,30.161483 12.280427,29.90959 10.644437,29.279855 9.6888882,28.674891 9.1714586,28.267775 8.6540289,27.860658 8.6474751,27.778724 8.6474751,27.778724 l -0.069864,0.03493 C 9.3100294,23.691285 \
|
||||
11.163248,19.798527 13.817445,16.565477 z m 37.552149,0.523984 c 2.548924,3.289983 4.265057,7.202594 4.890513,11.318043 -0.650428,0.410896 -1.756876,1.001936 -3.563088,1.606882 -1.171552,0.392383 -3.163859,0.759153 -4.960377,1.117832 -0.04367,-4.752703 -0.784809,-8.591423 -1.88634,-11.807094 0.917574,-0.263678 2.170552,-0.486495 2.864443,-0.76851 1.274693,-0.518066 2.003942,-1.001558 2.654849,-1.467153 z m -31.439008,2.619917 c 2.487341,0.672766 5.775813,1.137775 10.479669,1.222628 l 0.104797,10.689263 0,0.03493 0,0.733577 c -5.435005,-0.09059 -9.512219,-0.519044 -12.610536,-1.117831 0.106127,-4.776683 0.879334,-8.55791 2.02607,-11.562569 z m 23.264866,0.31439 c 1.073459,3.067541 1.833795,6.821314 1.816476,11.702298 -3.054474,0.423245 -7.062018,0.648559 -11.702298,0.698644 l 0,-0.838373 -0.104796,-10.654331 c 4.082416,-0.0864 7.404468,-0.403886 9.990618,-0.908238 z \
|
||||
M 8.2632205,30.922625 c 0.7558676,0.510548 1.5529563,1.013339 3.0041715,1.57195 0.937518,0.360875 2.612202,0.647642 3.91241,0.978102 0.112814,3.85566 0.703989,7.107756 1.606883,9.920754 -1.147172,-0.324262 -2.644553,-0.640648 -3.423359,-0.978102 -1.516688,-0.657177 -2.386627,-1.287332 -2.864443,-1.71168 -0.477816,-0.424347 -0.489051,-0.489051 -0.489051,-0.489051 L 9.8002387,40.319395 C 8.791691,37.621767 8.1584238,34.769583 8.1584238,31.900727 c 0,-0.330153 0.090589,-0.648169 0.1047967,-0.978102 z m 48.2763445,0.419186 c 0.0047,0.188973 0.06986,0.36991 0.06986,0.558916 0,2.938869 -0.620228,5.873558 -1.676747,8.628261 -0.07435,0.07583 -0.06552,0.07411 -0.454119,0.349323 -0.606965,0.429857 -1.631665,1.042044 -3.318562,1.676747 -1.208528,0.454713 -3.204964,0.850894 -5.135038,1.25756 0.84593,-2.765726 1.41808,-6.005357 1.606883,-9.815957 2.232369,-0.413371 4.483758,-0.840201 \
|
||||
5.938479,-1.327425 1.410632,-0.472457 2.153108,-0.89469 2.96924,-1.327425 z m -38.530252,2.864443 c 3.208141,0.56697 7.372279,0.898588 12.575603,0.978103 l 0.174662,9.885821 c -4.392517,-0.06139 -8.106722,-0.320566 -10.863925,-0.803441 -1.051954,-2.664695 -1.692909,-6.043794 -1.88634,-10.060483 z m 26.793022,0.31439 c -0.246298,3.923551 -0.877762,7.263679 -1.816476,9.885822 -2.561957,0.361954 -5.766249,0.560708 -9.431703,0.62878 l -0.174661,-9.815957 c 4.491734,-0.04969 8.334769,-0.293032 11.42284,-0.698645 z M 12.035901,44.860585 c 0.09977,0.04523 0.105535,0.09465 0.209594,0.139729 1.337656,0.579602 3.441099,1.058072 5.589157,1.537018 1.545042,3.399208 3.548524,5.969402 5.589157,7.789888 -3.034411,-1.215537 -5.871615,-3.007978 -8.174142,-5.309699 -1.245911,-1.245475 -2.271794,-2.662961 -3.213766,-4.156936 z m 40.69605,0 c -0.941972,1.493975 -1.967855,2.911461 \
|
||||
-3.213765,4.156936 -2.74253,2.741571 -6.244106,4.696717 -9.955686,5.868615 0.261347,-0.241079 0.507495,-0.394491 0.768509,-0.663713 1.674841,-1.727516 3.320792,-4.181056 4.645987,-7.265904 2.962447,-0.503021 5.408965,-1.122293 7.161107,-1.781544 0.284034,-0.106865 0.337297,-0.207323 0.593848,-0.31439 z m -31.404076,2.305527 c 2.645807,0.376448 5.701178,0.649995 9.466635,0.698645 l 0.139729,7.789888 c -1.38739,-0.480844 -3.316218,-1.29837 -5.659022,-3.388427 -1.388822,-1.238993 -2.743668,-3.0113 -3.947342,-5.100106 z m 20.365491,0.104797 c -1.04872,2.041937 -2.174337,3.779068 -3.353494,4.995309 -1.853177,1.911459 -3.425515,2.82679 -4.611055,3.353494 l -0.139729,-7.789887 c 3.13091,-0.05714 5.728238,-0.278725 8.104278,-0.558916 z";
|
||||
const flatMapPath =
|
||||
"m 2.9825053,17.550598 0,1.368113 0,26.267766 0,1.368113 1.36811,0 54.9981397,0 1.36811,0 0,-1.368113 0,-26.267766 0,-1.368113 -1.36811,0 -54.9981397,0 -1.36811,0 z m 2.73623,2.736226 10.3292497,0 0,10.466063 -10.3292497,0 0,-10.466063 z m 13.0654697,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 11.69737,0 0,10.466063 -11.69737,0 0,-10.466063 z m 14.43359,0 10.32926,0 0,10.466063 -10.32926,0 0,-10.466063 z m -41.9326497,13.202288 10.3292497,0 0,10.329252 -10.3292497,0 0,-10.329252 z m 13.0654697,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 11.69737,0 0,10.329252 -11.69737,0 0,-10.329252 z m 14.43359,0 10.32926,0 0,10.329252 -10.32926,0 0,-10.329252 z";
|
||||
const columbusViewPath =
|
||||
"m 14.723969,17.675598 -0.340489,0.817175 -11.1680536,26.183638 -0.817175,1.872692 2.076986,0 54.7506996,0 2.07698,0 -0.81717,-1.872692 -11.16805,-26.183638 -0.34049,-0.817175 -0.91933,0 -32.414586,0 -0.919322,0 z m 1.838643,2.723916 6.196908,0 -2.928209,10.418977 -7.729111,0 4.460412,-10.418977 z m 9.02297,0 4.903049,0 0,10.418977 -7.831258,0 2.928209,-10.418977 z m 7.626964,0 5.584031,0 2.62176,10.418977 -8.205791,0 0,-10.418977 z m 8.410081,0 5.51593,0 4.46042,10.418977 -7.38863,0 -2.58772,-10.418977 z m -30.678091,13.142892 8.103649,0 -2.89416,10.282782 -9.6018026,0 4.3923136,-10.282782 z m 10.929711,0 8.614384,0 0,10.282782 -11.508544,0 2.89416,-10.282782 z m 11.338299,0 8.852721,0 2.58772,10.282782 -11.440441,0 0,-10.282782 z m 11.678781,0 7.86531,0 4.39231,10.282782 -9.6699,0 -2.58772,-10.282782 z";
|
||||
|
||||
/**
|
||||
* <img src="Images/sceneModePicker.png" style="float: left; margin-right: 10px;" width="44" height="116" />
|
||||
* <p>The SceneModePicker is a single button widget for switching between scene modes;
|
||||
* shown to the left in its expanded state. Programatic switching of scene modes will
|
||||
* be automatically reflected in the widget as long as the specified Scene
|
||||
* is used to perform the change.</p><p style="clear: both;"></p><br/>
|
||||
*
|
||||
* @alias SceneModePicker
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene The Scene instance to use.
|
||||
* @param {number} [duration=2.0] The time, in seconds, it takes for the scene to transition.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*
|
||||
* @example
|
||||
* // In HTML head, include a link to the SceneModePicker.css stylesheet,
|
||||
* // and in the body, include: <div id="sceneModePickerContainer"></div>
|
||||
* // Note: This code assumes you already have a Scene instance.
|
||||
*
|
||||
* const sceneModePicker = new Cesium.SceneModePicker('sceneModePickerContainer', scene);
|
||||
*/
|
||||
function SceneModePicker(container, scene, duration) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
const viewModel = new SceneModePickerViewModel(scene, duration);
|
||||
|
||||
viewModel._globePath = globePath;
|
||||
viewModel._flatMapPath = flatMapPath;
|
||||
viewModel._columbusViewPath = columbusViewPath;
|
||||
|
||||
const wrapper = document.createElement("span");
|
||||
wrapper.className = "cesium-sceneModePicker-wrapper cesium-toolbar-button";
|
||||
container.appendChild(wrapper);
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "cesium-button cesium-toolbar-button";
|
||||
button.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-sceneModePicker-button2D": sceneMode === _sceneMode.SCENE2D,\
|
||||
"cesium-sceneModePicker-button3D": sceneMode === _sceneMode.SCENE3D,\
|
||||
"cesium-sceneModePicker-buttonColumbusView": sceneMode === _sceneMode.COLUMBUS_VIEW,\
|
||||
"cesium-sceneModePicker-selected": dropDownVisible },\
|
||||
attr: { title: selectedTooltip },\
|
||||
click: toggleDropDown',
|
||||
);
|
||||
button.innerHTML =
|
||||
'\
|
||||
<!-- ko cesiumSvgPath: { path: _globePath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon3D" } --><!-- /ko -->\
|
||||
<!-- ko cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-icon2D" } --><!-- /ko -->\
|
||||
<!-- ko cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64, css: "cesium-sceneModePicker-slide-svg cesium-sceneModePicker-iconColumbusView" } --><!-- /ko -->';
|
||||
wrapper.appendChild(button);
|
||||
|
||||
const morphTo3DButton = document.createElement("button");
|
||||
morphTo3DButton.type = "button";
|
||||
morphTo3DButton.className =
|
||||
"cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon";
|
||||
morphTo3DButton.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE3D)) || (!dropDownVisible && (sceneMode === _sceneMode.SCENE3D)),\
|
||||
"cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE3D,\
|
||||
"cesium-sceneModePicker-hidden" : !dropDownVisible },\
|
||||
attr: { title: tooltip3D },\
|
||||
click: morphTo3D,\
|
||||
cesiumSvgPath: { path: _globePath, width: 64, height: 64 }',
|
||||
);
|
||||
wrapper.appendChild(morphTo3DButton);
|
||||
|
||||
const morphTo2DButton = document.createElement("button");
|
||||
morphTo2DButton.type = "button";
|
||||
morphTo2DButton.className =
|
||||
"cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon";
|
||||
morphTo2DButton.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.SCENE2D)),\
|
||||
"cesium-sceneModePicker-none" : sceneMode === _sceneMode.SCENE2D,\
|
||||
"cesium-sceneModePicker-hidden" : !dropDownVisible },\
|
||||
attr: { title: tooltip2D },\
|
||||
click: morphTo2D,\
|
||||
cesiumSvgPath: { path: _flatMapPath, width: 64, height: 64 }',
|
||||
);
|
||||
wrapper.appendChild(morphTo2DButton);
|
||||
|
||||
const morphToCVButton = document.createElement("button");
|
||||
morphToCVButton.type = "button";
|
||||
morphToCVButton.className =
|
||||
"cesium-button cesium-toolbar-button cesium-sceneModePicker-dropDown-icon";
|
||||
morphToCVButton.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
css: { "cesium-sceneModePicker-visible" : (dropDownVisible && (sceneMode !== _sceneMode.COLUMBUS_VIEW)) || (!dropDownVisible && (sceneMode === _sceneMode.COLUMBUS_VIEW)),\
|
||||
"cesium-sceneModePicker-none" : sceneMode === _sceneMode.COLUMBUS_VIEW,\
|
||||
"cesium-sceneModePicker-hidden" : !dropDownVisible},\
|
||||
attr: { title: tooltipColumbusView },\
|
||||
click: morphToColumbusView,\
|
||||
cesiumSvgPath: { path: _columbusViewPath, width: 64, height: 64 }',
|
||||
);
|
||||
wrapper.appendChild(morphToCVButton);
|
||||
|
||||
knockout.applyBindings(viewModel, wrapper);
|
||||
|
||||
this._viewModel = viewModel;
|
||||
this._container = container;
|
||||
this._wrapper = wrapper;
|
||||
|
||||
this._closeDropDown = function (e) {
|
||||
if (!wrapper.contains(e.target)) {
|
||||
viewModel.dropDownVisible = false;
|
||||
}
|
||||
};
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.addEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.addEventListener("mousedown", this._closeDropDown, true);
|
||||
document.addEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperties(SceneModePicker.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof SceneModePicker.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof SceneModePicker.prototype
|
||||
*
|
||||
* @type {SceneModePickerViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
SceneModePicker.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
SceneModePicker.prototype.destroy = function () {
|
||||
this._viewModel.destroy();
|
||||
|
||||
if (FeatureDetection.supportsPointerEvents()) {
|
||||
document.removeEventListener("pointerdown", this._closeDropDown, true);
|
||||
} else {
|
||||
document.removeEventListener("mousedown", this._closeDropDown, true);
|
||||
document.removeEventListener("touchstart", this._closeDropDown, true);
|
||||
}
|
||||
|
||||
knockout.cleanNode(this._wrapper);
|
||||
this._container.removeChild(this._wrapper);
|
||||
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default SceneModePicker;
|
||||
@@ -0,0 +1,215 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
EventHelper,
|
||||
SceneMode,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import createCommand from "../createCommand.js";
|
||||
|
||||
/**
|
||||
* The view model for {@link SceneModePicker}.
|
||||
* @alias SceneModePickerViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Scene} scene The Scene to morph
|
||||
* @param {number} [duration=2.0] The duration of scene morph animations, in seconds
|
||||
*/
|
||||
function SceneModePickerViewModel(scene, duration) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._scene = scene;
|
||||
|
||||
const that = this;
|
||||
|
||||
const morphStart = function (transitioner, oldMode, newMode, isMorphing) {
|
||||
that.sceneMode = newMode;
|
||||
that.dropDownVisible = false;
|
||||
};
|
||||
|
||||
this._eventHelper = new EventHelper();
|
||||
this._eventHelper.add(scene.morphStart, morphStart);
|
||||
|
||||
this._duration = duration ?? 2.0;
|
||||
|
||||
/**
|
||||
* Gets or sets the current SceneMode. This property is observable.
|
||||
* @type {SceneMode}
|
||||
*/
|
||||
this.sceneMode = scene.mode;
|
||||
|
||||
/**
|
||||
* Gets or sets whether the button drop-down is currently visible. This property is observable.
|
||||
* @type {boolean}
|
||||
* @default false
|
||||
*/
|
||||
this.dropDownVisible = false;
|
||||
|
||||
/**
|
||||
* Gets or sets the 2D tooltip. This property is observable.
|
||||
* @type {string}
|
||||
* @default '2D'
|
||||
*/
|
||||
this.tooltip2D = "2D";
|
||||
|
||||
/**
|
||||
* Gets or sets the 3D tooltip. This property is observable.
|
||||
* @type {string}
|
||||
* @default '3D'
|
||||
*/
|
||||
this.tooltip3D = "3D";
|
||||
|
||||
/**
|
||||
* Gets or sets the Columbus View tooltip. This property is observable.
|
||||
* @type {string}
|
||||
* @default 'Columbus View'
|
||||
*/
|
||||
this.tooltipColumbusView = "Columbus View";
|
||||
|
||||
knockout.track(this, [
|
||||
"sceneMode",
|
||||
"dropDownVisible",
|
||||
"tooltip2D",
|
||||
"tooltip3D",
|
||||
"tooltipColumbusView",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Gets the currently active tooltip. This property is observable.
|
||||
* @type {string}
|
||||
*/
|
||||
this.selectedTooltip = undefined;
|
||||
knockout.defineProperty(this, "selectedTooltip", function () {
|
||||
const mode = that.sceneMode;
|
||||
if (mode === SceneMode.SCENE2D) {
|
||||
return that.tooltip2D;
|
||||
}
|
||||
if (mode === SceneMode.SCENE3D) {
|
||||
return that.tooltip3D;
|
||||
}
|
||||
return that.tooltipColumbusView;
|
||||
});
|
||||
|
||||
this._toggleDropDown = createCommand(function () {
|
||||
that.dropDownVisible = !that.dropDownVisible;
|
||||
});
|
||||
|
||||
this._morphTo2D = createCommand(function () {
|
||||
scene.morphTo2D(that._duration);
|
||||
});
|
||||
|
||||
this._morphTo3D = createCommand(function () {
|
||||
scene.morphTo3D(that._duration);
|
||||
});
|
||||
|
||||
this._morphToColumbusView = createCommand(function () {
|
||||
scene.morphToColumbusView(that._duration);
|
||||
});
|
||||
|
||||
//Used by knockout
|
||||
this._sceneMode = SceneMode;
|
||||
}
|
||||
|
||||
Object.defineProperties(SceneModePickerViewModel.prototype, {
|
||||
/**
|
||||
* Gets the scene
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets or sets the the duration of scene mode transition animations in seconds.
|
||||
* A value of zero causes the scene to instantly change modes.
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
* @type {number}
|
||||
*/
|
||||
duration: {
|
||||
get: function () {
|
||||
return this._duration;
|
||||
},
|
||||
set: function (value) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (value < 0.0) {
|
||||
throw new DeveloperError("duration value must be positive.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._duration = value;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to toggle the drop down box.
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
toggleDropDown: {
|
||||
get: function () {
|
||||
return this._toggleDropDown;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to morph to 2D.
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
morphTo2D: {
|
||||
get: function () {
|
||||
return this._morphTo2D;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to morph to 3D.
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
morphTo3D: {
|
||||
get: function () {
|
||||
return this._morphTo3D;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the command to morph to Columbus View.
|
||||
* @memberof SceneModePickerViewModel.prototype
|
||||
*
|
||||
* @type {Command}
|
||||
*/
|
||||
morphToColumbusView: {
|
||||
get: function () {
|
||||
return this._morphToColumbusView;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
SceneModePickerViewModel.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the view model.
|
||||
*/
|
||||
SceneModePickerViewModel.prototype.destroy = function () {
|
||||
this._eventHelper.removeAll();
|
||||
|
||||
destroyObject(this);
|
||||
};
|
||||
export default SceneModePickerViewModel;
|
||||
@@ -0,0 +1,23 @@
|
||||
.cesium-selection-wrapper {
|
||||
position: absolute;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
pointer-events: none;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition:
|
||||
visibility 0s 0.2s,
|
||||
opacity 0.2s ease-in;
|
||||
}
|
||||
|
||||
.cesium-selection-wrapper-visible {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 0.2s ease-out;
|
||||
}
|
||||
|
||||
.cesium-selection-wrapper svg {
|
||||
fill: #2e2;
|
||||
stroke: #000;
|
||||
stroke-width: 1.1px;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
defined,
|
||||
destroyObject,
|
||||
DeveloperError,
|
||||
getElement,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
import SelectionIndicatorViewModel from "./SelectionIndicatorViewModel.js";
|
||||
|
||||
/**
|
||||
* A widget for displaying an indicator on a selected object.
|
||||
*
|
||||
* @alias SelectionIndicator
|
||||
* @constructor
|
||||
*
|
||||
* @param {Element|string} container The DOM element or ID that will contain the widget.
|
||||
* @param {Scene} scene The Scene instance to use.
|
||||
*
|
||||
* @exception {DeveloperError} Element with id "container" does not exist in the document.
|
||||
*/
|
||||
function SelectionIndicator(container, scene) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
container = getElement(container);
|
||||
|
||||
this._container = container;
|
||||
|
||||
const el = document.createElement("div");
|
||||
el.className = "cesium-selection-wrapper";
|
||||
el.setAttribute(
|
||||
"data-bind",
|
||||
'\
|
||||
style: { "top" : _screenPositionY, "left" : _screenPositionX },\
|
||||
css: { "cesium-selection-wrapper-visible" : isVisible }',
|
||||
);
|
||||
container.appendChild(el);
|
||||
this._element = el;
|
||||
|
||||
const svgNS = "http://www.w3.org/2000/svg";
|
||||
const path =
|
||||
"M -34 -34 L -34 -11.25 L -30 -15.25 L -30 -30 L -15.25 -30 L -11.25 -34 L -34 -34 z M 11.25 -34 L 15.25 -30 L 30 -30 L 30 -15.25 L 34 -11.25 L 34 -34 L 11.25 -34 z M -34 11.25 L -34 34 L -11.25 34 L -15.25 30 L -30 30 L -30 15.25 L -34 11.25 z M 34 11.25 L 30 15.25 L 30 30 L 15.25 30 L 11.25 34 L 34 34 L 34 11.25 z";
|
||||
|
||||
const svg = document.createElementNS(svgNS, "svg:svg");
|
||||
svg.setAttribute("width", 160);
|
||||
svg.setAttribute("height", 160);
|
||||
svg.setAttribute("viewBox", "0 0 160 160");
|
||||
|
||||
const group = document.createElementNS(svgNS, "g");
|
||||
group.setAttribute("transform", "translate(80,80)");
|
||||
svg.appendChild(group);
|
||||
|
||||
const pathElement = document.createElementNS(svgNS, "path");
|
||||
pathElement.setAttribute("data-bind", "attr: { transform: _transform }");
|
||||
pathElement.setAttribute("d", path);
|
||||
group.appendChild(pathElement);
|
||||
|
||||
el.appendChild(svg);
|
||||
|
||||
const viewModel = new SelectionIndicatorViewModel(
|
||||
scene,
|
||||
this._element,
|
||||
this._container,
|
||||
);
|
||||
this._viewModel = viewModel;
|
||||
|
||||
knockout.applyBindings(this._viewModel, this._element);
|
||||
}
|
||||
|
||||
Object.defineProperties(SelectionIndicator.prototype, {
|
||||
/**
|
||||
* Gets the parent container.
|
||||
* @memberof SelectionIndicator.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the view model.
|
||||
* @memberof SelectionIndicator.prototype
|
||||
*
|
||||
* @type {SelectionIndicatorViewModel}
|
||||
*/
|
||||
viewModel: {
|
||||
get: function () {
|
||||
return this._viewModel;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {boolean} true if the object has been destroyed, false otherwise.
|
||||
*/
|
||||
SelectionIndicator.prototype.isDestroyed = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the widget. Should be called if permanently
|
||||
* removing the widget from layout.
|
||||
*/
|
||||
SelectionIndicator.prototype.destroy = function () {
|
||||
const container = this._container;
|
||||
knockout.cleanNode(this._element);
|
||||
container.removeChild(this._element);
|
||||
return destroyObject(this);
|
||||
};
|
||||
export default SelectionIndicator;
|
||||
@@ -0,0 +1,214 @@
|
||||
import {
|
||||
Cartesian2,
|
||||
defined,
|
||||
DeveloperError,
|
||||
EasingFunction,
|
||||
SceneTransforms,
|
||||
} from "@cesium/engine";
|
||||
import knockout from "../ThirdParty/knockout.js";
|
||||
|
||||
const screenSpacePos = new Cartesian2();
|
||||
const offScreen = "-1000px";
|
||||
|
||||
/**
|
||||
* The view model for {@link SelectionIndicator}.
|
||||
* @alias SelectionIndicatorViewModel
|
||||
* @constructor
|
||||
*
|
||||
* @param {Scene} scene The scene instance to use for screen-space coordinate conversion.
|
||||
* @param {Element} selectionIndicatorElement The element containing all elements that make up the selection indicator.
|
||||
* @param {Element} container The DOM element that contains the widget.
|
||||
*/
|
||||
function SelectionIndicatorViewModel(
|
||||
scene,
|
||||
selectionIndicatorElement,
|
||||
container,
|
||||
) {
|
||||
//>>includeStart('debug', pragmas.debug);
|
||||
if (!defined(scene)) {
|
||||
throw new DeveloperError("scene is required.");
|
||||
}
|
||||
|
||||
if (!defined(selectionIndicatorElement)) {
|
||||
throw new DeveloperError("selectionIndicatorElement is required.");
|
||||
}
|
||||
|
||||
if (!defined(container)) {
|
||||
throw new DeveloperError("container is required.");
|
||||
}
|
||||
//>>includeEnd('debug');
|
||||
|
||||
this._scene = scene;
|
||||
this._screenPositionX = offScreen;
|
||||
this._screenPositionY = offScreen;
|
||||
this._tweens = scene.tweens;
|
||||
this._container = container ?? document.body;
|
||||
this._selectionIndicatorElement = selectionIndicatorElement;
|
||||
this._scale = 1;
|
||||
|
||||
/**
|
||||
* Gets or sets the world position of the object for which to display the selection indicator.
|
||||
* @type {Cartesian3}
|
||||
*/
|
||||
this.position = undefined;
|
||||
|
||||
/**
|
||||
* Gets or sets the visibility of the selection indicator.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.showSelection = false;
|
||||
|
||||
knockout.track(this, [
|
||||
"position",
|
||||
"_screenPositionX",
|
||||
"_screenPositionY",
|
||||
"_scale",
|
||||
"showSelection",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Gets the visibility of the position indicator. This can be false even if an
|
||||
* object is selected, when the selected object has no position.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.isVisible = undefined;
|
||||
knockout.defineProperty(this, "isVisible", {
|
||||
get: function () {
|
||||
return this.showSelection && defined(this.position);
|
||||
},
|
||||
});
|
||||
|
||||
knockout.defineProperty(this, "_transform", {
|
||||
get: function () {
|
||||
return `scale(${this._scale})`;
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets or sets the function for converting the world position of the object to the screen space position.
|
||||
*
|
||||
* @member
|
||||
* @type {SelectionIndicatorViewModel.ComputeScreenSpacePosition}
|
||||
* @default SceneTransforms.worldToWindowCoordinates
|
||||
*
|
||||
* @example
|
||||
* selectionIndicatorViewModel.computeScreenSpacePosition = function(position, result) {
|
||||
* return Cesium.SceneTransforms.worldToWindowCoordinates(scene, position, result);
|
||||
* };
|
||||
*/
|
||||
this.computeScreenSpacePosition = function (position, result) {
|
||||
return SceneTransforms.worldToWindowCoordinates(scene, position, result);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the view of the selection indicator to match the position and content properties of the view model.
|
||||
* This function should be called as part of the render loop.
|
||||
*/
|
||||
SelectionIndicatorViewModel.prototype.update = function () {
|
||||
if (this.showSelection && defined(this.position)) {
|
||||
const screenPosition = this.computeScreenSpacePosition(
|
||||
this.position,
|
||||
screenSpacePos,
|
||||
);
|
||||
if (!defined(screenPosition)) {
|
||||
this._screenPositionX = offScreen;
|
||||
this._screenPositionY = offScreen;
|
||||
} else {
|
||||
const container = this._container;
|
||||
const containerWidth = container.parentNode.clientWidth;
|
||||
const containerHeight = container.parentNode.clientHeight;
|
||||
const indicatorSize = this._selectionIndicatorElement.clientWidth;
|
||||
const halfSize = indicatorSize * 0.5;
|
||||
|
||||
screenPosition.x =
|
||||
Math.min(
|
||||
Math.max(screenPosition.x, -indicatorSize),
|
||||
containerWidth + indicatorSize,
|
||||
) - halfSize;
|
||||
screenPosition.y =
|
||||
Math.min(
|
||||
Math.max(screenPosition.y, -indicatorSize),
|
||||
containerHeight + indicatorSize,
|
||||
) - halfSize;
|
||||
|
||||
this._screenPositionX = `${Math.floor(screenPosition.x + 0.25)}px`;
|
||||
this._screenPositionY = `${Math.floor(screenPosition.y + 0.25)}px`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Animate the indicator to draw attention to the selection.
|
||||
*/
|
||||
SelectionIndicatorViewModel.prototype.animateAppear = function () {
|
||||
this._tweens.addProperty({
|
||||
object: this,
|
||||
property: "_scale",
|
||||
startValue: 2,
|
||||
stopValue: 1,
|
||||
duration: 0.8,
|
||||
easingFunction: EasingFunction.EXPONENTIAL_OUT,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Animate the indicator to release the selection.
|
||||
*/
|
||||
SelectionIndicatorViewModel.prototype.animateDepart = function () {
|
||||
this._tweens.addProperty({
|
||||
object: this,
|
||||
property: "_scale",
|
||||
startValue: this._scale,
|
||||
stopValue: 1.5,
|
||||
duration: 0.8,
|
||||
easingFunction: EasingFunction.EXPONENTIAL_OUT,
|
||||
});
|
||||
};
|
||||
|
||||
Object.defineProperties(SelectionIndicatorViewModel.prototype, {
|
||||
/**
|
||||
* Gets the HTML element containing the selection indicator.
|
||||
* @memberof SelectionIndicatorViewModel.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
container: {
|
||||
get: function () {
|
||||
return this._container;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the HTML element that holds the selection indicator.
|
||||
* @memberof SelectionIndicatorViewModel.prototype
|
||||
*
|
||||
* @type {Element}
|
||||
*/
|
||||
selectionIndicatorElement: {
|
||||
get: function () {
|
||||
return this._selectionIndicatorElement;
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets the scene being used.
|
||||
* @memberof SelectionIndicatorViewModel.prototype
|
||||
*
|
||||
* @type {Scene}
|
||||
*/
|
||||
scene: {
|
||||
get: function () {
|
||||
return this._scene;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* A function that converts the world position of an object to a screen space position.
|
||||
* @callback SelectionIndicatorViewModel.ComputeScreenSpacePosition
|
||||
* @param {Cartesian3} position The position in WGS84 (world) coordinates.
|
||||
* @param {Cartesian2} result An object to return the input position transformed to window coordinates.
|
||||
* @returns {Cartesian2} The modified result parameter.
|
||||
*/
|
||||
export default SelectionIndicatorViewModel;
|
||||
@@ -0,0 +1,78 @@
|
||||
const svgNS = "http://www.w3.org/2000/svg";
|
||||
const svgClassName = "cesium-svgPath-svg";
|
||||
|
||||
/**
|
||||
* A Knockout binding handler that creates a DOM element for a single SVG path.
|
||||
* This binding handler will be registered as cesiumSvgPath.
|
||||
*
|
||||
* <p>
|
||||
* The parameter to this binding is an object with the following properties:
|
||||
* </p>
|
||||
*
|
||||
* <ul>
|
||||
* <li>path: The SVG path as a string.</li>
|
||||
* <li>width: The width of the SVG path with no transformations applied.</li>
|
||||
* <li>height: The height of the SVG path with no transformations applied.</li>
|
||||
* <li>css: Optional. A string containing additional CSS classes to apply to the SVG. 'cesium-svgPath-svg' is always applied.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @namespace SvgPathBindingHandler
|
||||
*
|
||||
* @example
|
||||
* // Create an SVG as a child of a div
|
||||
* <div data-bind="cesiumSvgPath: { path: 'M 100 100 L 300 100 L 200 300 z', width: 28, height: 28 }"></div>
|
||||
*
|
||||
* // parameters can be observable from the view model
|
||||
* <div data-bind="cesiumSvgPath: { path: currentPath, width: currentWidth, height: currentHeight }"></div>
|
||||
*
|
||||
* // or the whole object can be observable from the view model
|
||||
* <div data-bind="cesiumSvgPath: svgPathOptions"></div>
|
||||
*/
|
||||
const SvgPathBindingHandler = {
|
||||
/**
|
||||
* @function
|
||||
*/
|
||||
register: function (knockout) {
|
||||
knockout.bindingHandlers.cesiumSvgPath = {
|
||||
init: function (element, valueAccessor) {
|
||||
const svg = document.createElementNS(svgNS, "svg:svg");
|
||||
svg.setAttribute("class", svgClassName);
|
||||
|
||||
const pathElement = document.createElementNS(svgNS, "path");
|
||||
svg.appendChild(pathElement);
|
||||
|
||||
knockout.virtualElements.setDomNodeChildren(element, [svg]);
|
||||
|
||||
knockout.computed({
|
||||
read: function () {
|
||||
const value = knockout.unwrap(valueAccessor());
|
||||
|
||||
pathElement.setAttribute("d", knockout.unwrap(value.path));
|
||||
|
||||
const pathWidth = knockout.unwrap(value.width);
|
||||
const pathHeight = knockout.unwrap(value.height);
|
||||
|
||||
svg.setAttribute("width", pathWidth);
|
||||
svg.setAttribute("height", pathHeight);
|
||||
svg.setAttribute("viewBox", `0 0 ${pathWidth} ${pathHeight}`);
|
||||
|
||||
if (value.css) {
|
||||
svg.setAttribute(
|
||||
"class",
|
||||
`${svgClassName} ${knockout.unwrap(value.css)}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
disposeWhenNodeIsRemoved: element,
|
||||
});
|
||||
|
||||
return {
|
||||
controlsDescendantBindings: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
knockout.virtualElements.allowedBindings.cesiumSvgPath = true;
|
||||
},
|
||||
};
|
||||
export default SvgPathBindingHandler;
|
||||
@@ -0,0 +1,167 @@
|
||||
var oldValue;
|
||||
if (typeof ko !== 'undefined') {
|
||||
oldValue = ko;
|
||||
}
|
||||
|
||||
(function(){
|
||||
/*!
|
||||
* Knockout JavaScript library v3.5.1
|
||||
* (c) The Knockout.js team - http://knockoutjs.com/
|
||||
* License: MIT (http://www.opensource.org/licenses/mit-license.php)
|
||||
*/
|
||||
|
||||
(function() {(function(n){var A=this||(0,eval)("this"),w=A.document,R=A.navigator,v=A.jQuery,H=A.JSON;v||"undefined"===typeof jQuery||(v=jQuery);(function(n){n(A.ko={})})(function(S,T){function K(a,c){return null===a||typeof a in W?a===c:!1}function X(b,c){var d;return function(){d||(d=a.a.setTimeout(function(){d=n;b()},c))}}function Y(b,c){var d;return function(){clearTimeout(d);
|
||||
d=a.a.setTimeout(b,c)}}function Z(a,c){c&&"change"!==c?"beforeChange"===c?this.pc(a):this.gb(a,c):this.qc(a)}function aa(a,c){null!==c&&c.s&&c.s()}function ba(a,c){var d=this.qd,e=d[r];e.ra||(this.Qb&&this.mb[c]?(d.uc(c,a,this.mb[c]),this.mb[c]=null,--this.Qb):e.I[c]||d.uc(c,a,e.J?{da:a}:d.$c(a)),a.Ja&&a.gd())}var a="undefined"!==typeof S?S:{};a.b=function(b,c){for(var d=b.split("."),e=a,f=0;f<d.length-1;f++)e=e[d[f]];e[d[d.length-1]]=c};a.L=function(a,c,d){a[c]=d};a.version="3.5.1";a.b("version",
|
||||
a.version);a.options={deferUpdates:!1,useOnlyNativeEvents:!1,foreachHidesDestroyed:!1};a.a=function(){function b(a,b){for(var c in a)f.call(a,c)&&b(c,a[c])}function c(a,b){if(b)for(var c in b)f.call(b,c)&&(a[c]=b[c]);return a}function d(a,b){a.__proto__=b;return a}function e(b,c,d,e){var l=b[c].match(q)||[];a.a.D(d.match(q),function(b){a.a.Na(l,b,e)});b[c]=l.join(" ")}var f=Object.prototype.hasOwnProperty,g={__proto__:[]}instanceof Array,h="function"===typeof Symbol,m={},k={};m[R&&/Firefox\/2/i.test(R.userAgent)?
|
||||
"KeyboardEvent":"UIEvents"]=["keyup","keydown","keypress"];m.MouseEvents="click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave".split(" ");b(m,function(a,b){if(b.length)for(var c=0,d=b.length;c<d;c++)k[b[c]]=a});var l={propertychange:!0},p=w&&function(){for(var a=3,b=w.createElement("div"),c=b.getElementsByTagName("i");b.innerHTML="\x3c!--[if gt IE "+ ++a+"]><i></i><![endif]--\x3e",c[0];);return 4<a?a:n}(),q=/\S+/g,t;return{Jc:["authenticity_token",/^__RequestVerificationToken(_.*)?$/],
|
||||
D:function(a,b,c){for(var d=0,e=a.length;d<e;d++)b.call(c,a[d],d,a)},A:"function"==typeof Array.prototype.indexOf?function(a,b){return Array.prototype.indexOf.call(a,b)}:function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},Lb:function(a,b,c){for(var d=0,e=a.length;d<e;d++)if(b.call(c,a[d],d,a))return a[d];return n},Pa:function(b,c){var d=a.a.A(b,c);0<d?b.splice(d,1):0===d&&b.shift()},wc:function(b){var c=[];b&&a.a.D(b,function(b){0>a.a.A(c,b)&&c.push(b)});return c},Mb:function(a,
|
||||
b,c){var d=[];if(a)for(var e=0,l=a.length;e<l;e++)d.push(b.call(c,a[e],e));return d},jb:function(a,b,c){var d=[];if(a)for(var e=0,l=a.length;e<l;e++)b.call(c,a[e],e)&&d.push(a[e]);return d},Nb:function(a,b){if(b instanceof Array)a.push.apply(a,b);else for(var c=0,d=b.length;c<d;c++)a.push(b[c]);return a},Na:function(b,c,d){var e=a.a.A(a.a.bc(b),c);0>e?d&&b.push(c):d||b.splice(e,1)},Ba:g,extend:c,setPrototypeOf:d,Ab:g?d:c,P:b,Ga:function(a,b,c){if(!a)return a;var d={},e;for(e in a)f.call(a,e)&&(d[e]=
|
||||
b.call(c,a[e],e,a));return d},Tb:function(b){for(;b.firstChild;)a.removeNode(b.firstChild)},Yb:function(b){b=a.a.la(b);for(var c=(b[0]&&b[0].ownerDocument||w).createElement("div"),d=0,e=b.length;d<e;d++)c.appendChild(a.oa(b[d]));return c},Ca:function(b,c){for(var d=0,e=b.length,l=[];d<e;d++){var k=b[d].cloneNode(!0);l.push(c?a.oa(k):k)}return l},va:function(b,c){a.a.Tb(b);if(c)for(var d=0,e=c.length;d<e;d++)b.appendChild(c[d])},Xc:function(b,c){var d=b.nodeType?[b]:b;if(0<d.length){for(var e=d[0],
|
||||
l=e.parentNode,k=0,f=c.length;k<f;k++)l.insertBefore(c[k],e);k=0;for(f=d.length;k<f;k++)a.removeNode(d[k])}},Ua:function(a,b){if(a.length){for(b=8===b.nodeType&&b.parentNode||b;a.length&&a[0].parentNode!==b;)a.splice(0,1);for(;1<a.length&&a[a.length-1].parentNode!==b;)a.length--;if(1<a.length){var c=a[0],d=a[a.length-1];for(a.length=0;c!==d;)a.push(c),c=c.nextSibling;a.push(d)}}return a},Zc:function(a,b){7>p?a.setAttribute("selected",b):a.selected=b},Db:function(a){return null===a||a===n?"":a.trim?
|
||||
a.trim():a.toString().replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},Ud:function(a,b){a=a||"";return b.length>a.length?!1:a.substring(0,b.length)===b},vd:function(a,b){if(a===b)return!0;if(11===a.nodeType)return!1;if(b.contains)return b.contains(1!==a.nodeType?a.parentNode:a);if(b.compareDocumentPosition)return 16==(b.compareDocumentPosition(a)&16);for(;a&&a!=b;)a=a.parentNode;return!!a},Sb:function(b){return a.a.vd(b,b.ownerDocument.documentElement)},kd:function(b){return!!a.a.Lb(b,a.a.Sb)},R:function(a){return a&&
|
||||
a.tagName&&a.tagName.toLowerCase()},Ac:function(b){return a.onError?function(){try{return b.apply(this,arguments)}catch(c){throw a.onError&&a.onError(c),c;}}:b},setTimeout:function(b,c){return setTimeout(a.a.Ac(b),c)},Gc:function(b){setTimeout(function(){a.onError&&a.onError(b);throw b;},0)},B:function(b,c,d){var e=a.a.Ac(d);d=l[c];if(a.options.useOnlyNativeEvents||d||!v)if(d||"function"!=typeof b.addEventListener)if("undefined"!=typeof b.attachEvent){var k=function(a){e.call(b,a)},f="on"+c;b.attachEvent(f,
|
||||
k);a.a.K.za(b,function(){b.detachEvent(f,k)})}else throw Error("Browser doesn't support addEventListener or attachEvent");else b.addEventListener(c,e,!1);else t||(t="function"==typeof v(b).on?"on":"bind"),v(b)[t](c,e)},Fb:function(b,c){if(!b||!b.nodeType)throw Error("element must be a DOM node when calling triggerEvent");var d;"input"===a.a.R(b)&&b.type&&"click"==c.toLowerCase()?(d=b.type,d="checkbox"==d||"radio"==d):d=!1;if(a.options.useOnlyNativeEvents||!v||d)if("function"==typeof w.createEvent)if("function"==
|
||||
typeof b.dispatchEvent)d=w.createEvent(k[c]||"HTMLEvents"),d.initEvent(c,!0,!0,A,0,0,0,0,0,!1,!1,!1,!1,0,b),b.dispatchEvent(d);else throw Error("The supplied element doesn't support dispatchEvent");else if(d&&b.click)b.click();else if("undefined"!=typeof b.fireEvent)b.fireEvent("on"+c);else throw Error("Browser doesn't support triggering events");else v(b).trigger(c)},f:function(b){return a.O(b)?b():b},bc:function(b){return a.O(b)?b.v():b},Eb:function(b,c,d){var l;c&&("object"===typeof b.classList?
|
||||
(l=b.classList[d?"add":"remove"],a.a.D(c.match(q),function(a){l.call(b.classList,a)})):"string"===typeof b.className.baseVal?e(b.className,"baseVal",c,d):e(b,"className",c,d))},Bb:function(b,c){var d=a.a.f(c);if(null===d||d===n)d="";var e=a.h.firstChild(b);!e||3!=e.nodeType||a.h.nextSibling(e)?a.h.va(b,[b.ownerDocument.createTextNode(d)]):e.data=d;a.a.Ad(b)},Yc:function(a,b){a.name=b;if(7>=p)try{var c=a.name.replace(/[&<>'"]/g,function(a){return"&#"+a.charCodeAt(0)+";"});a.mergeAttributes(w.createElement("<input name='"+
|
||||
c+"'/>"),!1)}catch(d){}},Ad:function(a){9<=p&&(a=1==a.nodeType?a:a.parentNode,a.style&&(a.style.zoom=a.style.zoom))},wd:function(a){if(p){var b=a.style.width;a.style.width=0;a.style.width=b}},Pd:function(b,c){b=a.a.f(b);c=a.a.f(c);for(var d=[],e=b;e<=c;e++)d.push(e);return d},la:function(a){for(var b=[],c=0,d=a.length;c<d;c++)b.push(a[c]);return b},Da:function(a){return h?Symbol(a):a},Zd:6===p,$d:7===p,W:p,Lc:function(b,c){for(var d=a.a.la(b.getElementsByTagName("input")).concat(a.a.la(b.getElementsByTagName("textarea"))),
|
||||
e="string"==typeof c?function(a){return a.name===c}:function(a){return c.test(a.name)},l=[],k=d.length-1;0<=k;k--)e(d[k])&&l.push(d[k]);return l},Nd:function(b){return"string"==typeof b&&(b=a.a.Db(b))?H&&H.parse?H.parse(b):(new Function("return "+b))():null},hc:function(b,c,d){if(!H||!H.stringify)throw Error("Cannot find JSON.stringify(). Some browsers (e.g., IE < 8) don't support it natively, but you can overcome this by adding a script reference to json2.js, downloadable from http://www.json.org/json2.js");
|
||||
return H.stringify(a.a.f(b),c,d)},Od:function(c,d,e){e=e||{};var l=e.params||{},k=e.includeFields||this.Jc,f=c;if("object"==typeof c&&"form"===a.a.R(c))for(var f=c.action,h=k.length-1;0<=h;h--)for(var g=a.a.Lc(c,k[h]),m=g.length-1;0<=m;m--)l[g[m].name]=g[m].value;d=a.a.f(d);var p=w.createElement("form");p.style.display="none";p.action=f;p.method="post";for(var q in d)c=w.createElement("input"),c.type="hidden",c.name=q,c.value=a.a.hc(a.a.f(d[q])),p.appendChild(c);b(l,function(a,b){var c=w.createElement("input");
|
||||
c.type="hidden";c.name=a;c.value=b;p.appendChild(c)});w.body.appendChild(p);e.submitter?e.submitter(p):p.submit();setTimeout(function(){p.parentNode.removeChild(p)},0)}}}();a.b("utils",a.a);a.b("utils.arrayForEach",a.a.D);a.b("utils.arrayFirst",a.a.Lb);a.b("utils.arrayFilter",a.a.jb);a.b("utils.arrayGetDistinctValues",a.a.wc);a.b("utils.arrayIndexOf",a.a.A);a.b("utils.arrayMap",a.a.Mb);a.b("utils.arrayPushAll",a.a.Nb);a.b("utils.arrayRemoveItem",a.a.Pa);a.b("utils.cloneNodes",a.a.Ca);a.b("utils.createSymbolOrString",
|
||||
a.a.Da);a.b("utils.extend",a.a.extend);a.b("utils.fieldsIncludedWithJsonPost",a.a.Jc);a.b("utils.getFormFields",a.a.Lc);a.b("utils.objectMap",a.a.Ga);a.b("utils.peekObservable",a.a.bc);a.b("utils.postJson",a.a.Od);a.b("utils.parseJson",a.a.Nd);a.b("utils.registerEventHandler",a.a.B);a.b("utils.stringifyJson",a.a.hc);a.b("utils.range",a.a.Pd);a.b("utils.toggleDomNodeCssClass",a.a.Eb);a.b("utils.triggerEvent",a.a.Fb);a.b("utils.unwrapObservable",a.a.f);a.b("utils.objectForEach",a.a.P);a.b("utils.addOrRemoveItem",
|
||||
a.a.Na);a.b("utils.setTextContent",a.a.Bb);a.b("unwrap",a.a.f);Function.prototype.bind||(Function.prototype.bind=function(a){var c=this;if(1===arguments.length)return function(){return c.apply(a,arguments)};var d=Array.prototype.slice.call(arguments,1);return function(){var e=d.slice(0);e.push.apply(e,arguments);return c.apply(a,e)}});a.a.g=new function(){var b=0,c="__ko__"+(new Date).getTime(),d={},e,f;a.a.W?(e=function(a,e){var f=a[c];if(!f||"null"===f||!d[f]){if(!e)return n;f=a[c]="ko"+b++;d[f]=
|
||||
{}}return d[f]},f=function(a){var b=a[c];return b?(delete d[b],a[c]=null,!0):!1}):(e=function(a,b){var d=a[c];!d&&b&&(d=a[c]={});return d},f=function(a){return a[c]?(delete a[c],!0):!1});return{get:function(a,b){var c=e(a,!1);return c&&c[b]},set:function(a,b,c){(a=e(a,c!==n))&&(a[b]=c)},Ub:function(a,b,c){a=e(a,!0);return a[b]||(a[b]=c)},clear:f,Z:function(){return b++ +c}}};a.b("utils.domData",a.a.g);a.b("utils.domData.clear",a.a.g.clear);a.a.K=new function(){function b(b,c){var d=a.a.g.get(b,e);
|
||||
d===n&&c&&(d=[],a.a.g.set(b,e,d));return d}function c(c){var e=b(c,!1);if(e)for(var e=e.slice(0),k=0;k<e.length;k++)e[k](c);a.a.g.clear(c);a.a.K.cleanExternalData(c);g[c.nodeType]&&d(c.childNodes,!0)}function d(b,d){for(var e=[],l,f=0;f<b.length;f++)if(!d||8===b[f].nodeType)if(c(e[e.length]=l=b[f]),b[f]!==l)for(;f--&&-1==a.a.A(e,b[f]););}var e=a.a.g.Z(),f={1:!0,8:!0,9:!0},g={1:!0,9:!0};return{za:function(a,c){if("function"!=typeof c)throw Error("Callback must be a function");b(a,!0).push(c)},yb:function(c,
|
||||
d){var f=b(c,!1);f&&(a.a.Pa(f,d),0==f.length&&a.a.g.set(c,e,n))},oa:function(b){a.u.G(function(){f[b.nodeType]&&(c(b),g[b.nodeType]&&d(b.getElementsByTagName("*")))});return b},removeNode:function(b){a.oa(b);b.parentNode&&b.parentNode.removeChild(b)},cleanExternalData:function(a){v&&"function"==typeof v.cleanData&&v.cleanData([a])}}};a.oa=a.a.K.oa;a.removeNode=a.a.K.removeNode;a.b("cleanNode",a.oa);a.b("removeNode",a.removeNode);a.b("utils.domNodeDisposal",a.a.K);a.b("utils.domNodeDisposal.addDisposeCallback",
|
||||
a.a.K.za);a.b("utils.domNodeDisposal.removeDisposeCallback",a.a.K.yb);(function(){var b=[0,"",""],c=[1,"<table>","</table>"],d=[3,"<table><tbody><tr>","</tr></tbody></table>"],e=[1,"<select multiple='multiple'>","</select>"],f={thead:c,tbody:c,tfoot:c,tr:[2,"<table><tbody>","</tbody></table>"],td:d,th:d,option:e,optgroup:e},g=8>=a.a.W;a.a.ua=function(c,d){var e;if(v)if(v.parseHTML)e=v.parseHTML(c,d)||[];else{if((e=v.clean([c],d))&&e[0]){for(var l=e[0];l.parentNode&&11!==l.parentNode.nodeType;)l=l.parentNode;
|
||||
l.parentNode&&l.parentNode.removeChild(l)}}else{(e=d)||(e=w);var l=e.parentWindow||e.defaultView||A,p=a.a.Db(c).toLowerCase(),q=e.createElement("div"),t;t=(p=p.match(/^(?:\x3c!--.*?--\x3e\s*?)*?<([a-z]+)[\s>]/))&&f[p[1]]||b;p=t[0];t="ignored<div>"+t[1]+c+t[2]+"</div>";"function"==typeof l.innerShiv?q.appendChild(l.innerShiv(t)):(g&&e.body.appendChild(q),q.innerHTML=t,g&&q.parentNode.removeChild(q));for(;p--;)q=q.lastChild;e=a.a.la(q.lastChild.childNodes)}return e};a.a.Md=function(b,c){var d=a.a.ua(b,
|
||||
c);return d.length&&d[0].parentElement||a.a.Yb(d)};a.a.fc=function(b,c){a.a.Tb(b);c=a.a.f(c);if(null!==c&&c!==n)if("string"!=typeof c&&(c=c.toString()),v)v(b).html(c);else for(var d=a.a.ua(c,b.ownerDocument),e=0;e<d.length;e++)b.appendChild(d[e])}})();a.b("utils.parseHtmlFragment",a.a.ua);a.b("utils.setHtml",a.a.fc);a.aa=function(){function b(c,e){if(c)if(8==c.nodeType){var f=a.aa.Uc(c.nodeValue);null!=f&&e.push({ud:c,Kd:f})}else if(1==c.nodeType)for(var f=0,g=c.childNodes,h=g.length;f<h;f++)b(g[f],
|
||||
e)}var c={};return{Xb:function(a){if("function"!=typeof a)throw Error("You can only pass a function to ko.memoization.memoize()");var b=(4294967296*(1+Math.random())|0).toString(16).substring(1)+(4294967296*(1+Math.random())|0).toString(16).substring(1);c[b]=a;return"\x3c!--[ko_memo:"+b+"]--\x3e"},bd:function(a,b){var f=c[a];if(f===n)throw Error("Couldn't find any memo with ID "+a+". Perhaps it's already been unmemoized.");try{return f.apply(null,b||[]),!0}finally{delete c[a]}},cd:function(c,e){var f=
|
||||
[];b(c,f);for(var g=0,h=f.length;g<h;g++){var m=f[g].ud,k=[m];e&&a.a.Nb(k,e);a.aa.bd(f[g].Kd,k);m.nodeValue="";m.parentNode&&m.parentNode.removeChild(m)}},Uc:function(a){return(a=a.match(/^\[ko_memo\:(.*?)\]$/))?a[1]:null}}}();a.b("memoization",a.aa);a.b("memoization.memoize",a.aa.Xb);a.b("memoization.unmemoize",a.aa.bd);a.b("memoization.parseMemoText",a.aa.Uc);a.b("memoization.unmemoizeDomNodeAndDescendants",a.aa.cd);a.na=function(){function b(){if(f)for(var b=f,c=0,d;h<f;)if(d=e[h++]){if(h>b){if(5E3<=
|
||||
++c){h=f;a.a.Gc(Error("'Too much recursion' after processing "+c+" task groups."));break}b=f}try{d()}catch(p){a.a.Gc(p)}}}function c(){b();h=f=e.length=0}var d,e=[],f=0,g=1,h=0;A.MutationObserver?d=function(a){var b=w.createElement("div");(new MutationObserver(a)).observe(b,{attributes:!0});return function(){b.classList.toggle("foo")}}(c):d=w&&"onreadystatechange"in w.createElement("script")?function(a){var b=w.createElement("script");b.onreadystatechange=function(){b.onreadystatechange=null;w.documentElement.removeChild(b);
|
||||
b=null;a()};w.documentElement.appendChild(b)}:function(a){setTimeout(a,0)};return{scheduler:d,zb:function(b){f||a.na.scheduler(c);e[f++]=b;return g++},cancel:function(a){a=a-(g-f);a>=h&&a<f&&(e[a]=null)},resetForTesting:function(){var a=f-h;h=f=e.length=0;return a},Sd:b}}();a.b("tasks",a.na);a.b("tasks.schedule",a.na.zb);a.b("tasks.runEarly",a.na.Sd);a.Ta={throttle:function(b,c){b.throttleEvaluation=c;var d=null;return a.$({read:b,write:function(e){clearTimeout(d);d=a.a.setTimeout(function(){b(e)},
|
||||
c)}})},rateLimit:function(a,c){var d,e,f;"number"==typeof c?d=c:(d=c.timeout,e=c.method);a.Hb=!1;f="function"==typeof e?e:"notifyWhenChangesStop"==e?Y:X;a.ub(function(a){return f(a,d,c)})},deferred:function(b,c){if(!0!==c)throw Error("The 'deferred' extender only accepts the value 'true', because it is not supported to turn deferral off once enabled.");b.Hb||(b.Hb=!0,b.ub(function(c){var e,f=!1;return function(){if(!f){a.na.cancel(e);e=a.na.zb(c);try{f=!0,b.notifySubscribers(n,"dirty")}finally{f=
|
||||
!1}}}}))},notify:function(a,c){a.equalityComparer="always"==c?null:K}};var W={undefined:1,"boolean":1,number:1,string:1};a.b("extenders",a.Ta);a.ic=function(b,c,d){this.da=b;this.lc=c;this.mc=d;this.Ib=!1;this.fb=this.Jb=null;a.L(this,"dispose",this.s);a.L(this,"disposeWhenNodeIsRemoved",this.l)};a.ic.prototype.s=function(){this.Ib||(this.fb&&a.a.K.yb(this.Jb,this.fb),this.Ib=!0,this.mc(),this.da=this.lc=this.mc=this.Jb=this.fb=null)};a.ic.prototype.l=function(b){this.Jb=b;a.a.K.za(b,this.fb=this.s.bind(this))};
|
||||
a.T=function(){a.a.Ab(this,D);D.qb(this)};var D={qb:function(a){a.U={change:[]};a.sc=1},subscribe:function(b,c,d){var e=this;d=d||"change";var f=new a.ic(e,c?b.bind(c):b,function(){a.a.Pa(e.U[d],f);e.hb&&e.hb(d)});e.Qa&&e.Qa(d);e.U[d]||(e.U[d]=[]);e.U[d].push(f);return f},notifySubscribers:function(b,c){c=c||"change";"change"===c&&this.Gb();if(this.Wa(c)){var d="change"===c&&this.ed||this.U[c].slice(0);try{a.u.xc();for(var e=0,f;f=d[e];++e)f.Ib||f.lc(b)}finally{a.u.end()}}},ob:function(){return this.sc},
|
||||
Dd:function(a){return this.ob()!==a},Gb:function(){++this.sc},ub:function(b){var c=this,d=a.O(c),e,f,g,h,m;c.gb||(c.gb=c.notifySubscribers,c.notifySubscribers=Z);var k=b(function(){c.Ja=!1;d&&h===c&&(h=c.nc?c.nc():c());var a=f||m&&c.sb(g,h);m=f=e=!1;a&&c.gb(g=h)});c.qc=function(a,b){b&&c.Ja||(m=!b);c.ed=c.U.change.slice(0);c.Ja=e=!0;h=a;k()};c.pc=function(a){e||(g=a,c.gb(a,"beforeChange"))};c.rc=function(){m=!0};c.gd=function(){c.sb(g,c.v(!0))&&(f=!0)}},Wa:function(a){return this.U[a]&&this.U[a].length},
|
||||
Bd:function(b){if(b)return this.U[b]&&this.U[b].length||0;var c=0;a.a.P(this.U,function(a,b){"dirty"!==a&&(c+=b.length)});return c},sb:function(a,c){return!this.equalityComparer||!this.equalityComparer(a,c)},toString:function(){return"[object Object]"},extend:function(b){var c=this;b&&a.a.P(b,function(b,e){var f=a.Ta[b];"function"==typeof f&&(c=f(c,e)||c)});return c}};a.L(D,"init",D.qb);a.L(D,"subscribe",D.subscribe);a.L(D,"extend",D.extend);a.L(D,"getSubscriptionsCount",D.Bd);a.a.Ba&&a.a.setPrototypeOf(D,
|
||||
Function.prototype);a.T.fn=D;a.Qc=function(a){return null!=a&&"function"==typeof a.subscribe&&"function"==typeof a.notifySubscribers};a.b("subscribable",a.T);a.b("isSubscribable",a.Qc);a.S=a.u=function(){function b(a){d.push(e);e=a}function c(){e=d.pop()}var d=[],e,f=0;return{xc:b,end:c,cc:function(b){if(e){if(!a.Qc(b))throw Error("Only subscribable things can act as dependencies");e.od.call(e.pd,b,b.fd||(b.fd=++f))}},G:function(a,d,e){try{return b(),a.apply(d,e||[])}finally{c()}},qa:function(){if(e)return e.o.qa()},
|
||||
Va:function(){if(e)return e.o.Va()},Ya:function(){if(e)return e.Ya},o:function(){if(e)return e.o}}}();a.b("computedContext",a.S);a.b("computedContext.getDependenciesCount",a.S.qa);a.b("computedContext.getDependencies",a.S.Va);a.b("computedContext.isInitial",a.S.Ya);a.b("computedContext.registerDependency",a.S.cc);a.b("ignoreDependencies",a.Yd=a.u.G);var I=a.a.Da("_latestValue");a.ta=function(b){function c(){if(0<arguments.length)return c.sb(c[I],arguments[0])&&(c.ya(),c[I]=arguments[0],c.xa()),this;
|
||||
a.u.cc(c);return c[I]}c[I]=b;a.a.Ba||a.a.extend(c,a.T.fn);a.T.fn.qb(c);a.a.Ab(c,F);a.options.deferUpdates&&a.Ta.deferred(c,!0);return c};var F={equalityComparer:K,v:function(){return this[I]},xa:function(){this.notifySubscribers(this[I],"spectate");this.notifySubscribers(this[I])},ya:function(){this.notifySubscribers(this[I],"beforeChange")}};a.a.Ba&&a.a.setPrototypeOf(F,a.T.fn);var G=a.ta.Ma="__ko_proto__";F[G]=a.ta;a.O=function(b){if((b="function"==typeof b&&b[G])&&b!==F[G]&&b!==a.o.fn[G])throw Error("Invalid object that looks like an observable; possibly from another Knockout instance");
|
||||
return!!b};a.Za=function(b){return"function"==typeof b&&(b[G]===F[G]||b[G]===a.o.fn[G]&&b.Nc)};a.b("observable",a.ta);a.b("isObservable",a.O);a.b("isWriteableObservable",a.Za);a.b("isWritableObservable",a.Za);a.b("observable.fn",F);a.L(F,"peek",F.v);a.L(F,"valueHasMutated",F.xa);a.L(F,"valueWillMutate",F.ya);a.Ha=function(b){b=b||[];if("object"!=typeof b||!("length"in b))throw Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");b=a.ta(b);a.a.Ab(b,
|
||||
a.Ha.fn);return b.extend({trackArrayChanges:!0})};a.Ha.fn={remove:function(b){for(var c=this.v(),d=[],e="function"!=typeof b||a.O(b)?function(a){return a===b}:b,f=0;f<c.length;f++){var g=c[f];if(e(g)){0===d.length&&this.ya();if(c[f]!==g)throw Error("Array modified during remove; cannot remove item");d.push(g);c.splice(f,1);f--}}d.length&&this.xa();return d},removeAll:function(b){if(b===n){var c=this.v(),d=c.slice(0);this.ya();c.splice(0,c.length);this.xa();return d}return b?this.remove(function(c){return 0<=
|
||||
a.a.A(b,c)}):[]},destroy:function(b){var c=this.v(),d="function"!=typeof b||a.O(b)?function(a){return a===b}:b;this.ya();for(var e=c.length-1;0<=e;e--){var f=c[e];d(f)&&(f._destroy=!0)}this.xa()},destroyAll:function(b){return b===n?this.destroy(function(){return!0}):b?this.destroy(function(c){return 0<=a.a.A(b,c)}):[]},indexOf:function(b){var c=this();return a.a.A(c,b)},replace:function(a,c){var d=this.indexOf(a);0<=d&&(this.ya(),this.v()[d]=c,this.xa())},sorted:function(a){var c=this().slice(0);
|
||||
return a?c.sort(a):c.sort()},reversed:function(){return this().slice(0).reverse()}};a.a.Ba&&a.a.setPrototypeOf(a.Ha.fn,a.ta.fn);a.a.D("pop push reverse shift sort splice unshift".split(" "),function(b){a.Ha.fn[b]=function(){var a=this.v();this.ya();this.zc(a,b,arguments);var d=a[b].apply(a,arguments);this.xa();return d===a?this:d}});a.a.D(["slice"],function(b){a.Ha.fn[b]=function(){var a=this();return a[b].apply(a,arguments)}});a.Pc=function(b){return a.O(b)&&"function"==typeof b.remove&&"function"==
|
||||
typeof b.push};a.b("observableArray",a.Ha);a.b("isObservableArray",a.Pc);a.Ta.trackArrayChanges=function(b,c){function d(){function c(){if(m){var d=[].concat(b.v()||[]),e;if(b.Wa("arrayChange")){if(!f||1<m)f=a.a.Pb(k,d,b.Ob);e=f}k=d;f=null;m=0;e&&e.length&&b.notifySubscribers(e,"arrayChange")}}e?c():(e=!0,h=b.subscribe(function(){++m},null,"spectate"),k=[].concat(b.v()||[]),f=null,g=b.subscribe(c))}b.Ob={};c&&"object"==typeof c&&a.a.extend(b.Ob,c);b.Ob.sparse=!0;if(!b.zc){var e=!1,f=null,g,h,m=0,
|
||||
k,l=b.Qa,p=b.hb;b.Qa=function(a){l&&l.call(b,a);"arrayChange"===a&&d()};b.hb=function(a){p&&p.call(b,a);"arrayChange"!==a||b.Wa("arrayChange")||(g&&g.s(),h&&h.s(),h=g=null,e=!1,k=n)};b.zc=function(b,c,d){function l(a,b,c){return k[k.length]={status:a,value:b,index:c}}if(e&&!m){var k=[],p=b.length,g=d.length,h=0;switch(c){case "push":h=p;case "unshift":for(c=0;c<g;c++)l("added",d[c],h+c);break;case "pop":h=p-1;case "shift":p&&l("deleted",b[h],h);break;case "splice":c=Math.min(Math.max(0,0>d[0]?p+d[0]:
|
||||
d[0]),p);for(var p=1===g?p:Math.min(c+(d[1]||0),p),g=c+g-2,h=Math.max(p,g),U=[],L=[],n=2;c<h;++c,++n)c<p&&L.push(l("deleted",b[c],c)),c<g&&U.push(l("added",d[n],c));a.a.Kc(L,U);break;default:return}f=k}}}};var r=a.a.Da("_state");a.o=a.$=function(b,c,d){function e(){if(0<arguments.length){if("function"===typeof f)f.apply(g.nb,arguments);else throw Error("Cannot write a value to a ko.computed unless you specify a 'write' option. If you wish to read the current value, don't pass any parameters.");return this}g.ra||
|
||||
a.u.cc(e);(g.ka||g.J&&e.Xa())&&e.ha();return g.X}"object"===typeof b?d=b:(d=d||{},b&&(d.read=b));if("function"!=typeof d.read)throw Error("Pass a function that returns the value of the ko.computed");var f=d.write,g={X:n,sa:!0,ka:!0,rb:!1,jc:!1,ra:!1,wb:!1,J:!1,Wc:d.read,nb:c||d.owner,l:d.disposeWhenNodeIsRemoved||d.l||null,Sa:d.disposeWhen||d.Sa,Rb:null,I:{},V:0,Ic:null};e[r]=g;e.Nc="function"===typeof f;a.a.Ba||a.a.extend(e,a.T.fn);a.T.fn.qb(e);a.a.Ab(e,C);d.pure?(g.wb=!0,g.J=!0,a.a.extend(e,da)):
|
||||
d.deferEvaluation&&a.a.extend(e,ea);a.options.deferUpdates&&a.Ta.deferred(e,!0);g.l&&(g.jc=!0,g.l.nodeType||(g.l=null));g.J||d.deferEvaluation||e.ha();g.l&&e.ja()&&a.a.K.za(g.l,g.Rb=function(){e.s()});return e};var C={equalityComparer:K,qa:function(){return this[r].V},Va:function(){var b=[];a.a.P(this[r].I,function(a,d){b[d.Ka]=d.da});return b},Vb:function(b){if(!this[r].V)return!1;var c=this.Va();return-1!==a.a.A(c,b)?!0:!!a.a.Lb(c,function(a){return a.Vb&&a.Vb(b)})},uc:function(a,c,d){if(this[r].wb&&
|
||||
c===this)throw Error("A 'pure' computed must not be called recursively");this[r].I[a]=d;d.Ka=this[r].V++;d.La=c.ob()},Xa:function(){var a,c,d=this[r].I;for(a in d)if(Object.prototype.hasOwnProperty.call(d,a)&&(c=d[a],this.Ia&&c.da.Ja||c.da.Dd(c.La)))return!0},Jd:function(){this.Ia&&!this[r].rb&&this.Ia(!1)},ja:function(){var a=this[r];return a.ka||0<a.V},Rd:function(){this.Ja?this[r].ka&&(this[r].sa=!0):this.Hc()},$c:function(a){if(a.Hb){var c=a.subscribe(this.Jd,this,"dirty"),d=a.subscribe(this.Rd,
|
||||
this);return{da:a,s:function(){c.s();d.s()}}}return a.subscribe(this.Hc,this)},Hc:function(){var b=this,c=b.throttleEvaluation;c&&0<=c?(clearTimeout(this[r].Ic),this[r].Ic=a.a.setTimeout(function(){b.ha(!0)},c)):b.Ia?b.Ia(!0):b.ha(!0)},ha:function(b){var c=this[r],d=c.Sa,e=!1;if(!c.rb&&!c.ra){if(c.l&&!a.a.Sb(c.l)||d&&d()){if(!c.jc){this.s();return}}else c.jc=!1;c.rb=!0;try{e=this.zd(b)}finally{c.rb=!1}return e}},zd:function(b){var c=this[r],d=!1,e=c.wb?n:!c.V,d={qd:this,mb:c.I,Qb:c.V};a.u.xc({pd:d,
|
||||
od:ba,o:this,Ya:e});c.I={};c.V=0;var f=this.yd(c,d);c.V?d=this.sb(c.X,f):(this.s(),d=!0);d&&(c.J?this.Gb():this.notifySubscribers(c.X,"beforeChange"),c.X=f,this.notifySubscribers(c.X,"spectate"),!c.J&&b&&this.notifySubscribers(c.X),this.rc&&this.rc());e&&this.notifySubscribers(c.X,"awake");return d},yd:function(b,c){try{var d=b.Wc;return b.nb?d.call(b.nb):d()}finally{a.u.end(),c.Qb&&!b.J&&a.a.P(c.mb,aa),b.sa=b.ka=!1}},v:function(a){var c=this[r];(c.ka&&(a||!c.V)||c.J&&this.Xa())&&this.ha();return c.X},
|
||||
ub:function(b){a.T.fn.ub.call(this,b);this.nc=function(){this[r].J||(this[r].sa?this.ha():this[r].ka=!1);return this[r].X};this.Ia=function(a){this.pc(this[r].X);this[r].ka=!0;a&&(this[r].sa=!0);this.qc(this,!a)}},s:function(){var b=this[r];!b.J&&b.I&&a.a.P(b.I,function(a,b){b.s&&b.s()});b.l&&b.Rb&&a.a.K.yb(b.l,b.Rb);b.I=n;b.V=0;b.ra=!0;b.sa=!1;b.ka=!1;b.J=!1;b.l=n;b.Sa=n;b.Wc=n;this.Nc||(b.nb=n)}},da={Qa:function(b){var c=this,d=c[r];if(!d.ra&&d.J&&"change"==b){d.J=!1;if(d.sa||c.Xa())d.I=null,d.V=
|
||||
0,c.ha()&&c.Gb();else{var e=[];a.a.P(d.I,function(a,b){e[b.Ka]=a});a.a.D(e,function(a,b){var e=d.I[a],m=c.$c(e.da);m.Ka=b;m.La=e.La;d.I[a]=m});c.Xa()&&c.ha()&&c.Gb()}d.ra||c.notifySubscribers(d.X,"awake")}},hb:function(b){var c=this[r];c.ra||"change"!=b||this.Wa("change")||(a.a.P(c.I,function(a,b){b.s&&(c.I[a]={da:b.da,Ka:b.Ka,La:b.La},b.s())}),c.J=!0,this.notifySubscribers(n,"asleep"))},ob:function(){var b=this[r];b.J&&(b.sa||this.Xa())&&this.ha();return a.T.fn.ob.call(this)}},ea={Qa:function(a){"change"!=
|
||||
a&&"beforeChange"!=a||this.v()}};a.a.Ba&&a.a.setPrototypeOf(C,a.T.fn);var N=a.ta.Ma;C[N]=a.o;a.Oc=function(a){return"function"==typeof a&&a[N]===C[N]};a.Fd=function(b){return a.Oc(b)&&b[r]&&b[r].wb};a.b("computed",a.o);a.b("dependentObservable",a.o);a.b("isComputed",a.Oc);a.b("isPureComputed",a.Fd);a.b("computed.fn",C);a.L(C,"peek",C.v);a.L(C,"dispose",C.s);a.L(C,"isActive",C.ja);a.L(C,"getDependenciesCount",C.qa);a.L(C,"getDependencies",C.Va);a.xb=function(b,c){if("function"===typeof b)return a.o(b,
|
||||
c,{pure:!0});b=a.a.extend({},b);b.pure=!0;return a.o(b,c)};a.b("pureComputed",a.xb);(function(){function b(a,f,g){g=g||new d;a=f(a);if("object"!=typeof a||null===a||a===n||a instanceof RegExp||a instanceof Date||a instanceof String||a instanceof Number||a instanceof Boolean)return a;var h=a instanceof Array?[]:{};g.save(a,h);c(a,function(c){var d=f(a[c]);switch(typeof d){case "boolean":case "number":case "string":case "function":h[c]=d;break;case "object":case "undefined":var l=g.get(d);h[c]=l!==
|
||||
n?l:b(d,f,g)}});return h}function c(a,b){if(a instanceof Array){for(var c=0;c<a.length;c++)b(c);"function"==typeof a.toJSON&&b("toJSON")}else for(c in a)b(c)}function d(){this.keys=[];this.values=[]}a.ad=function(c){if(0==arguments.length)throw Error("When calling ko.toJS, pass the object you want to convert.");return b(c,function(b){for(var c=0;a.O(b)&&10>c;c++)b=b();return b})};a.toJSON=function(b,c,d){b=a.ad(b);return a.a.hc(b,c,d)};d.prototype={constructor:d,save:function(b,c){var d=a.a.A(this.keys,
|
||||
b);0<=d?this.values[d]=c:(this.keys.push(b),this.values.push(c))},get:function(b){b=a.a.A(this.keys,b);return 0<=b?this.values[b]:n}}})();a.b("toJS",a.ad);a.b("toJSON",a.toJSON);a.Wd=function(b,c,d){function e(c){var e=a.xb(b,d).extend({ma:"always"}),h=e.subscribe(function(a){a&&(h.s(),c(a))});e.notifySubscribers(e.v());return h}return"function"!==typeof Promise||c?e(c.bind(d)):new Promise(e)};a.b("when",a.Wd);(function(){a.w={M:function(b){switch(a.a.R(b)){case "option":return!0===b.__ko__hasDomDataOptionValue__?
|
||||
a.a.g.get(b,a.c.options.$b):7>=a.a.W?b.getAttributeNode("value")&&b.getAttributeNode("value").specified?b.value:b.text:b.value;case "select":return 0<=b.selectedIndex?a.w.M(b.options[b.selectedIndex]):n;default:return b.value}},cb:function(b,c,d){switch(a.a.R(b)){case "option":"string"===typeof c?(a.a.g.set(b,a.c.options.$b,n),"__ko__hasDomDataOptionValue__"in b&&delete b.__ko__hasDomDataOptionValue__,b.value=c):(a.a.g.set(b,a.c.options.$b,c),b.__ko__hasDomDataOptionValue__=!0,b.value="number"===
|
||||
typeof c?c:"");break;case "select":if(""===c||null===c)c=n;for(var e=-1,f=0,g=b.options.length,h;f<g;++f)if(h=a.w.M(b.options[f]),h==c||""===h&&c===n){e=f;break}if(d||0<=e||c===n&&1<b.size)b.selectedIndex=e,6===a.a.W&&a.a.setTimeout(function(){b.selectedIndex=e},0);break;default:if(null===c||c===n)c="";b.value=c}}}})();a.b("selectExtensions",a.w);a.b("selectExtensions.readValue",a.w.M);a.b("selectExtensions.writeValue",a.w.cb);a.m=function(){function b(b){b=a.a.Db(b);123===b.charCodeAt(0)&&(b=b.slice(1,
|
||||
-1));b+="\n,";var c=[],d=b.match(e),p,q=[],h=0;if(1<d.length){for(var x=0,B;B=d[x];++x){var u=B.charCodeAt(0);if(44===u){if(0>=h){c.push(p&&q.length?{key:p,value:q.join("")}:{unknown:p||q.join("")});p=h=0;q=[];continue}}else if(58===u){if(!h&&!p&&1===q.length){p=q.pop();continue}}else if(47===u&&1<B.length&&(47===B.charCodeAt(1)||42===B.charCodeAt(1)))continue;else 47===u&&x&&1<B.length?(u=d[x-1].match(f))&&!g[u[0]]&&(b=b.substr(b.indexOf(B)+1),d=b.match(e),x=-1,B="/"):40===u||123===u||91===u?++h:
|
||||
41===u||125===u||93===u?--h:p||q.length||34!==u&&39!==u||(B=B.slice(1,-1));q.push(B)}if(0<h)throw Error("Unbalanced parentheses, braces, or brackets");}return c}var c=["true","false","null","undefined"],d=/^(?:[$_a-z][$\w]*|(.+)(\.\s*[$_a-z][$\w]*|\[.+\]))$/i,e=RegExp("\"(?:\\\\.|[^\"])*\"|'(?:\\\\.|[^'])*'|`(?:\\\\.|[^`])*`|/\\*(?:[^*]|\\*+[^*/])*\\*+/|//.*\n|/(?:\\\\.|[^/])+/w*|[^\\s:,/][^,\"'`{}()/:[\\]]*[^\\s,\"'`{}()/:[\\]]|[^\\s]","g"),f=/[\])"'A-Za-z0-9_$]+$/,g={"in":1,"return":1,"typeof":1},
|
||||
h={};return{Ra:[],wa:h,ac:b,vb:function(e,f){function l(b,e){var f;if(!x){var k=a.getBindingHandler(b);if(k&&k.preprocess&&!(e=k.preprocess(e,b,l)))return;if(k=h[b])f=e,0<=a.a.A(c,f)?f=!1:(k=f.match(d),f=null===k?!1:k[1]?"Object("+k[1]+")"+k[2]:f),k=f;k&&q.push("'"+("string"==typeof h[b]?h[b]:b)+"':function(_z){"+f+"=_z}")}g&&(e="function(){return "+e+" }");p.push("'"+b+"':"+e)}f=f||{};var p=[],q=[],g=f.valueAccessors,x=f.bindingParams,B="string"===typeof e?b(e):e;a.a.D(B,function(a){l(a.key||a.unknown,
|
||||
a.value)});q.length&&l("_ko_property_writers","{"+q.join(",")+" }");return p.join(",")},Id:function(a,b){for(var c=0;c<a.length;c++)if(a[c].key==b)return!0;return!1},eb:function(b,c,d,e,f){if(b&&a.O(b))!a.Za(b)||f&&b.v()===e||b(e);else if((b=c.get("_ko_property_writers"))&&b[d])b[d](e)}}}();a.b("expressionRewriting",a.m);a.b("expressionRewriting.bindingRewriteValidators",a.m.Ra);a.b("expressionRewriting.parseObjectLiteral",a.m.ac);a.b("expressionRewriting.preProcessBindings",a.m.vb);a.b("expressionRewriting._twoWayBindings",
|
||||
a.m.wa);a.b("jsonExpressionRewriting",a.m);a.b("jsonExpressionRewriting.insertPropertyAccessorsIntoJson",a.m.vb);(function(){function b(a){return 8==a.nodeType&&g.test(f?a.text:a.nodeValue)}function c(a){return 8==a.nodeType&&h.test(f?a.text:a.nodeValue)}function d(d,e){for(var f=d,h=1,g=[];f=f.nextSibling;){if(c(f)&&(a.a.g.set(f,k,!0),h--,0===h))return g;g.push(f);b(f)&&h++}if(!e)throw Error("Cannot find closing comment tag to match: "+d.nodeValue);return null}function e(a,b){var c=d(a,b);return c?
|
||||
0<c.length?c[c.length-1].nextSibling:a.nextSibling:null}var f=w&&"\x3c!--test--\x3e"===w.createComment("test").text,g=f?/^\x3c!--\s*ko(?:\s+([\s\S]+))?\s*--\x3e$/:/^\s*ko(?:\s+([\s\S]+))?\s*$/,h=f?/^\x3c!--\s*\/ko\s*--\x3e$/:/^\s*\/ko\s*$/,m={ul:!0,ol:!0},k="__ko_matchedEndComment__";a.h={ea:{},childNodes:function(a){return b(a)?d(a):a.childNodes},Ea:function(c){if(b(c)){c=a.h.childNodes(c);for(var d=0,e=c.length;d<e;d++)a.removeNode(c[d])}else a.a.Tb(c)},va:function(c,d){if(b(c)){a.h.Ea(c);for(var e=
|
||||
c.nextSibling,f=0,k=d.length;f<k;f++)e.parentNode.insertBefore(d[f],e)}else a.a.va(c,d)},Vc:function(a,c){var d;b(a)?(d=a.nextSibling,a=a.parentNode):d=a.firstChild;d?c!==d&&a.insertBefore(c,d):a.appendChild(c)},Wb:function(c,d,e){e?(e=e.nextSibling,b(c)&&(c=c.parentNode),e?d!==e&&c.insertBefore(d,e):c.appendChild(d)):a.h.Vc(c,d)},firstChild:function(a){if(b(a))return!a.nextSibling||c(a.nextSibling)?null:a.nextSibling;if(a.firstChild&&c(a.firstChild))throw Error("Found invalid end comment, as the first child of "+
|
||||
a);return a.firstChild},nextSibling:function(d){b(d)&&(d=e(d));if(d.nextSibling&&c(d.nextSibling)){var f=d.nextSibling;if(c(f)&&!a.a.g.get(f,k))throw Error("Found end comment without a matching opening comment, as child of "+d);return null}return d.nextSibling},Cd:b,Vd:function(a){return(a=(f?a.text:a.nodeValue).match(g))?a[1]:null},Sc:function(d){if(m[a.a.R(d)]){var f=d.firstChild;if(f){do if(1===f.nodeType){var k;k=f.firstChild;var h=null;if(k){do if(h)h.push(k);else if(b(k)){var g=e(k,!0);g?k=
|
||||
g:h=[k]}else c(k)&&(h=[k]);while(k=k.nextSibling)}if(k=h)for(h=f.nextSibling,g=0;g<k.length;g++)h?d.insertBefore(k[g],h):d.appendChild(k[g])}while(f=f.nextSibling)}}}}})();a.b("virtualElements",a.h);a.b("virtualElements.allowedBindings",a.h.ea);a.b("virtualElements.emptyNode",a.h.Ea);a.b("virtualElements.insertAfter",a.h.Wb);a.b("virtualElements.prepend",a.h.Vc);a.b("virtualElements.setDomNodeChildren",a.h.va);(function(){a.ga=function(){this.nd={}};a.a.extend(a.ga.prototype,{nodeHasBindings:function(b){switch(b.nodeType){case 1:return null!=
|
||||
b.getAttribute("data-bind")||a.j.getComponentNameForNode(b);case 8:return a.h.Cd(b);default:return!1}},getBindings:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b):null;return a.j.tc(d,b,c,!1)},getBindingAccessors:function(b,c){var d=this.getBindingsString(b,c),d=d?this.parseBindingsString(d,c,b,{valueAccessors:!0}):null;return a.j.tc(d,b,c,!0)},getBindingsString:function(b){switch(b.nodeType){case 1:return b.getAttribute("data-bind");case 8:return a.h.Vd(b);default:return null}},
|
||||
parseBindingsString:function(b,c,d,e){try{var f=this.nd,g=b+(e&&e.valueAccessors||""),h;if(!(h=f[g])){var m,k="with($context){with($data||{}){return{"+a.m.vb(b,e)+"}}}";m=new Function("$context","$element",k);h=f[g]=m}return h(c,d)}catch(l){throw l.message="Unable to parse bindings.\nBindings value: "+b+"\nMessage: "+l.message,l;}}});a.ga.instance=new a.ga})();a.b("bindingProvider",a.ga);(function(){function b(b){var c=(b=a.a.g.get(b,z))&&b.N;c&&(b.N=null,c.Tc())}function c(c,d,e){this.node=c;this.yc=
|
||||
d;this.kb=[];this.H=!1;d.N||a.a.K.za(c,b);e&&e.N&&(e.N.kb.push(c),this.Kb=e)}function d(a){return function(){return a}}function e(a){return a()}function f(b){return a.a.Ga(a.u.G(b),function(a,c){return function(){return b()[c]}})}function g(b,c,e){return"function"===typeof b?f(b.bind(null,c,e)):a.a.Ga(b,d)}function h(a,b){return f(this.getBindings.bind(this,a,b))}function m(b,c){var d=a.h.firstChild(c);if(d){var e,f=a.ga.instance,l=f.preprocessNode;if(l){for(;e=d;)d=a.h.nextSibling(e),l.call(f,e);
|
||||
d=a.h.firstChild(c)}for(;e=d;)d=a.h.nextSibling(e),k(b,e)}a.i.ma(c,a.i.H)}function k(b,c){var d=b,e=1===c.nodeType;e&&a.h.Sc(c);if(e||a.ga.instance.nodeHasBindings(c))d=p(c,null,b).bindingContextForDescendants;d&&!u[a.a.R(c)]&&m(d,c)}function l(b){var c=[],d={},e=[];a.a.P(b,function ca(f){if(!d[f]){var k=a.getBindingHandler(f);k&&(k.after&&(e.push(f),a.a.D(k.after,function(c){if(b[c]){if(-1!==a.a.A(e,c))throw Error("Cannot combine the following bindings, because they have a cyclic dependency: "+e.join(", "));
|
||||
ca(c)}}),e.length--),c.push({key:f,Mc:k}));d[f]=!0}});return c}function p(b,c,d){var f=a.a.g.Ub(b,z,{}),k=f.hd;if(!c){if(k)throw Error("You cannot apply bindings multiple times to the same element.");f.hd=!0}k||(f.context=d);f.Zb||(f.Zb={});var g;if(c&&"function"!==typeof c)g=c;else{var p=a.ga.instance,q=p.getBindingAccessors||h,m=a.$(function(){if(g=c?c(d,b):q.call(p,b,d)){if(d[t])d[t]();if(d[B])d[B]()}return g},null,{l:b});g&&m.ja()||(m=null)}var x=d,u;if(g){var J=function(){return a.a.Ga(m?m():
|
||||
g,e)},r=m?function(a){return function(){return e(m()[a])}}:function(a){return g[a]};J.get=function(a){return g[a]&&e(r(a))};J.has=function(a){return a in g};a.i.H in g&&a.i.subscribe(b,a.i.H,function(){var c=(0,g[a.i.H])();if(c){var d=a.h.childNodes(b);d.length&&c(d,a.Ec(d[0]))}});a.i.pa in g&&(x=a.i.Cb(b,d),a.i.subscribe(b,a.i.pa,function(){var c=(0,g[a.i.pa])();c&&a.h.firstChild(b)&&c(b)}));f=l(g);a.a.D(f,function(c){var d=c.Mc.init,e=c.Mc.update,f=c.key;if(8===b.nodeType&&!a.h.ea[f])throw Error("The binding '"+
|
||||
f+"' cannot be used with virtual elements");try{"function"==typeof d&&a.u.G(function(){var a=d(b,r(f),J,x.$data,x);if(a&&a.controlsDescendantBindings){if(u!==n)throw Error("Multiple bindings ("+u+" and "+f+") are trying to control descendant bindings of the same element. You cannot use these bindings together on the same element.");u=f}}),"function"==typeof e&&a.$(function(){e(b,r(f),J,x.$data,x)},null,{l:b})}catch(k){throw k.message='Unable to process binding "'+f+": "+g[f]+'"\nMessage: '+k.message,
|
||||
k;}})}f=u===n;return{shouldBindDescendants:f,bindingContextForDescendants:f&&x}}function q(b,c){return b&&b instanceof a.fa?b:new a.fa(b,n,n,c)}var t=a.a.Da("_subscribable"),x=a.a.Da("_ancestorBindingInfo"),B=a.a.Da("_dataDependency");a.c={};var u={script:!0,textarea:!0,template:!0};a.getBindingHandler=function(b){return a.c[b]};var J={};a.fa=function(b,c,d,e,f){function k(){var b=p?h():h,f=a.a.f(b);c?(a.a.extend(l,c),x in c&&(l[x]=c[x])):(l.$parents=[],l.$root=f,l.ko=a);l[t]=q;g?f=l.$data:(l.$rawData=
|
||||
b,l.$data=f);d&&(l[d]=f);e&&e(l,c,f);if(c&&c[t]&&!a.S.o().Vb(c[t]))c[t]();m&&(l[B]=m);return l.$data}var l=this,g=b===J,h=g?n:b,p="function"==typeof h&&!a.O(h),q,m=f&&f.dataDependency;f&&f.exportDependencies?k():(q=a.xb(k),q.v(),q.ja()?q.equalityComparer=null:l[t]=n)};a.fa.prototype.createChildContext=function(b,c,d,e){!e&&c&&"object"==typeof c&&(e=c,c=e.as,d=e.extend);if(c&&e&&e.noChildContext){var f="function"==typeof b&&!a.O(b);return new a.fa(J,this,null,function(a){d&&d(a);a[c]=f?b():b},e)}return new a.fa(b,
|
||||
this,c,function(a,b){a.$parentContext=b;a.$parent=b.$data;a.$parents=(b.$parents||[]).slice(0);a.$parents.unshift(a.$parent);d&&d(a)},e)};a.fa.prototype.extend=function(b,c){return new a.fa(J,this,null,function(c){a.a.extend(c,"function"==typeof b?b(c):b)},c)};var z=a.a.g.Z();c.prototype.Tc=function(){this.Kb&&this.Kb.N&&this.Kb.N.sd(this.node)};c.prototype.sd=function(b){a.a.Pa(this.kb,b);!this.kb.length&&this.H&&this.Cc()};c.prototype.Cc=function(){this.H=!0;this.yc.N&&!this.kb.length&&(this.yc.N=
|
||||
null,a.a.K.yb(this.node,b),a.i.ma(this.node,a.i.pa),this.Tc())};a.i={H:"childrenComplete",pa:"descendantsComplete",subscribe:function(b,c,d,e,f){var k=a.a.g.Ub(b,z,{});k.Fa||(k.Fa=new a.T);f&&f.notifyImmediately&&k.Zb[c]&&a.u.G(d,e,[b]);return k.Fa.subscribe(d,e,c)},ma:function(b,c){var d=a.a.g.get(b,z);if(d&&(d.Zb[c]=!0,d.Fa&&d.Fa.notifySubscribers(b,c),c==a.i.H))if(d.N)d.N.Cc();else if(d.N===n&&d.Fa&&d.Fa.Wa(a.i.pa))throw Error("descendantsComplete event not supported for bindings on this node");
|
||||
},Cb:function(b,d){var e=a.a.g.Ub(b,z,{});e.N||(e.N=new c(b,e,d[x]));return d[x]==e?d:d.extend(function(a){a[x]=e})}};a.Td=function(b){return(b=a.a.g.get(b,z))&&b.context};a.ib=function(b,c,d){1===b.nodeType&&a.h.Sc(b);return p(b,c,q(d))};a.ld=function(b,c,d){d=q(d);return a.ib(b,g(c,d,b),d)};a.Oa=function(a,b){1!==b.nodeType&&8!==b.nodeType||m(q(a),b)};a.vc=function(a,b,c){!v&&A.jQuery&&(v=A.jQuery);if(2>arguments.length){if(b=w.body,!b)throw Error("ko.applyBindings: could not find document.body; has the document been loaded?");
|
||||
}else if(!b||1!==b.nodeType&&8!==b.nodeType)throw Error("ko.applyBindings: first parameter should be your view model; second parameter should be a DOM node");k(q(a,c),b)};a.Dc=function(b){return!b||1!==b.nodeType&&8!==b.nodeType?n:a.Td(b)};a.Ec=function(b){return(b=a.Dc(b))?b.$data:n};a.b("bindingHandlers",a.c);a.b("bindingEvent",a.i);a.b("bindingEvent.subscribe",a.i.subscribe);a.b("bindingEvent.startPossiblyAsyncContentBinding",a.i.Cb);a.b("applyBindings",a.vc);a.b("applyBindingsToDescendants",a.Oa);
|
||||
a.b("applyBindingAccessorsToNode",a.ib);a.b("applyBindingsToNode",a.ld);a.b("contextFor",a.Dc);a.b("dataFor",a.Ec)})();(function(b){function c(c,e){var k=Object.prototype.hasOwnProperty.call(f,c)?f[c]:b,l;k?k.subscribe(e):(k=f[c]=new a.T,k.subscribe(e),d(c,function(b,d){var e=!(!d||!d.synchronous);g[c]={definition:b,Gd:e};delete f[c];l||e?k.notifySubscribers(b):a.na.zb(function(){k.notifySubscribers(b)})}),l=!0)}function d(a,b){e("getConfig",[a],function(c){c?e("loadComponent",[a,c],function(a){b(a,
|
||||
c)}):b(null,null)})}function e(c,d,f,l){l||(l=a.j.loaders.slice(0));var g=l.shift();if(g){var q=g[c];if(q){var t=!1;if(q.apply(g,d.concat(function(a){t?f(null):null!==a?f(a):e(c,d,f,l)}))!==b&&(t=!0,!g.suppressLoaderExceptions))throw Error("Component loaders must supply values by invoking the callback, not by returning values synchronously.");}else e(c,d,f,l)}else f(null)}var f={},g={};a.j={get:function(d,e){var f=Object.prototype.hasOwnProperty.call(g,d)?g[d]:b;f?f.Gd?a.u.G(function(){e(f.definition)}):
|
||||
a.na.zb(function(){e(f.definition)}):c(d,e)},Bc:function(a){delete g[a]},oc:e};a.j.loaders=[];a.b("components",a.j);a.b("components.get",a.j.get);a.b("components.clearCachedDefinition",a.j.Bc)})();(function(){function b(b,c,d,e){function g(){0===--B&&e(h)}var h={},B=2,u=d.template;d=d.viewModel;u?f(c,u,function(c){a.j.oc("loadTemplate",[b,c],function(a){h.template=a;g()})}):g();d?f(c,d,function(c){a.j.oc("loadViewModel",[b,c],function(a){h[m]=a;g()})}):g()}function c(a,b,d){if("function"===typeof b)d(function(a){return new b(a)});
|
||||
else if("function"===typeof b[m])d(b[m]);else if("instance"in b){var e=b.instance;d(function(){return e})}else"viewModel"in b?c(a,b.viewModel,d):a("Unknown viewModel value: "+b)}function d(b){switch(a.a.R(b)){case "script":return a.a.ua(b.text);case "textarea":return a.a.ua(b.value);case "template":if(e(b.content))return a.a.Ca(b.content.childNodes)}return a.a.Ca(b.childNodes)}function e(a){return A.DocumentFragment?a instanceof DocumentFragment:a&&11===a.nodeType}function f(a,b,c){"string"===typeof b.require?
|
||||
T||A.require?(T||A.require)([b.require],function(a){a&&"object"===typeof a&&a.Xd&&a["default"]&&(a=a["default"]);c(a)}):a("Uses require, but no AMD loader is present"):c(b)}function g(a){return function(b){throw Error("Component '"+a+"': "+b);}}var h={};a.j.register=function(b,c){if(!c)throw Error("Invalid configuration for "+b);if(a.j.tb(b))throw Error("Component "+b+" is already registered");h[b]=c};a.j.tb=function(a){return Object.prototype.hasOwnProperty.call(h,a)};a.j.unregister=function(b){delete h[b];
|
||||
a.j.Bc(b)};a.j.Fc={getConfig:function(b,c){c(a.j.tb(b)?h[b]:null)},loadComponent:function(a,c,d){var e=g(a);f(e,c,function(c){b(a,e,c,d)})},loadTemplate:function(b,c,f){b=g(b);if("string"===typeof c)f(a.a.ua(c));else if(c instanceof Array)f(c);else if(e(c))f(a.a.la(c.childNodes));else if(c.element)if(c=c.element,A.HTMLElement?c instanceof HTMLElement:c&&c.tagName&&1===c.nodeType)f(d(c));else if("string"===typeof c){var h=w.getElementById(c);h?f(d(h)):b("Cannot find element with ID "+c)}else b("Unknown element type: "+
|
||||
c);else b("Unknown template value: "+c)},loadViewModel:function(a,b,d){c(g(a),b,d)}};var m="createViewModel";a.b("components.register",a.j.register);a.b("components.isRegistered",a.j.tb);a.b("components.unregister",a.j.unregister);a.b("components.defaultLoader",a.j.Fc);a.j.loaders.push(a.j.Fc);a.j.dd=h})();(function(){function b(b,e){var f=b.getAttribute("params");if(f){var f=c.parseBindingsString(f,e,b,{valueAccessors:!0,bindingParams:!0}),f=a.a.Ga(f,function(c){return a.o(c,null,{l:b})}),g=a.a.Ga(f,
|
||||
function(c){var e=c.v();return c.ja()?a.o({read:function(){return a.a.f(c())},write:a.Za(e)&&function(a){c()(a)},l:b}):e});Object.prototype.hasOwnProperty.call(g,"$raw")||(g.$raw=f);return g}return{$raw:{}}}a.j.getComponentNameForNode=function(b){var c=a.a.R(b);if(a.j.tb(c)&&(-1!=c.indexOf("-")||"[object HTMLUnknownElement]"==""+b||8>=a.a.W&&b.tagName===c))return c};a.j.tc=function(c,e,f,g){if(1===e.nodeType){var h=a.j.getComponentNameForNode(e);if(h){c=c||{};if(c.component)throw Error('Cannot use the "component" binding on a custom element matching a component');
|
||||
var m={name:h,params:b(e,f)};c.component=g?function(){return m}:m}}return c};var c=new a.ga;9>a.a.W&&(a.j.register=function(a){return function(b){return a.apply(this,arguments)}}(a.j.register),w.createDocumentFragment=function(b){return function(){var c=b(),f=a.j.dd,g;for(g in f);return c}}(w.createDocumentFragment))})();(function(){function b(b,c,d){c=c.template;if(!c)throw Error("Component '"+b+"' has no template");b=a.a.Ca(c);a.h.va(d,b)}function c(a,b,c){var d=a.createViewModel;return d?d.call(a,
|
||||
b,c):b}var d=0;a.c.component={init:function(e,f,g,h,m){function k(){var a=l&&l.dispose;"function"===typeof a&&a.call(l);q&&q.s();p=l=q=null}var l,p,q,t=a.a.la(a.h.childNodes(e));a.h.Ea(e);a.a.K.za(e,k);a.o(function(){var g=a.a.f(f()),h,u;"string"===typeof g?h=g:(h=a.a.f(g.name),u=a.a.f(g.params));if(!h)throw Error("No component name specified");var n=a.i.Cb(e,m),z=p=++d;a.j.get(h,function(d){if(p===z){k();if(!d)throw Error("Unknown component '"+h+"'");b(h,d,e);var f=c(d,u,{element:e,templateNodes:t});
|
||||
d=n.createChildContext(f,{extend:function(a){a.$component=f;a.$componentTemplateNodes=t}});f&&f.koDescendantsComplete&&(q=a.i.subscribe(e,a.i.pa,f.koDescendantsComplete,f));l=f;a.Oa(d,e)}})},null,{l:e});return{controlsDescendantBindings:!0}}};a.h.ea.component=!0})();var V={"class":"className","for":"htmlFor"};a.c.attr={update:function(b,c){var d=a.a.f(c())||{};a.a.P(d,function(c,d){d=a.a.f(d);var g=c.indexOf(":"),g="lookupNamespaceURI"in b&&0<g&&b.lookupNamespaceURI(c.substr(0,g)),h=!1===d||null===
|
||||
d||d===n;h?g?b.removeAttributeNS(g,c):b.removeAttribute(c):d=d.toString();8>=a.a.W&&c in V?(c=V[c],h?b.removeAttribute(c):b[c]=d):h||(g?b.setAttributeNS(g,c,d):b.setAttribute(c,d));"name"===c&&a.a.Yc(b,h?"":d)})}};(function(){a.c.checked={after:["value","attr"],init:function(b,c,d){function e(){var e=b.checked,f=g();if(!a.S.Ya()&&(e||!m&&!a.S.qa())){var k=a.u.G(c);if(l){var q=p?k.v():k,z=t;t=f;z!==f?e&&(a.a.Na(q,f,!0),a.a.Na(q,z,!1)):a.a.Na(q,f,e);p&&a.Za(k)&&k(q)}else h&&(f===n?f=e:e||(f=n)),a.m.eb(k,
|
||||
d,"checked",f,!0)}}function f(){var d=a.a.f(c()),e=g();l?(b.checked=0<=a.a.A(d,e),t=e):b.checked=h&&e===n?!!d:g()===d}var g=a.xb(function(){if(d.has("checkedValue"))return a.a.f(d.get("checkedValue"));if(q)return d.has("value")?a.a.f(d.get("value")):b.value}),h="checkbox"==b.type,m="radio"==b.type;if(h||m){var k=c(),l=h&&a.a.f(k)instanceof Array,p=!(l&&k.push&&k.splice),q=m||l,t=l?g():n;m&&!b.name&&a.c.uniqueName.init(b,function(){return!0});a.o(e,null,{l:b});a.a.B(b,"click",e);a.o(f,null,{l:b});
|
||||
k=n}}};a.m.wa.checked=!0;a.c.checkedValue={update:function(b,c){b.value=a.a.f(c())}}})();a.c["class"]={update:function(b,c){var d=a.a.Db(a.a.f(c()));a.a.Eb(b,b.__ko__cssValue,!1);b.__ko__cssValue=d;a.a.Eb(b,d,!0)}};a.c.css={update:function(b,c){var d=a.a.f(c());null!==d&&"object"==typeof d?a.a.P(d,function(c,d){d=a.a.f(d);a.a.Eb(b,c,d)}):a.c["class"].update(b,c)}};a.c.enable={update:function(b,c){var d=a.a.f(c());d&&b.disabled?b.removeAttribute("disabled"):d||b.disabled||(b.disabled=!0)}};a.c.disable=
|
||||
{update:function(b,c){a.c.enable.update(b,function(){return!a.a.f(c())})}};a.c.event={init:function(b,c,d,e,f){var g=c()||{};a.a.P(g,function(g){"string"==typeof g&&a.a.B(b,g,function(b){var k,l=c()[g];if(l){try{var p=a.a.la(arguments);e=f.$data;p.unshift(e);k=l.apply(e,p)}finally{!0!==k&&(b.preventDefault?b.preventDefault():b.returnValue=!1)}!1===d.get(g+"Bubble")&&(b.cancelBubble=!0,b.stopPropagation&&b.stopPropagation())}})})}};a.c.foreach={Rc:function(b){return function(){var c=b(),d=a.a.bc(c);
|
||||
if(!d||"number"==typeof d.length)return{foreach:c,templateEngine:a.ba.Ma};a.a.f(c);return{foreach:d.data,as:d.as,noChildContext:d.noChildContext,includeDestroyed:d.includeDestroyed,afterAdd:d.afterAdd,beforeRemove:d.beforeRemove,afterRender:d.afterRender,beforeMove:d.beforeMove,afterMove:d.afterMove,templateEngine:a.ba.Ma}}},init:function(b,c){return a.c.template.init(b,a.c.foreach.Rc(c))},update:function(b,c,d,e,f){return a.c.template.update(b,a.c.foreach.Rc(c),d,e,f)}};a.m.Ra.foreach=!1;a.h.ea.foreach=
|
||||
!0;a.c.hasfocus={init:function(b,c,d){function e(e){b.__ko_hasfocusUpdating=!0;var f=b.ownerDocument;if("activeElement"in f){var g;try{g=f.activeElement}catch(l){g=f.body}e=g===b}f=c();a.m.eb(f,d,"hasfocus",e,!0);b.__ko_hasfocusLastValue=e;b.__ko_hasfocusUpdating=!1}var f=e.bind(null,!0),g=e.bind(null,!1);a.a.B(b,"focus",f);a.a.B(b,"focusin",f);a.a.B(b,"blur",g);a.a.B(b,"focusout",g);b.__ko_hasfocusLastValue=!1},update:function(b,c){var d=!!a.a.f(c());b.__ko_hasfocusUpdating||b.__ko_hasfocusLastValue===
|
||||
d||(d?b.focus():b.blur(),!d&&b.__ko_hasfocusLastValue&&b.ownerDocument.body.focus(),a.u.G(a.a.Fb,null,[b,d?"focusin":"focusout"]))}};a.m.wa.hasfocus=!0;a.c.hasFocus=a.c.hasfocus;a.m.wa.hasFocus="hasfocus";a.c.html={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.fc(b,c())}};(function(){function b(b,d,e){a.c[b]={init:function(b,c,h,m,k){var l,p,q={},t,x,n;if(d){m=h.get("as");var u=h.get("noChildContext");n=!(m&&u);q={as:m,noChildContext:u,exportDependencies:n}}x=(t=
|
||||
"render"==h.get("completeOn"))||h.has(a.i.pa);a.o(function(){var h=a.a.f(c()),m=!e!==!h,u=!p,r;if(n||m!==l){x&&(k=a.i.Cb(b,k));if(m){if(!d||n)q.dataDependency=a.S.o();r=d?k.createChildContext("function"==typeof h?h:c,q):a.S.qa()?k.extend(null,q):k}u&&a.S.qa()&&(p=a.a.Ca(a.h.childNodes(b),!0));m?(u||a.h.va(b,a.a.Ca(p)),a.Oa(r,b)):(a.h.Ea(b),t||a.i.ma(b,a.i.H));l=m}},null,{l:b});return{controlsDescendantBindings:!0}}};a.m.Ra[b]=!1;a.h.ea[b]=!0}b("if");b("ifnot",!1,!0);b("with",!0)})();a.c.let={init:function(b,
|
||||
c,d,e,f){c=f.extend(c);a.Oa(c,b);return{controlsDescendantBindings:!0}}};a.h.ea.let=!0;var Q={};a.c.options={init:function(b){if("select"!==a.a.R(b))throw Error("options binding applies only to SELECT elements");for(;0<b.length;)b.remove(0);return{controlsDescendantBindings:!0}},update:function(b,c,d){function e(){return a.a.jb(b.options,function(a){return a.selected})}function f(a,b,c){var d=typeof b;return"function"==d?b(a):"string"==d?a[b]:c}function g(c,d){if(x&&l)a.i.ma(b,a.i.H);else if(t.length){var e=
|
||||
0<=a.a.A(t,a.w.M(d[0]));a.a.Zc(d[0],e);x&&!e&&a.u.G(a.a.Fb,null,[b,"change"])}}var h=b.multiple,m=0!=b.length&&h?b.scrollTop:null,k=a.a.f(c()),l=d.get("valueAllowUnset")&&d.has("value"),p=d.get("optionsIncludeDestroyed");c={};var q,t=[];l||(h?t=a.a.Mb(e(),a.w.M):0<=b.selectedIndex&&t.push(a.w.M(b.options[b.selectedIndex])));k&&("undefined"==typeof k.length&&(k=[k]),q=a.a.jb(k,function(b){return p||b===n||null===b||!a.a.f(b._destroy)}),d.has("optionsCaption")&&(k=a.a.f(d.get("optionsCaption")),null!==
|
||||
k&&k!==n&&q.unshift(Q)));var x=!1;c.beforeRemove=function(a){b.removeChild(a)};k=g;d.has("optionsAfterRender")&&"function"==typeof d.get("optionsAfterRender")&&(k=function(b,c){g(0,c);a.u.G(d.get("optionsAfterRender"),null,[c[0],b!==Q?b:n])});a.a.ec(b,q,function(c,e,g){g.length&&(t=!l&&g[0].selected?[a.w.M(g[0])]:[],x=!0);e=b.ownerDocument.createElement("option");c===Q?(a.a.Bb(e,d.get("optionsCaption")),a.w.cb(e,n)):(g=f(c,d.get("optionsValue"),c),a.w.cb(e,a.a.f(g)),c=f(c,d.get("optionsText"),g),
|
||||
a.a.Bb(e,c));return[e]},c,k);if(!l){var B;h?B=t.length&&e().length<t.length:B=t.length&&0<=b.selectedIndex?a.w.M(b.options[b.selectedIndex])!==t[0]:t.length||0<=b.selectedIndex;B&&a.u.G(a.a.Fb,null,[b,"change"])}(l||a.S.Ya())&&a.i.ma(b,a.i.H);a.a.wd(b);m&&20<Math.abs(m-b.scrollTop)&&(b.scrollTop=m)}};a.c.options.$b=a.a.g.Z();a.c.selectedOptions={init:function(b,c,d){function e(){var e=c(),f=[];a.a.D(b.getElementsByTagName("option"),function(b){b.selected&&f.push(a.w.M(b))});a.m.eb(e,d,"selectedOptions",
|
||||
f)}function f(){var d=a.a.f(c()),e=b.scrollTop;d&&"number"==typeof d.length&&a.a.D(b.getElementsByTagName("option"),function(b){var c=0<=a.a.A(d,a.w.M(b));b.selected!=c&&a.a.Zc(b,c)});b.scrollTop=e}if("select"!=a.a.R(b))throw Error("selectedOptions binding applies only to SELECT elements");var g;a.i.subscribe(b,a.i.H,function(){g?e():(a.a.B(b,"change",e),g=a.o(f,null,{l:b}))},null,{notifyImmediately:!0})},update:function(){}};a.m.wa.selectedOptions=!0;a.c.style={update:function(b,c){var d=a.a.f(c()||
|
||||
{});a.a.P(d,function(c,d){d=a.a.f(d);if(null===d||d===n||!1===d)d="";if(v)v(b).css(c,d);else if(/^--/.test(c))b.style.setProperty(c,d);else{c=c.replace(/-(\w)/g,function(a,b){return b.toUpperCase()});var g=b.style[c];b.style[c]=d;d===g||b.style[c]!=g||isNaN(d)||(b.style[c]=d+"px")}})}};a.c.submit={init:function(b,c,d,e,f){if("function"!=typeof c())throw Error("The value for a submit binding must be a function");a.a.B(b,"submit",function(a){var d,e=c();try{d=e.call(f.$data,b)}finally{!0!==d&&(a.preventDefault?
|
||||
a.preventDefault():a.returnValue=!1)}})}};a.c.text={init:function(){return{controlsDescendantBindings:!0}},update:function(b,c){a.a.Bb(b,c())}};a.h.ea.text=!0;(function(){if(A&&A.navigator){var b=function(a){if(a)return parseFloat(a[1])},c=A.navigator.userAgent,d,e,f,g,h;(d=A.opera&&A.opera.version&&parseInt(A.opera.version()))||(h=b(c.match(/Edge\/([^ ]+)$/)))||b(c.match(/Chrome\/([^ ]+)/))||(e=b(c.match(/Version\/([^ ]+) Safari/)))||(f=b(c.match(/Firefox\/([^ ]+)/)))||(g=a.a.W||b(c.match(/MSIE ([^ ]+)/)))||
|
||||
(g=b(c.match(/rv:([^ )]+)/)))}if(8<=g&&10>g)var m=a.a.g.Z(),k=a.a.g.Z(),l=function(b){var c=this.activeElement;(c=c&&a.a.g.get(c,k))&&c(b)},p=function(b,c){var d=b.ownerDocument;a.a.g.get(d,m)||(a.a.g.set(d,m,!0),a.a.B(d,"selectionchange",l));a.a.g.set(b,k,c)};a.c.textInput={init:function(b,c,k){function l(c,d){a.a.B(b,c,d)}function m(){var d=a.a.f(c());if(null===d||d===n)d="";L!==n&&d===L?a.a.setTimeout(m,4):b.value!==d&&(y=!0,b.value=d,y=!1,v=b.value)}function r(){w||(L=b.value,w=a.a.setTimeout(z,
|
||||
4))}function z(){clearTimeout(w);L=w=n;var d=b.value;v!==d&&(v=d,a.m.eb(c(),k,"textInput",d))}var v=b.value,w,L,A=9==a.a.W?r:z,y=!1;g&&l("keypress",z);11>g&&l("propertychange",function(a){y||"value"!==a.propertyName||A(a)});8==g&&(l("keyup",z),l("keydown",z));p&&(p(b,A),l("dragend",r));(!g||9<=g)&&l("input",A);5>e&&"textarea"===a.a.R(b)?(l("keydown",r),l("paste",r),l("cut",r)):11>d?l("keydown",r):4>f?(l("DOMAutoComplete",z),l("dragdrop",z),l("drop",z)):h&&"number"===b.type&&l("keydown",r);l("change",
|
||||
z);l("blur",z);a.o(m,null,{l:b})}};a.m.wa.textInput=!0;a.c.textinput={preprocess:function(a,b,c){c("textInput",a)}}})();a.c.uniqueName={init:function(b,c){if(c()){var d="ko_unique_"+ ++a.c.uniqueName.rd;a.a.Yc(b,d)}}};a.c.uniqueName.rd=0;a.c.using={init:function(b,c,d,e,f){var g;d.has("as")&&(g={as:d.get("as"),noChildContext:d.get("noChildContext")});c=f.createChildContext(c,g);a.Oa(c,b);return{controlsDescendantBindings:!0}}};a.h.ea.using=!0;a.c.value={init:function(b,c,d){var e=a.a.R(b),f="input"==
|
||||
e;if(!f||"checkbox"!=b.type&&"radio"!=b.type){var g=[],h=d.get("valueUpdate"),m=!1,k=null;h&&("string"==typeof h?g=[h]:g=a.a.wc(h),a.a.Pa(g,"change"));var l=function(){k=null;m=!1;var e=c(),f=a.w.M(b);a.m.eb(e,d,"value",f)};!a.a.W||!f||"text"!=b.type||"off"==b.autocomplete||b.form&&"off"==b.form.autocomplete||-1!=a.a.A(g,"propertychange")||(a.a.B(b,"propertychange",function(){m=!0}),a.a.B(b,"focus",function(){m=!1}),a.a.B(b,"blur",function(){m&&l()}));a.a.D(g,function(c){var d=l;a.a.Ud(c,"after")&&
|
||||
(d=function(){k=a.w.M(b);a.a.setTimeout(l,0)},c=c.substring(5));a.a.B(b,c,d)});var p;p=f&&"file"==b.type?function(){var d=a.a.f(c());null===d||d===n||""===d?b.value="":a.u.G(l)}:function(){var f=a.a.f(c()),g=a.w.M(b);if(null!==k&&f===k)a.a.setTimeout(p,0);else if(f!==g||g===n)"select"===e?(g=d.get("valueAllowUnset"),a.w.cb(b,f,g),g||f===a.w.M(b)||a.u.G(l)):a.w.cb(b,f)};if("select"===e){var q;a.i.subscribe(b,a.i.H,function(){q?d.get("valueAllowUnset")?p():l():(a.a.B(b,"change",l),q=a.o(p,null,{l:b}))},
|
||||
null,{notifyImmediately:!0})}else a.a.B(b,"change",l),a.o(p,null,{l:b})}else a.ib(b,{checkedValue:c})},update:function(){}};a.m.wa.value=!0;a.c.visible={update:function(b,c){var d=a.a.f(c()),e="none"!=b.style.display;d&&!e?b.style.display="":!d&&e&&(b.style.display="none")}};a.c.hidden={update:function(b,c){a.c.visible.update(b,function(){return!a.a.f(c())})}};(function(b){a.c[b]={init:function(c,d,e,f,g){return a.c.event.init.call(this,c,function(){var a={};a[b]=d();return a},e,f,g)}}})("click");
|
||||
a.ca=function(){};a.ca.prototype.renderTemplateSource=function(){throw Error("Override renderTemplateSource");};a.ca.prototype.createJavaScriptEvaluatorBlock=function(){throw Error("Override createJavaScriptEvaluatorBlock");};a.ca.prototype.makeTemplateSource=function(b,c){if("string"==typeof b){c=c||w;var d=c.getElementById(b);if(!d)throw Error("Cannot find template with ID "+b);return new a.C.F(d)}if(1==b.nodeType||8==b.nodeType)return new a.C.ia(b);throw Error("Unknown template type: "+b);};a.ca.prototype.renderTemplate=
|
||||
function(a,c,d,e){a=this.makeTemplateSource(a,e);return this.renderTemplateSource(a,c,d,e)};a.ca.prototype.isTemplateRewritten=function(a,c){return!1===this.allowTemplateRewriting?!0:this.makeTemplateSource(a,c).data("isRewritten")};a.ca.prototype.rewriteTemplate=function(a,c,d){a=this.makeTemplateSource(a,d);c=c(a.text());a.text(c);a.data("isRewritten",!0)};a.b("templateEngine",a.ca);a.kc=function(){function b(b,c,d,h){b=a.m.ac(b);for(var m=a.m.Ra,k=0;k<b.length;k++){var l=b[k].key;if(Object.prototype.hasOwnProperty.call(m,
|
||||
l)){var p=m[l];if("function"===typeof p){if(l=p(b[k].value))throw Error(l);}else if(!p)throw Error("This template engine does not support the '"+l+"' binding within its templates");}}d="ko.__tr_ambtns(function($context,$element){return(function(){return{ "+a.m.vb(b,{valueAccessors:!0})+" } })()},'"+d.toLowerCase()+"')";return h.createJavaScriptEvaluatorBlock(d)+c}var c=/(<([a-z]+\d*)(?:\s+(?!data-bind\s*=\s*)[a-z0-9\-]+(?:=(?:\"[^\"]*\"|\'[^\']*\'|[^>]*))?)*\s+)data-bind\s*=\s*(["'])([\s\S]*?)\3/gi,
|
||||
d=/\x3c!--\s*ko\b\s*([\s\S]*?)\s*--\x3e/g;return{xd:function(b,c,d){c.isTemplateRewritten(b,d)||c.rewriteTemplate(b,function(b){return a.kc.Ld(b,c)},d)},Ld:function(a,f){return a.replace(c,function(a,c,d,e,l){return b(l,c,d,f)}).replace(d,function(a,c){return b(c,"\x3c!-- ko --\x3e","#comment",f)})},md:function(b,c){return a.aa.Xb(function(d,h){var m=d.nextSibling;m&&m.nodeName.toLowerCase()===c&&a.ib(m,b,h)})}}}();a.b("__tr_ambtns",a.kc.md);(function(){a.C={};a.C.F=function(b){if(this.F=b){var c=
|
||||
a.a.R(b);this.ab="script"===c?1:"textarea"===c?2:"template"==c&&b.content&&11===b.content.nodeType?3:4}};a.C.F.prototype.text=function(){var b=1===this.ab?"text":2===this.ab?"value":"innerHTML";if(0==arguments.length)return this.F[b];var c=arguments[0];"innerHTML"===b?a.a.fc(this.F,c):this.F[b]=c};var b=a.a.g.Z()+"_";a.C.F.prototype.data=function(c){if(1===arguments.length)return a.a.g.get(this.F,b+c);a.a.g.set(this.F,b+c,arguments[1])};var c=a.a.g.Z();a.C.F.prototype.nodes=function(){var b=this.F;
|
||||
if(0==arguments.length){var e=a.a.g.get(b,c)||{},f=e.lb||(3===this.ab?b.content:4===this.ab?b:n);if(!f||e.jd){var g=this.text();g&&g!==e.bb&&(f=a.a.Md(g,b.ownerDocument),a.a.g.set(b,c,{lb:f,bb:g,jd:!0}))}return f}e=arguments[0];this.ab!==n&&this.text("");a.a.g.set(b,c,{lb:e})};a.C.ia=function(a){this.F=a};a.C.ia.prototype=new a.C.F;a.C.ia.prototype.constructor=a.C.ia;a.C.ia.prototype.text=function(){if(0==arguments.length){var b=a.a.g.get(this.F,c)||{};b.bb===n&&b.lb&&(b.bb=b.lb.innerHTML);return b.bb}a.a.g.set(this.F,
|
||||
c,{bb:arguments[0]})};a.b("templateSources",a.C);a.b("templateSources.domElement",a.C.F);a.b("templateSources.anonymousTemplate",a.C.ia)})();(function(){function b(b,c,d){var e;for(c=a.h.nextSibling(c);b&&(e=b)!==c;)b=a.h.nextSibling(e),d(e,b)}function c(c,d){if(c.length){var e=c[0],f=c[c.length-1],g=e.parentNode,h=a.ga.instance,m=h.preprocessNode;if(m){b(e,f,function(a,b){var c=a.previousSibling,d=m.call(h,a);d&&(a===e&&(e=d[0]||b),a===f&&(f=d[d.length-1]||c))});c.length=0;if(!e)return;e===f?c.push(e):
|
||||
(c.push(e,f),a.a.Ua(c,g))}b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.vc(d,b)});b(e,f,function(b){1!==b.nodeType&&8!==b.nodeType||a.aa.cd(b,[d])});a.a.Ua(c,g)}}function d(a){return a.nodeType?a:0<a.length?a[0]:null}function e(b,e,f,h,m){m=m||{};var n=(b&&d(b)||f||{}).ownerDocument,B=m.templateEngine||g;a.kc.xd(f,B,n);f=B.renderTemplate(f,h,m,n);if("number"!=typeof f.length||0<f.length&&"number"!=typeof f[0].nodeType)throw Error("Template engine must return an array of DOM nodes");n=!1;switch(e){case "replaceChildren":a.h.va(b,
|
||||
f);n=!0;break;case "replaceNode":a.a.Xc(b,f);n=!0;break;case "ignoreTargetNode":break;default:throw Error("Unknown renderMode: "+e);}n&&(c(f,h),m.afterRender&&a.u.G(m.afterRender,null,[f,h[m.as||"$data"]]),"replaceChildren"==e&&a.i.ma(b,a.i.H));return f}function f(b,c,d){return a.O(b)?b():"function"===typeof b?b(c,d):b}var g;a.gc=function(b){if(b!=n&&!(b instanceof a.ca))throw Error("templateEngine must inherit from ko.templateEngine");g=b};a.dc=function(b,c,h,m,t){h=h||{};if((h.templateEngine||g)==
|
||||
n)throw Error("Set a template engine before calling renderTemplate");t=t||"replaceChildren";if(m){var x=d(m);return a.$(function(){var g=c&&c instanceof a.fa?c:new a.fa(c,null,null,null,{exportDependencies:!0}),n=f(b,g.$data,g),g=e(m,t,n,g,h);"replaceNode"==t&&(m=g,x=d(m))},null,{Sa:function(){return!x||!a.a.Sb(x)},l:x&&"replaceNode"==t?x.parentNode:x})}return a.aa.Xb(function(d){a.dc(b,c,h,d,"replaceNode")})};a.Qd=function(b,d,g,h,m){function x(b,c){a.u.G(a.a.ec,null,[h,b,u,g,r,c]);a.i.ma(h,a.i.H)}
|
||||
function r(a,b){c(b,v);g.afterRender&&g.afterRender(b,a);v=null}function u(a,c){v=m.createChildContext(a,{as:z,noChildContext:g.noChildContext,extend:function(a){a.$index=c;z&&(a[z+"Index"]=c)}});var d=f(b,a,v);return e(h,"ignoreTargetNode",d,v,g)}var v,z=g.as,w=!1===g.includeDestroyed||a.options.foreachHidesDestroyed&&!g.includeDestroyed;if(w||g.beforeRemove||!a.Pc(d))return a.$(function(){var b=a.a.f(d)||[];"undefined"==typeof b.length&&(b=[b]);w&&(b=a.a.jb(b,function(b){return b===n||null===b||
|
||||
!a.a.f(b._destroy)}));x(b)},null,{l:h});x(d.v());var A=d.subscribe(function(a){x(d(),a)},null,"arrayChange");A.l(h);return A};var h=a.a.g.Z(),m=a.a.g.Z();a.c.template={init:function(b,c){var d=a.a.f(c());if("string"==typeof d||"name"in d)a.h.Ea(b);else if("nodes"in d){d=d.nodes||[];if(a.O(d))throw Error('The "nodes" option must be a plain, non-observable array.');var e=d[0]&&d[0].parentNode;e&&a.a.g.get(e,m)||(e=a.a.Yb(d),a.a.g.set(e,m,!0));(new a.C.ia(b)).nodes(e)}else if(d=a.h.childNodes(b),0<d.length)e=
|
||||
a.a.Yb(d),(new a.C.ia(b)).nodes(e);else throw Error("Anonymous template defined, but no template content was provided");return{controlsDescendantBindings:!0}},update:function(b,c,d,e,f){var g=c();c=a.a.f(g);d=!0;e=null;"string"==typeof c?c={}:(g="name"in c?c.name:b,"if"in c&&(d=a.a.f(c["if"])),d&&"ifnot"in c&&(d=!a.a.f(c.ifnot)),d&&!g&&(d=!1));"foreach"in c?e=a.Qd(g,d&&c.foreach||[],c,b,f):d?(d=f,"data"in c&&(d=f.createChildContext(c.data,{as:c.as,noChildContext:c.noChildContext,exportDependencies:!0})),
|
||||
e=a.dc(g,d,c,b)):a.h.Ea(b);f=e;(c=a.a.g.get(b,h))&&"function"==typeof c.s&&c.s();a.a.g.set(b,h,!f||f.ja&&!f.ja()?n:f)}};a.m.Ra.template=function(b){b=a.m.ac(b);return 1==b.length&&b[0].unknown||a.m.Id(b,"name")?null:"This template engine does not support anonymous templates nested within its templates"};a.h.ea.template=!0})();a.b("setTemplateEngine",a.gc);a.b("renderTemplate",a.dc);a.a.Kc=function(a,c,d){if(a.length&&c.length){var e,f,g,h,m;for(e=f=0;(!d||e<d)&&(h=a[f]);++f){for(g=0;m=c[g];++g)if(h.value===
|
||||
m.value){h.moved=m.index;m.moved=h.index;c.splice(g,1);e=g=0;break}e+=g}}};a.a.Pb=function(){function b(b,d,e,f,g){var h=Math.min,m=Math.max,k=[],l,p=b.length,q,n=d.length,r=n-p||1,v=p+n+1,u,w,z;for(l=0;l<=p;l++)for(w=u,k.push(u=[]),z=h(n,l+r),q=m(0,l-1);q<=z;q++)u[q]=q?l?b[l-1]===d[q-1]?w[q-1]:h(w[q]||v,u[q-1]||v)+1:q+1:l+1;h=[];m=[];r=[];l=p;for(q=n;l||q;)n=k[l][q]-1,q&&n===k[l][q-1]?m.push(h[h.length]={status:e,value:d[--q],index:q}):l&&n===k[l-1][q]?r.push(h[h.length]={status:f,value:b[--l],index:l}):
|
||||
(--q,--l,g.sparse||h.push({status:"retained",value:d[q]}));a.a.Kc(r,m,!g.dontLimitMoves&&10*p);return h.reverse()}return function(a,d,e){e="boolean"===typeof e?{dontLimitMoves:e}:e||{};a=a||[];d=d||[];return a.length<d.length?b(a,d,"added","deleted",e):b(d,a,"deleted","added",e)}}();a.b("utils.compareArrays",a.a.Pb);(function(){function b(b,c,d,h,m){var k=[],l=a.$(function(){var l=c(d,m,a.a.Ua(k,b))||[];0<k.length&&(a.a.Xc(k,l),h&&a.u.G(h,null,[d,l,m]));k.length=0;a.a.Nb(k,l)},null,{l:b,Sa:function(){return!a.a.kd(k)}});
|
||||
return{Y:k,$:l.ja()?l:n}}var c=a.a.g.Z(),d=a.a.g.Z();a.a.ec=function(e,f,g,h,m,k){function l(b){y={Aa:b,pb:a.ta(w++)};v.push(y);r||F.push(y)}function p(b){y=t[b];w!==y.pb.v()&&D.push(y);y.pb(w++);a.a.Ua(y.Y,e);v.push(y)}function q(b,c){if(b)for(var d=0,e=c.length;d<e;d++)a.a.D(c[d].Y,function(a){b(a,d,c[d].Aa)})}f=f||[];"undefined"==typeof f.length&&(f=[f]);h=h||{};var t=a.a.g.get(e,c),r=!t,v=[],u=0,w=0,z=[],A=[],C=[],D=[],F=[],y,I=0;if(r)a.a.D(f,l);else{if(!k||t&&t._countWaitingForRemove){var E=
|
||||
a.a.Mb(t,function(a){return a.Aa});k=a.a.Pb(E,f,{dontLimitMoves:h.dontLimitMoves,sparse:!0})}for(var E=0,G,H,K;G=k[E];E++)switch(H=G.moved,K=G.index,G.status){case "deleted":for(;u<K;)p(u++);H===n&&(y=t[u],y.$&&(y.$.s(),y.$=n),a.a.Ua(y.Y,e).length&&(h.beforeRemove&&(v.push(y),I++,y.Aa===d?y=null:C.push(y)),y&&z.push.apply(z,y.Y)));u++;break;case "added":for(;w<K;)p(u++);H!==n?(A.push(v.length),p(H)):l(G.value)}for(;w<f.length;)p(u++);v._countWaitingForRemove=I}a.a.g.set(e,c,v);q(h.beforeMove,D);a.a.D(z,
|
||||
h.beforeRemove?a.oa:a.removeNode);var M,O,P;try{P=e.ownerDocument.activeElement}catch(N){}if(A.length)for(;(E=A.shift())!=n;){y=v[E];for(M=n;E;)if((O=v[--E].Y)&&O.length){M=O[O.length-1];break}for(f=0;u=y.Y[f];M=u,f++)a.h.Wb(e,u,M)}for(E=0;y=v[E];E++){y.Y||a.a.extend(y,b(e,g,y.Aa,m,y.pb));for(f=0;u=y.Y[f];M=u,f++)a.h.Wb(e,u,M);!y.Ed&&m&&(m(y.Aa,y.Y,y.pb),y.Ed=!0,M=y.Y[y.Y.length-1])}P&&e.ownerDocument.activeElement!=P&&P.focus();q(h.beforeRemove,C);for(E=0;E<C.length;++E)C[E].Aa=d;q(h.afterMove,D);
|
||||
q(h.afterAdd,F)}})();a.b("utils.setDomNodeChildrenFromArrayMapping",a.a.ec);a.ba=function(){this.allowTemplateRewriting=!1};a.ba.prototype=new a.ca;a.ba.prototype.constructor=a.ba;a.ba.prototype.renderTemplateSource=function(b,c,d,e){if(c=(9>a.a.W?0:b.nodes)?b.nodes():null)return a.a.la(c.cloneNode(!0).childNodes);b=b.text();return a.a.ua(b,e)};a.ba.Ma=new a.ba;a.gc(a.ba.Ma);a.b("nativeTemplateEngine",a.ba);(function(){a.$a=function(){var a=this.Hd=function(){if(!v||!v.tmpl)return 0;try{if(0<=v.tmpl.tag.tmpl.open.toString().indexOf("__"))return 2}catch(a){}return 1}();
|
||||
this.renderTemplateSource=function(b,e,f,g){g=g||w;f=f||{};if(2>a)throw Error("Your version of jQuery.tmpl is too old. Please upgrade to jQuery.tmpl 1.0.0pre or later.");var h=b.data("precompiled");h||(h=b.text()||"",h=v.template(null,"{{ko_with $item.koBindingContext}}"+h+"{{/ko_with}}"),b.data("precompiled",h));b=[e.$data];e=v.extend({koBindingContext:e},f.templateOptions);e=v.tmpl(h,b,e);e.appendTo(g.createElement("div"));v.fragments={};return e};this.createJavaScriptEvaluatorBlock=function(a){return"{{ko_code ((function() { return "+
|
||||
a+" })()) }}"};this.addTemplate=function(a,b){w.write("<script type='text/html' id='"+a+"'>"+b+"\x3c/script>")};0<a&&(v.tmpl.tag.ko_code={open:"__.push($1 || '');"},v.tmpl.tag.ko_with={open:"with($1) {",close:"} "})};a.$a.prototype=new a.ca;a.$a.prototype.constructor=a.$a;var b=new a.$a;0<b.Hd&&a.gc(b);a.b("jqueryTmplTemplateEngine",a.$a)})()})})();})();
|
||||
|
||||
})();
|
||||
|
||||
// Avoid polluting the global scope.
|
||||
var knockout = ko;
|
||||
if (typeof window !== 'undefined') {
|
||||
ko = window.ko;
|
||||
if (typeof oldValue !== 'undefined') {
|
||||
window.ko = oldValue;
|
||||
} else {
|
||||
delete window.ko;
|
||||
}
|
||||
} else {
|
||||
ko = global.ko;
|
||||
if (typeof oldValue !== 'undefined') {
|
||||
global.ko = oldValue;
|
||||
} else {
|
||||
delete global.ko;
|
||||
}
|
||||
}
|
||||
|
||||
export default knockout;
|
||||
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* @license
|
||||
* Knockout ES5 plugin - https://github.com/SteveSanderson/knockout-es5
|
||||
* Copyright (c) Steve Sanderson
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
var OBSERVABLES_PROPERTY = '__knockoutObservables';
|
||||
var SUBSCRIBABLE_PROPERTY = '__knockoutSubscribable';
|
||||
|
||||
// Model tracking
|
||||
// --------------
|
||||
//
|
||||
// This is the central feature of Knockout-ES5. We augment model objects by converting properties
|
||||
// into ES5 getter/setter pairs that read/write an underlying Knockout observable. This means you can
|
||||
// use plain JavaScript syntax to read/write the property while still getting the full benefits of
|
||||
// Knockout's automatic dependency detection and notification triggering.
|
||||
//
|
||||
// For comparison, here's Knockout ES3-compatible syntax:
|
||||
//
|
||||
// var firstNameLength = myModel.user().firstName().length; // Read
|
||||
// myModel.user().firstName('Bert'); // Write
|
||||
//
|
||||
// ... versus Knockout-ES5 syntax:
|
||||
//
|
||||
// var firstNameLength = myModel.user.firstName.length; // Read
|
||||
// myModel.user.firstName = 'Bert'; // Write
|
||||
|
||||
// `ko.track(model)` converts each property on the given model object into a getter/setter pair that
|
||||
// wraps a Knockout observable. Optionally specify an array of property names to wrap; otherwise we
|
||||
// wrap all properties. If any of the properties are already observables, we replace them with
|
||||
// ES5 getter/setter pairs that wrap your original observable instances. In the case of readonly
|
||||
// ko.computed properties, we simply do not define a setter (so attempted writes will be ignored,
|
||||
// which is how ES5 readonly properties normally behave).
|
||||
//
|
||||
// By design, this does *not* recursively walk child object properties, because making literally
|
||||
// everything everywhere independently observable is usually unhelpful. When you do want to track
|
||||
// child object properties independently, define your own class for those child objects and put
|
||||
// a separate ko.track call into its constructor --- this gives you far more control.
|
||||
function track(obj, propertyNames) {
|
||||
if (!obj /*|| typeof obj !== 'object'*/) {
|
||||
throw new Error('When calling ko.track, you must pass an object as the first parameter.');
|
||||
}
|
||||
|
||||
var ko = this,
|
||||
allObservablesForObject = getAllObservablesForObject(obj, true);
|
||||
propertyNames = propertyNames || Object.getOwnPropertyNames(obj);
|
||||
|
||||
propertyNames.forEach(function(propertyName) {
|
||||
// Skip storage properties
|
||||
if (propertyName === OBSERVABLES_PROPERTY || propertyName === SUBSCRIBABLE_PROPERTY) {
|
||||
return;
|
||||
}
|
||||
// Skip properties that are already tracked
|
||||
if (propertyName in allObservablesForObject) {
|
||||
return;
|
||||
}
|
||||
|
||||
var origValue = obj[propertyName],
|
||||
isArray = origValue instanceof Array,
|
||||
observable = ko.isObservable(origValue) ? origValue
|
||||
: isArray ? ko.observableArray(origValue)
|
||||
: ko.observable(origValue);
|
||||
|
||||
Object.defineProperty(obj, propertyName, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: observable,
|
||||
set: ko.isWriteableObservable(observable) ? observable : undefined
|
||||
});
|
||||
|
||||
allObservablesForObject[propertyName] = observable;
|
||||
|
||||
if (isArray) {
|
||||
notifyWhenPresentOrFutureArrayValuesMutate(ko, observable);
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Gets or creates the hidden internal key-value collection of observables corresponding to
|
||||
// properties on the model object.
|
||||
function getAllObservablesForObject(obj, createIfNotDefined) {
|
||||
var result = obj[OBSERVABLES_PROPERTY];
|
||||
if (!result && createIfNotDefined) {
|
||||
result = {};
|
||||
Object.defineProperty(obj, OBSERVABLES_PROPERTY, {
|
||||
value : result
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Computed properties
|
||||
// -------------------
|
||||
//
|
||||
// The preceding code is already sufficient to upgrade ko.computed model properties to ES5
|
||||
// getter/setter pairs (or in the case of readonly ko.computed properties, just a getter).
|
||||
// These then behave like a regular property with a getter function, except they are smarter:
|
||||
// your evaluator is only invoked when one of its dependencies changes. The result is cached
|
||||
// and used for all evaluations until the next time a dependency changes).
|
||||
//
|
||||
// However, instead of forcing developers to declare a ko.computed property explicitly, it's
|
||||
// nice to offer a utility function that declares a computed getter directly.
|
||||
|
||||
// Implements `ko.defineProperty`
|
||||
function defineComputedProperty(obj, propertyName, evaluatorOrOptions) {
|
||||
var ko = this,
|
||||
computedOptions = { owner: obj, deferEvaluation: true };
|
||||
|
||||
if (typeof evaluatorOrOptions === 'function') {
|
||||
computedOptions.read = evaluatorOrOptions;
|
||||
} else {
|
||||
if ('value' in evaluatorOrOptions) {
|
||||
throw new Error('For ko.defineProperty, you must not specify a "value" for the property. You must provide a "get" function.');
|
||||
}
|
||||
|
||||
if (typeof evaluatorOrOptions.get !== 'function') {
|
||||
throw new Error('For ko.defineProperty, the third parameter must be either an evaluator function, or an options object containing a function called "get".');
|
||||
}
|
||||
|
||||
computedOptions.read = evaluatorOrOptions.get;
|
||||
computedOptions.write = evaluatorOrOptions.set;
|
||||
}
|
||||
|
||||
obj[propertyName] = ko.computed(computedOptions);
|
||||
track.call(ko, obj, [propertyName]);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Array handling
|
||||
// --------------
|
||||
//
|
||||
// Arrays are special, because unlike other property types, they have standard mutator functions
|
||||
// (`push`/`pop`/`splice`/etc.) and it's desirable to trigger a change notification whenever one of
|
||||
// those mutator functions is invoked.
|
||||
//
|
||||
// Traditionally, Knockout handles this by putting special versions of `push`/`pop`/etc. on observable
|
||||
// arrays that mutate the underlying array and then trigger a notification. That approach doesn't
|
||||
// work for Knockout-ES5 because properties now return the underlying arrays, so the mutator runs
|
||||
// in the context of the underlying array, not any particular observable:
|
||||
//
|
||||
// // Operates on the underlying array value
|
||||
// myModel.someCollection.push('New value');
|
||||
//
|
||||
// To solve this, Knockout-ES5 detects array values, and modifies them as follows:
|
||||
// 1. Associates a hidden subscribable with each array instance that it encounters
|
||||
// 2. Intercepts standard mutators (`push`/`pop`/etc.) and makes them trigger the subscribable
|
||||
// Then, for model properties whose values are arrays, the property's underlying observable
|
||||
// subscribes to the array subscribable, so it can trigger a change notification after mutation.
|
||||
|
||||
// Given an observable that underlies a model property, watch for any array value that might
|
||||
// be assigned as the property value, and hook into its change events
|
||||
function notifyWhenPresentOrFutureArrayValuesMutate(ko, observable) {
|
||||
var watchingArraySubscription = null;
|
||||
ko.computed(function () {
|
||||
// Unsubscribe to any earlier array instance
|
||||
if (watchingArraySubscription) {
|
||||
watchingArraySubscription.dispose();
|
||||
watchingArraySubscription = null;
|
||||
}
|
||||
|
||||
// Subscribe to the new array instance
|
||||
var newArrayInstance = observable();
|
||||
if (newArrayInstance instanceof Array) {
|
||||
watchingArraySubscription = startWatchingArrayInstance(ko, observable, newArrayInstance);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Listens for array mutations, and when they happen, cause the observable to fire notifications.
|
||||
// This is used to make model properties of type array fire notifications when the array changes.
|
||||
// Returns a subscribable that can later be disposed.
|
||||
function startWatchingArrayInstance(ko, observable, arrayInstance) {
|
||||
var subscribable = getSubscribableForArray(ko, arrayInstance);
|
||||
return subscribable.subscribe(observable);
|
||||
}
|
||||
|
||||
// Gets or creates a subscribable that fires after each array mutation
|
||||
function getSubscribableForArray(ko, arrayInstance) {
|
||||
var subscribable = arrayInstance[SUBSCRIBABLE_PROPERTY];
|
||||
if (!subscribable) {
|
||||
subscribable = new ko.subscribable();
|
||||
Object.defineProperty(arrayInstance, SUBSCRIBABLE_PROPERTY, {
|
||||
value : subscribable
|
||||
});
|
||||
|
||||
var notificationPauseSignal = {};
|
||||
wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal);
|
||||
addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal);
|
||||
}
|
||||
|
||||
return subscribable;
|
||||
}
|
||||
|
||||
// After each array mutation, fires a notification on the given subscribable
|
||||
function wrapStandardArrayMutators(arrayInstance, subscribable, notificationPauseSignal) {
|
||||
['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'].forEach(function(fnName) {
|
||||
var origMutator = arrayInstance[fnName];
|
||||
arrayInstance[fnName] = function() {
|
||||
var result = origMutator.apply(this, arguments);
|
||||
if (notificationPauseSignal.pause !== true) {
|
||||
subscribable.notifySubscribers(this);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Adds Knockout's additional array mutation functions to the array
|
||||
function addKnockoutArrayMutators(ko, arrayInstance, subscribable, notificationPauseSignal) {
|
||||
['remove', 'removeAll', 'destroy', 'destroyAll', 'replace'].forEach(function(fnName) {
|
||||
// Make it a non-enumerable property for consistency with standard Array functions
|
||||
Object.defineProperty(arrayInstance, fnName, {
|
||||
enumerable: false,
|
||||
value: function() {
|
||||
var result;
|
||||
|
||||
// These additional array mutators are built using the underlying push/pop/etc.
|
||||
// mutators, which are wrapped to trigger notifications. But we don't want to
|
||||
// trigger multiple notifications, so pause the push/pop/etc. wrappers and
|
||||
// delivery only one notification at the end of the process.
|
||||
notificationPauseSignal.pause = true;
|
||||
try {
|
||||
// Creates a temporary observableArray that can perform the operation.
|
||||
result = ko.observableArray.fn[fnName].apply(ko.observableArray(arrayInstance), arguments);
|
||||
}
|
||||
finally {
|
||||
notificationPauseSignal.pause = false;
|
||||
}
|
||||
subscribable.notifySubscribers(arrayInstance);
|
||||
return result;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Static utility functions
|
||||
// ------------------------
|
||||
//
|
||||
// Since Knockout-ES5 sets up properties that return values, not observables, you can't
|
||||
// trivially subscribe to the underlying observables (e.g., `someProperty.subscribe(...)`),
|
||||
// or tell them that object values have mutated, etc. To handle this, we set up some
|
||||
// extra utility functions that can return or work with the underlying observables.
|
||||
|
||||
// Returns the underlying observable associated with a model property (or `null` if the
|
||||
// model or property doesn't exist, or isn't associated with an observable). This means
|
||||
// you can subscribe to the property, e.g.:
|
||||
//
|
||||
// ko.getObservable(model, 'propertyName')
|
||||
// .subscribe(function(newValue) { ... });
|
||||
function getObservable(obj, propertyName) {
|
||||
if (!obj /*|| typeof obj !== 'object'*/) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var allObservablesForObject = getAllObservablesForObject(obj, false);
|
||||
return (allObservablesForObject && allObservablesForObject[propertyName]) || null;
|
||||
}
|
||||
|
||||
// Causes a property's associated observable to fire a change notification. Useful when
|
||||
// the property value is a complex object and you've modified a child property.
|
||||
function valueHasMutated(obj, propertyName) {
|
||||
var observable = getObservable(obj, propertyName);
|
||||
|
||||
if (observable) {
|
||||
observable.valueHasMutated();
|
||||
}
|
||||
}
|
||||
|
||||
// Extends a Knockout instance with Knockout-ES5 functionality
|
||||
function attachToKo(ko) {
|
||||
ko.track = track;
|
||||
ko.getObservable = getObservable;
|
||||
ko.valueHasMutated = valueHasMutated;
|
||||
ko.defineProperty = defineComputedProperty;
|
||||
}
|
||||
|
||||
export default {
|
||||
attachToKo : attachToKo
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
import knockout from './knockout-3.5.1.js';
|
||||
import knockout_es5 from './knockout-es5.js';
|
||||
import SvgPathBindingHandler from '../SvgPathBindingHandler.js';
|
||||
|
||||
// install the Knockout-ES5 plugin
|
||||
knockout_es5.attachToKo(knockout);
|
||||
|
||||
// Register all Cesium binding handlers
|
||||
SvgPathBindingHandler.register(knockout);
|
||||
|
||||
export default knockout;
|
||||
@@ -0,0 +1,114 @@
|
||||
.cesium-timeline-main {
|
||||
position: relative;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden;
|
||||
border: solid 1px #888;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.cesium-timeline-trackContainer {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
border-top: solid 1px #888;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.cesium-timeline-tracks {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.cesium-timeline-needle {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 1.7em;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background: #f00;
|
||||
}
|
||||
|
||||
.cesium-timeline-bar {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
height: 1.7em;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(116, 117, 119, 0.8) 0%,
|
||||
rgba(58, 68, 82, 0.8) 11%,
|
||||
rgba(46, 50, 56, 0.8) 46%,
|
||||
rgba(53, 53, 53, 0.8) 81%,
|
||||
rgba(53, 53, 53, 0.8) 100%
|
||||
);
|
||||
}
|
||||
|
||||
.cesium-timeline-ruler {
|
||||
/* NOTE: The label and the ruler must use the same font/size */
|
||||
visibility: hidden;
|
||||
white-space: nowrap;
|
||||
font-size: 80%;
|
||||
z-index: -200;
|
||||
}
|
||||
|
||||
.cesium-timeline-highlight {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: #08f;
|
||||
}
|
||||
|
||||
.cesium-timeline-ticLabel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
white-space: nowrap;
|
||||
font-size: 80%;
|
||||
color: #eee;
|
||||
}
|
||||
|
||||
.cesium-timeline-ticMain {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
height: 50%;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.cesium-timeline-ticSub {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
height: 33%;
|
||||
background: #aaa;
|
||||
}
|
||||
|
||||
.cesium-timeline-ticTiny {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 1px;
|
||||
height: 25%;
|
||||
background: #888;
|
||||
}
|
||||
|
||||
.cesium-timeline-icon16 {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url("../Images/TimelineIcons.png");
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { JulianDate } from "@cesium/engine";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function TimelineHighlightRange(color, heightInPx, base) {
|
||||
this._color = color;
|
||||
this._height = heightInPx;
|
||||
this._base = base ?? 0;
|
||||
}
|
||||
|
||||
TimelineHighlightRange.prototype.getHeight = function () {
|
||||
return this._height;
|
||||
};
|
||||
|
||||
TimelineHighlightRange.prototype.getBase = function () {
|
||||
return this._base;
|
||||
};
|
||||
|
||||
TimelineHighlightRange.prototype.getStartTime = function () {
|
||||
return this._start;
|
||||
};
|
||||
|
||||
TimelineHighlightRange.prototype.getStopTime = function () {
|
||||
return this._stop;
|
||||
};
|
||||
|
||||
TimelineHighlightRange.prototype.setRange = function (start, stop) {
|
||||
this._start = start;
|
||||
this._stop = stop;
|
||||
};
|
||||
|
||||
TimelineHighlightRange.prototype.render = function (renderState) {
|
||||
let range = "";
|
||||
if (this._start && this._stop && this._color) {
|
||||
const highlightStart = JulianDate.secondsDifference(
|
||||
this._start,
|
||||
renderState.epochJulian,
|
||||
);
|
||||
let highlightLeft = Math.round(
|
||||
renderState.timeBarWidth * renderState.getAlpha(highlightStart),
|
||||
);
|
||||
const highlightStop = JulianDate.secondsDifference(
|
||||
this._stop,
|
||||
renderState.epochJulian,
|
||||
);
|
||||
let highlightWidth =
|
||||
Math.round(
|
||||
renderState.timeBarWidth * renderState.getAlpha(highlightStop),
|
||||
) - highlightLeft;
|
||||
if (highlightLeft < 0) {
|
||||
highlightWidth += highlightLeft;
|
||||
highlightLeft = 0;
|
||||
}
|
||||
if (highlightLeft + highlightWidth > renderState.timeBarWidth) {
|
||||
highlightWidth = renderState.timeBarWidth - highlightLeft;
|
||||
}
|
||||
if (highlightWidth > 0) {
|
||||
range = `<span class="cesium-timeline-highlight" style="left: ${highlightLeft.toString()}px; width: ${highlightWidth.toString()}px; bottom: ${this._base.toString()}px; height: ${
|
||||
this._height
|
||||
}px; background-color: ${this._color};"></span>`;
|
||||
}
|
||||
}
|
||||
return range;
|
||||
};
|
||||
export default TimelineHighlightRange;
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Color, defined, JulianDate } from "@cesium/engine";
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function TimelineTrack(interval, pixelHeight, color, backgroundColor) {
|
||||
this.interval = interval;
|
||||
this.height = pixelHeight;
|
||||
this.color = color || new Color(0.5, 0.5, 0.5, 1.0);
|
||||
this.backgroundColor = backgroundColor || new Color(0.0, 0.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
TimelineTrack.prototype.render = function (context, renderState) {
|
||||
const startInterval = this.interval.start;
|
||||
const stopInterval = this.interval.stop;
|
||||
|
||||
const spanStart = renderState.startJulian;
|
||||
const spanStop = JulianDate.addSeconds(
|
||||
renderState.startJulian,
|
||||
renderState.duration,
|
||||
new JulianDate(),
|
||||
);
|
||||
|
||||
if (
|
||||
JulianDate.lessThan(startInterval, spanStart) &&
|
||||
JulianDate.greaterThan(stopInterval, spanStop)
|
||||
) {
|
||||
//The track takes up the entire visible span.
|
||||
context.fillStyle = this.color.toCssColorString();
|
||||
context.fillRect(0, renderState.y, renderState.timeBarWidth, this.height);
|
||||
} else if (
|
||||
JulianDate.lessThanOrEquals(startInterval, spanStop) &&
|
||||
JulianDate.greaterThanOrEquals(stopInterval, spanStart)
|
||||
) {
|
||||
//The track only takes up some of the visible span, compute that span.
|
||||
let x;
|
||||
let start, stop;
|
||||
for (x = 0; x < renderState.timeBarWidth; ++x) {
|
||||
const currentTime = JulianDate.addSeconds(
|
||||
renderState.startJulian,
|
||||
(x / renderState.timeBarWidth) * renderState.duration,
|
||||
new JulianDate(),
|
||||
);
|
||||
if (
|
||||
!defined(start) &&
|
||||
JulianDate.greaterThanOrEquals(currentTime, startInterval)
|
||||
) {
|
||||
start = x;
|
||||
} else if (
|
||||
!defined(stop) &&
|
||||
JulianDate.greaterThanOrEquals(currentTime, stopInterval)
|
||||
) {
|
||||
stop = x;
|
||||
}
|
||||
}
|
||||
|
||||
context.fillStyle = this.backgroundColor.toCssColorString();
|
||||
context.fillRect(0, renderState.y, renderState.timeBarWidth, this.height);
|
||||
|
||||
if (defined(start)) {
|
||||
if (!defined(stop)) {
|
||||
stop = renderState.timeBarWidth;
|
||||
}
|
||||
context.fillStyle = this.color.toCssColorString();
|
||||
context.fillRect(
|
||||
start,
|
||||
renderState.y,
|
||||
Math.max(stop - start, 1),
|
||||
this.height,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
export default TimelineTrack;
|
||||