openskidata-format 12.0.0 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Lift.js +4 -4
- package/dist/Lift.js.map +1 -1
- package/dist/SkiArea.d.ts +3 -0
- package/dist/SkiArea.js.map +1 -1
- package/dist/SkiPass.d.ts +58 -0
- package/dist/SkiPass.js +3 -0
- package/dist/SkiPass.js.map +1 -0
- package/dist/Source.d.ts +14 -1
- package/dist/Source.js +32 -1
- package/dist/Source.js.map +1 -1
- package/dist/ViewportHint.js +4 -1
- package/dist/ViewportHint.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/testUtils.d.ts +2 -0
- package/dist/testUtils.js +7 -0
- package/dist/testUtils.js.map +1 -0
- package/package.json +1 -1
- package/src/ElevationProfile.test.ts +5 -0
- package/src/Lift.test.ts +3 -0
- package/src/Lift.ts +4 -4
- package/src/SkiArea.ts +3 -0
- package/src/SkiPass.ts +62 -0
- package/src/SlopeGradingScale.test.ts +5 -0
- package/src/Source.test.ts +50 -0
- package/src/Source.ts +39 -0
- package/src/ViewportHint.ts +4 -1
- package/src/index.ts +1 -0
- package/src/testUtils.ts +5 -0
package/dist/Lift.js
CHANGED
|
@@ -96,17 +96,17 @@ function getFormattedLiftType(liftType) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
function getLiftColor(status) {
|
|
99
|
-
const
|
|
100
|
-
const
|
|
99
|
+
const brightRedColor = 'hsl(0, 82%, 42%)';
|
|
100
|
+
const dimRedColor = 'hsl(0, 53%, 42%)';
|
|
101
101
|
switch (status) {
|
|
102
102
|
case Status_1.Status.Disused:
|
|
103
103
|
case Status_1.Status.Abandoned:
|
|
104
|
-
return
|
|
104
|
+
return dimRedColor;
|
|
105
105
|
case Status_1.Status.Proposed:
|
|
106
106
|
case Status_1.Status.Planned:
|
|
107
107
|
case Status_1.Status.Construction:
|
|
108
108
|
case Status_1.Status.Operating:
|
|
109
|
-
return
|
|
109
|
+
return brightRedColor;
|
|
110
110
|
default:
|
|
111
111
|
return (0, exhaustiveMatchingGuard_1.exhaustiveMatchingGuard)(status);
|
|
112
112
|
}
|
package/dist/Lift.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Lift.js","sourceRoot":"","sources":["../src/Lift.ts"],"names":[],"mappings":"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"}
|
package/dist/SkiArea.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { LiftType } from './Lift';
|
|
|
3
3
|
import { Place } from './Place';
|
|
4
4
|
import { RunDifficulty } from './Run';
|
|
5
5
|
import { RunDifficultyConvention } from './RunDifficultyConvention';
|
|
6
|
+
import { SkiPassMembership } from './SkiPass';
|
|
6
7
|
import { SnowCoverHistory } from './SnowCoverHistory';
|
|
7
8
|
import { Source } from './Source';
|
|
8
9
|
import { Status } from './Status';
|
|
@@ -41,6 +42,7 @@ export type SkiAreaSummaryFeature = GeoJSON.Feature<SkiAreaGeometry, SkiAreaSumm
|
|
|
41
42
|
* @property {string[]} websites - Official website(s) of the ski area. Derived from the OpenStreetMap website tag and Skimap.org data.
|
|
42
43
|
* @property {string | null} wikidataID - Wikidata identifier. Derived from the OpenStreetMap wikidata tag.
|
|
43
44
|
* @property {Place[]} places - Geographic places this ski area is within (e.g., city, region, country). Derived from reverse geocoding.
|
|
45
|
+
* @property {SkiPassMembership[]} skiPasses - Multi-resort season passes this ski area is on. Empty if it is on none.
|
|
44
46
|
*/
|
|
45
47
|
export type SkiAreaProperties = SkiAreaSummaryProperties & {
|
|
46
48
|
sources: Source[];
|
|
@@ -50,6 +52,7 @@ export type SkiAreaProperties = SkiAreaSummaryProperties & {
|
|
|
50
52
|
wikidataID: string | null;
|
|
51
53
|
places: Place[];
|
|
52
54
|
viewportHint: ViewportHint;
|
|
55
|
+
skiPasses: SkiPassMembership[];
|
|
53
56
|
};
|
|
54
57
|
export type SkiAreaSummaryProperties = {
|
|
55
58
|
type: FeatureType.SkiArea;
|
package/dist/SkiArea.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkiArea.js","sourceRoot":"","sources":["../src/SkiArea.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"SkiArea.js","sourceRoot":"","sources":["../src/SkiArea.ts"],"names":[],"mappings":";;;AA2EA,IAAY,eAGX;AAHD,WAAY,eAAe;IACzB,wCAAqB,CAAA;IACrB,oCAAiB,CAAA;AACnB,CAAC,EAHW,eAAe,+BAAf,eAAe,QAG1B"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Source } from './Source';
|
|
2
|
+
/**
|
|
3
|
+
* Stable identifier for a ski pass, e.g. "ikon".
|
|
4
|
+
*/
|
|
5
|
+
export type SkiPassID = string;
|
|
6
|
+
/**
|
|
7
|
+
* A ski area's membership of one tier of one ski pass.
|
|
8
|
+
*
|
|
9
|
+
* @property {SkiPassID} passID - Identifier of the ski pass.
|
|
10
|
+
* @property {string} passName - Display name of the ski pass.
|
|
11
|
+
* @property {string | null} tier - Tier within the pass, e.g. "base" or "session". Null for the pass's standard tier.
|
|
12
|
+
* @property {string | null} access - Access code, copied verbatim from the source, e.g. "5, 26, 27" or "U". The source documents these per pass in free text, so they are not parsed.
|
|
13
|
+
* @property {number | null} yearJoined - Year the ski area joined this pass, when the source records it.
|
|
14
|
+
* @property {Source[]} sources - Data sources.
|
|
15
|
+
*/
|
|
16
|
+
export type SkiPassMembership = {
|
|
17
|
+
passID: SkiPassID;
|
|
18
|
+
passName: string;
|
|
19
|
+
tier: string | null;
|
|
20
|
+
access: string | null;
|
|
21
|
+
yearJoined: number | null;
|
|
22
|
+
sources: Source[];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* A multi-resort season pass.
|
|
26
|
+
*
|
|
27
|
+
* Unlike runs, lifts, ski areas and spots, a ski pass is not a geographic feature: it is a
|
|
28
|
+
* commercial product that covers a set of ski areas. The ski areas it covers each carry a
|
|
29
|
+
* matching `SkiPassMembership`.
|
|
30
|
+
*
|
|
31
|
+
* @property {SkiPassID} id - Unique identifier for the ski pass. Unlike a ski area ID, this is stable across runs.
|
|
32
|
+
* @property {string} name - Name of the ski pass.
|
|
33
|
+
* @property {Source[]} sources - Data sources.
|
|
34
|
+
* @property {number} skiAreaCount - Number of ski areas this pass covers. Equal to the length of skiAreaIDs.
|
|
35
|
+
* @property {string[]} skiAreaIDs - IDs of the ski areas this pass covers, sorted, so that the order does not depend on anything outside this array.
|
|
36
|
+
* @property {SkiPassUnresolvedRosterEntry[]} unresolvedRosterEntries - Ski areas the source lists on this pass that could not be resolved to a ski area feature.
|
|
37
|
+
*/
|
|
38
|
+
export type SkiPass = {
|
|
39
|
+
type: 'skiPass';
|
|
40
|
+
id: SkiPassID;
|
|
41
|
+
name: string;
|
|
42
|
+
sources: Source[];
|
|
43
|
+
skiAreaCount: number;
|
|
44
|
+
skiAreaIDs: string[];
|
|
45
|
+
unresolvedRosterEntries: SkiPassUnresolvedRosterEntry[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* A ski area listed on a pass by the source, which has no corresponding ski area feature.
|
|
49
|
+
*
|
|
50
|
+
* @property {string} name - Ski area name as written by the source.
|
|
51
|
+
* @property {string} location - Location as written by the source, e.g. "U.S. - Colorado".
|
|
52
|
+
* @property {string} reason - Why the entry could not be resolved.
|
|
53
|
+
*/
|
|
54
|
+
export type SkiPassUnresolvedRosterEntry = {
|
|
55
|
+
name: string;
|
|
56
|
+
location: string;
|
|
57
|
+
reason: string;
|
|
58
|
+
};
|
package/dist/SkiPass.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SkiPass.js","sourceRoot":"","sources":["../src/SkiPass.ts"],"names":[],"mappings":""}
|
package/dist/Source.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
export declare enum SourceType {
|
|
2
2
|
SKIMAP_ORG = "skimap.org",
|
|
3
|
-
OPENSTREETMAP = "openstreetmap"
|
|
3
|
+
OPENSTREETMAP = "openstreetmap",
|
|
4
|
+
STORM_SKIING = "stormskiing.com"
|
|
4
5
|
}
|
|
5
6
|
export type Source = {
|
|
6
7
|
type: SourceType;
|
|
7
8
|
id: string;
|
|
8
9
|
};
|
|
10
|
+
/**
|
|
11
|
+
* The Storm Skiing Journal's ski pass chart, a Google Sheets document.
|
|
12
|
+
*
|
|
13
|
+
* A `STORM_SKIING` source id references a single cell of that document, in `<gid>!<A1>` form
|
|
14
|
+
* (e.g. `677843907!AI64`), so it can be linked to directly.
|
|
15
|
+
*/
|
|
16
|
+
export declare const STORM_SKIING_CHART_DOCUMENT_ID = "1G2-l2DVg7-QwroOi7EqRDrJYJ4ICYLcJbLx-nARJdrA";
|
|
17
|
+
/**
|
|
18
|
+
* URL of the CSV export of one sheet of the ski pass chart. Used to fetch the chart; the ids of
|
|
19
|
+
* the sources derived from it are resolved by `getSourceURL`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function getStormSkiingChartCSVURL(gid: string): string;
|
|
9
22
|
export declare function getSourceURL(source: Source): string;
|
|
10
23
|
export declare function getSourceName(type: SourceType): string;
|
package/dist/Source.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SourceType = void 0;
|
|
3
|
+
exports.STORM_SKIING_CHART_DOCUMENT_ID = exports.SourceType = void 0;
|
|
4
|
+
exports.getStormSkiingChartCSVURL = getStormSkiingChartCSVURL;
|
|
4
5
|
exports.getSourceURL = getSourceURL;
|
|
5
6
|
exports.getSourceName = getSourceName;
|
|
6
7
|
const exhaustiveMatchingGuard_1 = require("./util/exhaustiveMatchingGuard");
|
|
@@ -8,13 +9,41 @@ var SourceType;
|
|
|
8
9
|
(function (SourceType) {
|
|
9
10
|
SourceType["SKIMAP_ORG"] = "skimap.org";
|
|
10
11
|
SourceType["OPENSTREETMAP"] = "openstreetmap";
|
|
12
|
+
SourceType["STORM_SKIING"] = "stormskiing.com";
|
|
11
13
|
})(SourceType || (exports.SourceType = SourceType = {}));
|
|
14
|
+
/**
|
|
15
|
+
* The Storm Skiing Journal's ski pass chart, a Google Sheets document.
|
|
16
|
+
*
|
|
17
|
+
* A `STORM_SKIING` source id references a single cell of that document, in `<gid>!<A1>` form
|
|
18
|
+
* (e.g. `677843907!AI64`), so it can be linked to directly.
|
|
19
|
+
*/
|
|
20
|
+
exports.STORM_SKIING_CHART_DOCUMENT_ID = '1G2-l2DVg7-QwroOi7EqRDrJYJ4ICYLcJbLx-nARJdrA';
|
|
21
|
+
/**
|
|
22
|
+
* URL of the CSV export of one sheet of the ski pass chart. Used to fetch the chart; the ids of
|
|
23
|
+
* the sources derived from it are resolved by `getSourceURL`.
|
|
24
|
+
*/
|
|
25
|
+
function getStormSkiingChartCSVURL(gid) {
|
|
26
|
+
return (`https://docs.google.com/spreadsheets/d/${exports.STORM_SKIING_CHART_DOCUMENT_ID}` +
|
|
27
|
+
`/export?format=csv&gid=${gid}`);
|
|
28
|
+
}
|
|
12
29
|
function getSourceURL(source) {
|
|
13
30
|
switch (source.type) {
|
|
14
31
|
case SourceType.OPENSTREETMAP:
|
|
15
32
|
return 'https://www.openstreetmap.org/' + source.id;
|
|
16
33
|
case SourceType.SKIMAP_ORG:
|
|
17
34
|
return 'https://www.skimap.org/SkiAreas/view/' + source.id;
|
|
35
|
+
case SourceType.STORM_SKIING: {
|
|
36
|
+
const separatorIndex = source.id.indexOf('!');
|
|
37
|
+
if (separatorIndex === -1) {
|
|
38
|
+
throw new Error(`Malformed ${SourceType.STORM_SKIING} source id "${source.id}". Expected <gid>!<A1 reference>.`);
|
|
39
|
+
}
|
|
40
|
+
const gid = source.id.slice(0, separatorIndex);
|
|
41
|
+
const range = source.id.slice(separatorIndex + 1);
|
|
42
|
+
// The gid appears twice: as a query parameter to select the sheet, and in the fragment,
|
|
43
|
+
// which is the only place Google Sheets accepts a cell range.
|
|
44
|
+
return (`https://docs.google.com/spreadsheets/d/${exports.STORM_SKIING_CHART_DOCUMENT_ID}` +
|
|
45
|
+
`/edit?gid=${gid}#gid=${gid}&range=${range}`);
|
|
46
|
+
}
|
|
18
47
|
default:
|
|
19
48
|
return (0, exhaustiveMatchingGuard_1.exhaustiveMatchingGuard)(source.type);
|
|
20
49
|
}
|
|
@@ -25,6 +54,8 @@ function getSourceName(type) {
|
|
|
25
54
|
return 'OpenStreetMap';
|
|
26
55
|
case SourceType.SKIMAP_ORG:
|
|
27
56
|
return 'Skimap.org';
|
|
57
|
+
case SourceType.STORM_SKIING:
|
|
58
|
+
return 'The Storm Skiing Journal';
|
|
28
59
|
default:
|
|
29
60
|
return (0, exhaustiveMatchingGuard_1.exhaustiveMatchingGuard)(type);
|
|
30
61
|
}
|
package/dist/Source.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Source.js","sourceRoot":"","sources":["../src/Source.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"Source.js","sourceRoot":"","sources":["../src/Source.ts"],"names":[],"mappings":";;;AA0BA,8DAKC;AAED,oCAyBC;AAED,sCAWC;AAvED,4EAAwE;AAExE,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,uCAAyB,CAAA;IACzB,6CAA+B,CAAA;IAC/B,8CAAgC,CAAA;AAClC,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB;AAOD;;;;;GAKG;AACU,QAAA,8BAA8B,GACzC,8CAA8C,CAAA;AAEhD;;;GAGG;AACH,SAAgB,yBAAyB,CAAC,GAAW;IACnD,OAAO,CACL,0CAA0C,sCAA8B,EAAE;QAC1E,0BAA0B,GAAG,EAAE,CAChC,CAAA;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,MAAc;IACzC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,UAAU,CAAC,aAAa;YAC3B,OAAO,gCAAgC,GAAG,MAAM,CAAC,EAAE,CAAA;QACrD,KAAK,UAAU,CAAC,UAAU;YACxB,OAAO,uCAAuC,GAAG,MAAM,CAAC,EAAE,CAAA;QAC5D,KAAK,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC;YAC7B,MAAM,cAAc,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAC7C,IAAI,cAAc,KAAK,CAAC,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CACb,aAAa,UAAU,CAAC,YAAY,eAAe,MAAM,CAAC,EAAE,mCAAmC,CAChG,CAAA;YACH,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;YAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAA;YACjD,wFAAwF;YACxF,8DAA8D;YAC9D,OAAO,CACL,0CAA0C,sCAA8B,EAAE;gBAC1E,aAAa,GAAG,QAAQ,GAAG,UAAU,KAAK,EAAE,CAC7C,CAAA;QACH,CAAC;QACD;YACE,OAAO,IAAA,iDAAuB,EAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/C,CAAC;AACH,CAAC;AAED,SAAgB,aAAa,CAAC,IAAgB;IAC5C,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,UAAU,CAAC,aAAa;YAC3B,OAAO,eAAe,CAAA;QACxB,KAAK,UAAU,CAAC,UAAU;YACxB,OAAO,YAAY,CAAA;QACrB,KAAK,UAAU,CAAC,YAAY;YAC1B,OAAO,0BAA0B,CAAA;QACnC;YACE,OAAO,IAAA,iDAAuB,EAAC,IAAI,CAAC,CAAA;IACxC,CAAC;AACH,CAAC"}
|
package/dist/ViewportHint.js
CHANGED
|
@@ -47,11 +47,14 @@ function computeViewportHint(geometries) {
|
|
|
47
47
|
sumCos += Math.cos(bearingRad) * len;
|
|
48
48
|
}
|
|
49
49
|
// Uphill bearing = downhill + 180°; null if no elevation variation found.
|
|
50
|
+
// A small offset is added so the camera is angled slightly to the side of the fall line,
|
|
51
|
+
// giving a better 3-D profile of the terrain rather than pointing straight uphill.
|
|
52
|
+
const bearingSideOffsetDeg = 30;
|
|
50
53
|
let mapBearing = null;
|
|
51
54
|
if (sumSin !== 0 || sumCos !== 0) {
|
|
52
55
|
const dominantDownhill = (Math.atan2(sumSin, sumCos) * 180) / Math.PI;
|
|
53
56
|
const normalizedDownhill = ((dominantDownhill % 360) + 360) % 360;
|
|
54
|
-
mapBearing = (normalizedDownhill + 180) % 360;
|
|
57
|
+
mapBearing = (normalizedDownhill + 180 + bearingSideOffsetDeg) % 360;
|
|
55
58
|
}
|
|
56
59
|
const metersPerDeg = 111320;
|
|
57
60
|
const cosLat = Math.cos(centerLat * (Math.PI / 180));
|
package/dist/ViewportHint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ViewportHint.js","sourceRoot":"","sources":["../src/ViewportHint.ts"],"names":[],"mappings":";;AAuCA,
|
|
1
|
+
{"version":3,"file":"ViewportHint.js","sourceRoot":"","sources":["../src/ViewportHint.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ tslib_1.__exportStar(require("./Run"), exports);
|
|
|
10
10
|
tslib_1.__exportStar(require("./RunDifficultyConvention"), exports);
|
|
11
11
|
tslib_1.__exportStar(require("./SlopeGradingScale"), exports);
|
|
12
12
|
tslib_1.__exportStar(require("./SkiArea"), exports);
|
|
13
|
+
tslib_1.__exportStar(require("./SkiPass"), exports);
|
|
13
14
|
tslib_1.__exportStar(require("./SnowCoverHistory"), exports);
|
|
14
15
|
tslib_1.__exportStar(require("./Source"), exports);
|
|
15
16
|
tslib_1.__exportStar(require("./Spot"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAkC;AAClC,wDAA6B;AAC7B,iDAAsB;AACtB,8DAAmC;AACnC,kDAAuB;AACvB,gDAAqB;AACrB,oEAAyC;AACzC,8DAAmC;AACnC,oDAAyB;AACzB,6DAAkC;AAClC,mDAAwB;AACxB,iDAAsB;AACtB,mDAAwB;AACxB,yDAA8B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,6DAAkC;AAClC,wDAA6B;AAC7B,iDAAsB;AACtB,8DAAmC;AACnC,kDAAuB;AACvB,gDAAqB;AACrB,oEAAyC;AACzC,8DAAmC;AACnC,oDAAyB;AACzB,oDAAyB;AACzB,6DAAkC;AAClC,mDAAwB;AACxB,iDAAsB;AACtB,mDAAwB;AACxB,yDAA8B"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mockViewportHint = mockViewportHint;
|
|
4
|
+
function mockViewportHint() {
|
|
5
|
+
return { center: [0, 0], bearing: null, rotatedWidthMeters: 0, rotatedHeightMeters: 0, minCameraY: 0 };
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=testUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testUtils.js","sourceRoot":"","sources":["../src/testUtils.ts"],"names":[],"mappings":";;AAEA,4CAEC;AAFD,SAAgB,gBAAgB;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAA;AACxG,CAAC"}
|
package/package.json
CHANGED
|
@@ -10,6 +10,7 @@ import { getLiftElevationData, LiftFeature, LiftType } from './Lift'
|
|
|
10
10
|
import { getRunElevationData, RunDifficulty, RunFeature, RunUse } from './Run'
|
|
11
11
|
import { RunDifficultyConvention } from './RunDifficultyConvention'
|
|
12
12
|
import { Status } from './Status'
|
|
13
|
+
import { mockViewportHint } from './testUtils'
|
|
13
14
|
|
|
14
15
|
describe('ElevationProfile', () => {
|
|
15
16
|
describe('getAscentAndDescent', () => {
|
|
@@ -277,6 +278,7 @@ describe('ElevationProfile', () => {
|
|
|
277
278
|
wikidataID: null,
|
|
278
279
|
tunnel: null,
|
|
279
280
|
places: [],
|
|
281
|
+
viewportHint: mockViewportHint(),
|
|
280
282
|
},
|
|
281
283
|
}
|
|
282
284
|
|
|
@@ -317,6 +319,7 @@ describe('ElevationProfile', () => {
|
|
|
317
319
|
wikidataID: null,
|
|
318
320
|
tunnel: null,
|
|
319
321
|
places: [],
|
|
322
|
+
viewportHint: mockViewportHint(),
|
|
320
323
|
},
|
|
321
324
|
}
|
|
322
325
|
|
|
@@ -361,6 +364,7 @@ describe('ElevationProfile', () => {
|
|
|
361
364
|
wikidataID: null,
|
|
362
365
|
tunnel: null,
|
|
363
366
|
places: [],
|
|
367
|
+
viewportHint: mockViewportHint(),
|
|
364
368
|
},
|
|
365
369
|
}
|
|
366
370
|
|
|
@@ -408,6 +412,7 @@ describe('ElevationProfile', () => {
|
|
|
408
412
|
wikidataID: null,
|
|
409
413
|
tunnel: null,
|
|
410
414
|
places: [],
|
|
415
|
+
viewportHint: mockViewportHint(),
|
|
411
416
|
},
|
|
412
417
|
geometry: {
|
|
413
418
|
type: 'LineString',
|
package/src/Lift.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { FeatureType } from './FeatureType';
|
|
2
2
|
import { getLiftElevationData, LiftFeature, LiftType, getFormattedLiftType, getLiftColor } from './Lift';
|
|
3
|
+
import { mockViewportHint } from './testUtils';
|
|
3
4
|
import { LiftStationPosition, LiftStationSpotFeature, SpotType } from './Spot';
|
|
4
5
|
import { Status } from './Status';
|
|
5
6
|
|
|
@@ -41,6 +42,7 @@ function makeLiftFeature(overrides: {
|
|
|
41
42
|
websites: [],
|
|
42
43
|
wikidataID: null,
|
|
43
44
|
places: [],
|
|
45
|
+
viewportHint: mockViewportHint(),
|
|
44
46
|
},
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -64,6 +66,7 @@ function makeStation(
|
|
|
64
66
|
skiAreas: [],
|
|
65
67
|
sources: [],
|
|
66
68
|
places: [],
|
|
69
|
+
viewportHint: mockViewportHint(),
|
|
67
70
|
},
|
|
68
71
|
}
|
|
69
72
|
}
|
package/src/Lift.ts
CHANGED
|
@@ -201,18 +201,18 @@ export function getFormattedLiftType(liftType: LiftType): string {
|
|
|
201
201
|
}
|
|
202
202
|
|
|
203
203
|
export function getLiftColor(status: Status): string {
|
|
204
|
-
const
|
|
205
|
-
const
|
|
204
|
+
const brightRedColor = 'hsl(0, 82%, 42%)'
|
|
205
|
+
const dimRedColor = 'hsl(0, 53%, 42%)'
|
|
206
206
|
|
|
207
207
|
switch (status) {
|
|
208
208
|
case Status.Disused:
|
|
209
209
|
case Status.Abandoned:
|
|
210
|
-
return
|
|
210
|
+
return dimRedColor
|
|
211
211
|
case Status.Proposed:
|
|
212
212
|
case Status.Planned:
|
|
213
213
|
case Status.Construction:
|
|
214
214
|
case Status.Operating:
|
|
215
|
-
return
|
|
215
|
+
return brightRedColor
|
|
216
216
|
default:
|
|
217
217
|
return exhaustiveMatchingGuard(status)
|
|
218
218
|
}
|
package/src/SkiArea.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { LiftType } from './Lift'
|
|
|
3
3
|
import { Place } from './Place'
|
|
4
4
|
import { RunDifficulty } from './Run'
|
|
5
5
|
import { RunDifficultyConvention } from './RunDifficultyConvention'
|
|
6
|
+
import { SkiPassMembership } from './SkiPass'
|
|
6
7
|
import { SnowCoverHistory } from './SnowCoverHistory'
|
|
7
8
|
import { Source } from './Source'
|
|
8
9
|
import { Status } from './Status'
|
|
@@ -51,6 +52,7 @@ export type SkiAreaSummaryFeature = GeoJSON.Feature<
|
|
|
51
52
|
* @property {string[]} websites - Official website(s) of the ski area. Derived from the OpenStreetMap website tag and Skimap.org data.
|
|
52
53
|
* @property {string | null} wikidataID - Wikidata identifier. Derived from the OpenStreetMap wikidata tag.
|
|
53
54
|
* @property {Place[]} places - Geographic places this ski area is within (e.g., city, region, country). Derived from reverse geocoding.
|
|
55
|
+
* @property {SkiPassMembership[]} skiPasses - Multi-resort season passes this ski area is on. Empty if it is on none.
|
|
54
56
|
*/
|
|
55
57
|
export type SkiAreaProperties = SkiAreaSummaryProperties & {
|
|
56
58
|
sources: Source[]
|
|
@@ -60,6 +62,7 @@ export type SkiAreaProperties = SkiAreaSummaryProperties & {
|
|
|
60
62
|
wikidataID: string | null
|
|
61
63
|
places: Place[]
|
|
62
64
|
viewportHint: ViewportHint
|
|
65
|
+
skiPasses: SkiPassMembership[]
|
|
63
66
|
}
|
|
64
67
|
|
|
65
68
|
export type SkiAreaSummaryProperties = {
|
package/src/SkiPass.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Source } from './Source'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stable identifier for a ski pass, e.g. "ikon".
|
|
5
|
+
*/
|
|
6
|
+
export type SkiPassID = string
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A ski area's membership of one tier of one ski pass.
|
|
10
|
+
*
|
|
11
|
+
* @property {SkiPassID} passID - Identifier of the ski pass.
|
|
12
|
+
* @property {string} passName - Display name of the ski pass.
|
|
13
|
+
* @property {string | null} tier - Tier within the pass, e.g. "base" or "session". Null for the pass's standard tier.
|
|
14
|
+
* @property {string | null} access - Access code, copied verbatim from the source, e.g. "5, 26, 27" or "U". The source documents these per pass in free text, so they are not parsed.
|
|
15
|
+
* @property {number | null} yearJoined - Year the ski area joined this pass, when the source records it.
|
|
16
|
+
* @property {Source[]} sources - Data sources.
|
|
17
|
+
*/
|
|
18
|
+
export type SkiPassMembership = {
|
|
19
|
+
passID: SkiPassID
|
|
20
|
+
passName: string
|
|
21
|
+
tier: string | null
|
|
22
|
+
access: string | null
|
|
23
|
+
yearJoined: number | null
|
|
24
|
+
sources: Source[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* A multi-resort season pass.
|
|
29
|
+
*
|
|
30
|
+
* Unlike runs, lifts, ski areas and spots, a ski pass is not a geographic feature: it is a
|
|
31
|
+
* commercial product that covers a set of ski areas. The ski areas it covers each carry a
|
|
32
|
+
* matching `SkiPassMembership`.
|
|
33
|
+
*
|
|
34
|
+
* @property {SkiPassID} id - Unique identifier for the ski pass. Unlike a ski area ID, this is stable across runs.
|
|
35
|
+
* @property {string} name - Name of the ski pass.
|
|
36
|
+
* @property {Source[]} sources - Data sources.
|
|
37
|
+
* @property {number} skiAreaCount - Number of ski areas this pass covers. Equal to the length of skiAreaIDs.
|
|
38
|
+
* @property {string[]} skiAreaIDs - IDs of the ski areas this pass covers, sorted, so that the order does not depend on anything outside this array.
|
|
39
|
+
* @property {SkiPassUnresolvedRosterEntry[]} unresolvedRosterEntries - Ski areas the source lists on this pass that could not be resolved to a ski area feature.
|
|
40
|
+
*/
|
|
41
|
+
export type SkiPass = {
|
|
42
|
+
type: 'skiPass'
|
|
43
|
+
id: SkiPassID
|
|
44
|
+
name: string
|
|
45
|
+
sources: Source[]
|
|
46
|
+
skiAreaCount: number
|
|
47
|
+
skiAreaIDs: string[]
|
|
48
|
+
unresolvedRosterEntries: SkiPassUnresolvedRosterEntry[]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* A ski area listed on a pass by the source, which has no corresponding ski area feature.
|
|
53
|
+
*
|
|
54
|
+
* @property {string} name - Ski area name as written by the source.
|
|
55
|
+
* @property {string} location - Location as written by the source, e.g. "U.S. - Colorado".
|
|
56
|
+
* @property {string} reason - Why the entry could not be resolved.
|
|
57
|
+
*/
|
|
58
|
+
export type SkiPassUnresolvedRosterEntry = {
|
|
59
|
+
name: string
|
|
60
|
+
location: string
|
|
61
|
+
reason: string
|
|
62
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { RunDifficulty, RunUse } from "./Run";
|
|
2
2
|
import { getEstimatedRunDifficulty, getSlopeGradingScale } from "./SlopeGradingScale";
|
|
3
|
+
import { mockViewportHint } from "./testUtils";
|
|
3
4
|
|
|
4
5
|
describe("getEstimatedRunDifficulty", () => {
|
|
5
6
|
it("should return null for steepness below minimum threshold", () => {
|
|
@@ -30,6 +31,7 @@ describe("getEstimatedRunDifficulty", () => {
|
|
|
30
31
|
wikidataID: null,
|
|
31
32
|
tunnel: null,
|
|
32
33
|
places: [],
|
|
34
|
+
viewportHint: mockViewportHint(),
|
|
33
35
|
},
|
|
34
36
|
});
|
|
35
37
|
|
|
@@ -64,6 +66,7 @@ describe("getEstimatedRunDifficulty", () => {
|
|
|
64
66
|
wikidataID: null,
|
|
65
67
|
tunnel: null,
|
|
66
68
|
places: [],
|
|
69
|
+
viewportHint: mockViewportHint(),
|
|
67
70
|
},
|
|
68
71
|
});
|
|
69
72
|
|
|
@@ -102,6 +105,7 @@ describe("getEstimatedRunDifficulty", () => {
|
|
|
102
105
|
wikidataID: null,
|
|
103
106
|
tunnel: null,
|
|
104
107
|
places: [],
|
|
108
|
+
viewportHint: mockViewportHint(),
|
|
105
109
|
},
|
|
106
110
|
});
|
|
107
111
|
|
|
@@ -138,6 +142,7 @@ describe("getEstimatedRunDifficulty", () => {
|
|
|
138
142
|
wikidataID: null,
|
|
139
143
|
tunnel: null,
|
|
140
144
|
places: [],
|
|
145
|
+
viewportHint: mockViewportHint(),
|
|
141
146
|
},
|
|
142
147
|
});
|
|
143
148
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getSourceName,
|
|
3
|
+
getSourceURL,
|
|
4
|
+
getStormSkiingChartCSVURL,
|
|
5
|
+
SourceType,
|
|
6
|
+
} from './Source'
|
|
7
|
+
|
|
8
|
+
describe('getSourceURL', () => {
|
|
9
|
+
it('links to an OpenStreetMap element', () => {
|
|
10
|
+
expect(
|
|
11
|
+
getSourceURL({ type: SourceType.OPENSTREETMAP, id: 'relation/5883752' }),
|
|
12
|
+
).toBe('https://www.openstreetmap.org/relation/5883752')
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('links to a Skimap.org ski area', () => {
|
|
16
|
+
expect(getSourceURL({ type: SourceType.SKIMAP_ORG, id: '181' })).toBe(
|
|
17
|
+
'https://www.skimap.org/SkiAreas/view/181',
|
|
18
|
+
)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('links to a cell of the ski pass chart', () => {
|
|
22
|
+
expect(
|
|
23
|
+
getSourceURL({ type: SourceType.STORM_SKIING, id: '677843907!AI64' }),
|
|
24
|
+
).toBe(
|
|
25
|
+
'https://docs.google.com/spreadsheets/d/1G2-l2DVg7-QwroOi7EqRDrJYJ4ICYLcJbLx-nARJdrA/edit?gid=677843907#gid=677843907&range=AI64',
|
|
26
|
+
)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('rejects a ski pass chart id without a sheet', () => {
|
|
30
|
+
expect(() =>
|
|
31
|
+
getSourceURL({ type: SourceType.STORM_SKIING, id: 'AI64' }),
|
|
32
|
+
).toThrow('Malformed stormskiing.com source id')
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
describe('getSourceName', () => {
|
|
37
|
+
it('names every source type', () => {
|
|
38
|
+
for (const type of Object.values(SourceType)) {
|
|
39
|
+
expect(getSourceName(type).length).toBeGreaterThan(0)
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('getStormSkiingChartCSVURL', () => {
|
|
45
|
+
it('builds the CSV export URL for a sheet', () => {
|
|
46
|
+
expect(getStormSkiingChartCSVURL('677843907')).toBe(
|
|
47
|
+
'https://docs.google.com/spreadsheets/d/1G2-l2DVg7-QwroOi7EqRDrJYJ4ICYLcJbLx-nARJdrA/export?format=csv&gid=677843907',
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
})
|
package/src/Source.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { exhaustiveMatchingGuard } from './util/exhaustiveMatchingGuard'
|
|
|
3
3
|
export enum SourceType {
|
|
4
4
|
SKIMAP_ORG = 'skimap.org',
|
|
5
5
|
OPENSTREETMAP = 'openstreetmap',
|
|
6
|
+
STORM_SKIING = 'stormskiing.com',
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
export type Source = {
|
|
@@ -10,12 +11,48 @@ export type Source = {
|
|
|
10
11
|
id: string
|
|
11
12
|
}
|
|
12
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The Storm Skiing Journal's ski pass chart, a Google Sheets document.
|
|
16
|
+
*
|
|
17
|
+
* A `STORM_SKIING` source id references a single cell of that document, in `<gid>!<A1>` form
|
|
18
|
+
* (e.g. `677843907!AI64`), so it can be linked to directly.
|
|
19
|
+
*/
|
|
20
|
+
export const STORM_SKIING_CHART_DOCUMENT_ID =
|
|
21
|
+
'1G2-l2DVg7-QwroOi7EqRDrJYJ4ICYLcJbLx-nARJdrA'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* URL of the CSV export of one sheet of the ski pass chart. Used to fetch the chart; the ids of
|
|
25
|
+
* the sources derived from it are resolved by `getSourceURL`.
|
|
26
|
+
*/
|
|
27
|
+
export function getStormSkiingChartCSVURL(gid: string): string {
|
|
28
|
+
return (
|
|
29
|
+
`https://docs.google.com/spreadsheets/d/${STORM_SKIING_CHART_DOCUMENT_ID}` +
|
|
30
|
+
`/export?format=csv&gid=${gid}`
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
13
34
|
export function getSourceURL(source: Source): string {
|
|
14
35
|
switch (source.type) {
|
|
15
36
|
case SourceType.OPENSTREETMAP:
|
|
16
37
|
return 'https://www.openstreetmap.org/' + source.id
|
|
17
38
|
case SourceType.SKIMAP_ORG:
|
|
18
39
|
return 'https://www.skimap.org/SkiAreas/view/' + source.id
|
|
40
|
+
case SourceType.STORM_SKIING: {
|
|
41
|
+
const separatorIndex = source.id.indexOf('!')
|
|
42
|
+
if (separatorIndex === -1) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`Malformed ${SourceType.STORM_SKIING} source id "${source.id}". Expected <gid>!<A1 reference>.`,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
const gid = source.id.slice(0, separatorIndex)
|
|
48
|
+
const range = source.id.slice(separatorIndex + 1)
|
|
49
|
+
// The gid appears twice: as a query parameter to select the sheet, and in the fragment,
|
|
50
|
+
// which is the only place Google Sheets accepts a cell range.
|
|
51
|
+
return (
|
|
52
|
+
`https://docs.google.com/spreadsheets/d/${STORM_SKIING_CHART_DOCUMENT_ID}` +
|
|
53
|
+
`/edit?gid=${gid}#gid=${gid}&range=${range}`
|
|
54
|
+
)
|
|
55
|
+
}
|
|
19
56
|
default:
|
|
20
57
|
return exhaustiveMatchingGuard(source.type)
|
|
21
58
|
}
|
|
@@ -27,6 +64,8 @@ export function getSourceName(type: SourceType): string {
|
|
|
27
64
|
return 'OpenStreetMap'
|
|
28
65
|
case SourceType.SKIMAP_ORG:
|
|
29
66
|
return 'Skimap.org'
|
|
67
|
+
case SourceType.STORM_SKIING:
|
|
68
|
+
return 'The Storm Skiing Journal'
|
|
30
69
|
default:
|
|
31
70
|
return exhaustiveMatchingGuard(type)
|
|
32
71
|
}
|
package/src/ViewportHint.ts
CHANGED
|
@@ -83,11 +83,14 @@ export function computeViewportHint(
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Uphill bearing = downhill + 180°; null if no elevation variation found.
|
|
86
|
+
// A small offset is added so the camera is angled slightly to the side of the fall line,
|
|
87
|
+
// giving a better 3-D profile of the terrain rather than pointing straight uphill.
|
|
88
|
+
const bearingSideOffsetDeg = 30
|
|
86
89
|
let mapBearing: number | null = null
|
|
87
90
|
if (sumSin !== 0 || sumCos !== 0) {
|
|
88
91
|
const dominantDownhill = (Math.atan2(sumSin, sumCos) * 180) / Math.PI
|
|
89
92
|
const normalizedDownhill = ((dominantDownhill % 360) + 360) % 360
|
|
90
|
-
mapBearing = (normalizedDownhill + 180) % 360
|
|
93
|
+
mapBearing = (normalizedDownhill + 180 + bearingSideOffsetDeg) % 360
|
|
91
94
|
}
|
|
92
95
|
|
|
93
96
|
const metersPerDeg = 111320
|
package/src/index.ts
CHANGED