celestial-chart 0.8.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/CHANGELOG.md +105 -0
- package/LICENSE +13 -0
- package/NOTICE.md +41 -0
- package/README.md +192 -0
- package/build/celestial.cjs +15354 -0
- package/build/celestial.js +15330 -0
- package/build/celestial.min.js +7 -0
- package/build/celestial.mjs +15333 -0
- package/celestial.css +111 -0
- package/images/dtpick.png +0 -0
- package/lib/geo-zoom.js +116 -0
- package/package.json +89 -0
- package/src/add.js +46 -0
- package/src/canvas.js +269 -0
- package/src/celestial.js +1177 -0
- package/src/config.js +537 -0
- package/src/core.js +14 -0
- package/src/d3.js +28 -0
- package/src/datetimepicker.js +233 -0
- package/src/form.js +837 -0
- package/src/get.js +210 -0
- package/src/global.js +4 -0
- package/src/horizontal.js +98 -0
- package/src/index.js +8 -0
- package/src/kepler.js +481 -0
- package/src/location.js +359 -0
- package/src/moon.js +522 -0
- package/src/projection.js +205 -0
- package/src/svg.js +879 -0
- package/src/timezones.js +71 -0
- package/src/transform.js +94 -0
- package/src/util.js +275 -0
- package/types/celestial.d.ts +545 -0
package/celestial.css
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/* Copyright 2015-16 Olaf Frohn https://github.com/ofrohn, see LICENSE */
|
|
2
|
+
|
|
3
|
+
#celestial-map { width: 100%; height: auto; margin: 0; padding: 0; display: inline-block; position: relative; min-width:720px; overflow: visible; }
|
|
4
|
+
#celestial-map canvas { display: inline-block; position:relative; z-index:0; cursor:hand; cursor:grab; cursor:-moz-grab; cursor:-webkit-grab; }
|
|
5
|
+
#celestial-map canvas:active { cursor:move; cursor: grabbing; cursor: -moz-grabbing; cursor: -webkit-grabbing; }
|
|
6
|
+
#d3-celestial-footer { text-align:center; color:#666; font:10pt/1 'Arial Unicode MS', Arial, Helvetica, sans-serif; }
|
|
7
|
+
#d3-celestial-footer a { text-decoration:none; color:#99f; }
|
|
8
|
+
|
|
9
|
+
/* Form */
|
|
10
|
+
#celestial-form { font:12pt/1 'Arial Unicode MS', Arial, Helvetica, sans-serif; display: inline-block; position: relative; }
|
|
11
|
+
#error { position:absolute; min-width:100px; height:auto; padding: 2px 4px; color:#f00; background:#fff; border:2px solid #f00; border-radius:3px; font-weight:normal; display:block; top:-9999px; left:-9999px; opacity:0; transition:opacity 1s linear; }
|
|
12
|
+
#celestial-form .col { border-top: 1px dotted #000; padding: 4px 6px; margin:0 0 4px; clear:both; white-space: nowrap; }
|
|
13
|
+
/* What parts to show */
|
|
14
|
+
#celestial-form #general,
|
|
15
|
+
#celestial-form #location,
|
|
16
|
+
#celestial-form #stars,
|
|
17
|
+
#celestial-form #dsos,
|
|
18
|
+
#celestial-form #constellations,
|
|
19
|
+
#celestial-form #lines,
|
|
20
|
+
#celestial-form #other,
|
|
21
|
+
#celestial-form #download { display: block }
|
|
22
|
+
|
|
23
|
+
#celestial-form input { vertical-align: 0px; }
|
|
24
|
+
#celestial-form input[type='number'] { width:48px; height:18px; text-align:right; padding:0; }
|
|
25
|
+
input[type="number"]::-webkit-inner-spin-button,
|
|
26
|
+
input[type="number"]::-webkit-outer-spin-button { height: auto; }
|
|
27
|
+
#celestial-form #centerx, #celestial-form #centery, #celestial-form #centerz,
|
|
28
|
+
#celestial-form #lat, #celestial-form #lon { width:64px; margin-top:4px; }
|
|
29
|
+
#celestial-form input[type='text'] { width:194px; height:18px; text-align:left; padding-left:2px; }
|
|
30
|
+
#celestial-form input[type='checkbox'] { vertical-align: -2px; }
|
|
31
|
+
#celestial-form input[type='color'] { width:48px; vertical-align: -3px; height:22px; background:#fff; }
|
|
32
|
+
#celestial-form #datepick { position:relative; display:inline-block; _vertical-align:-8px; top:7px; left:-31px; width:28px; height:24px; border:0px none; border-left:1px solid #ccc; background-color: #f7f7f7; background-image: url('images/dtpick.png'); background-position: -45px 1px; cursor:default; }
|
|
33
|
+
#celestial-form #datepick.active { background-position: -69px 1px; }
|
|
34
|
+
#celestial-form #datetime { cursor:default; }
|
|
35
|
+
#celestial-form input#now { position:relative; left:-24px; }
|
|
36
|
+
#celestial-form #constellation { }
|
|
37
|
+
#celestial-form select option { color:#000; }
|
|
38
|
+
#celestial-form select option[value='---'] { color:#ccc; }
|
|
39
|
+
|
|
40
|
+
#celestial-form input[type='button'] { width:64px; padding-bottom:1px; margin-top:4px; background: #f7f7f7; }
|
|
41
|
+
#celestial-form input#download-png,
|
|
42
|
+
#celestial-form input#download-svg { display: inline-block; text-align: center; margin-left:4px; width:108px; height:24px; font: inherit; line-height:20px; text-decoration: none; color: #000; background: #f7f7f7; }
|
|
43
|
+
#celestial-form input#width { margin-left:2px; }
|
|
44
|
+
#celestial-form input#now,
|
|
45
|
+
#celestial-form input#here { width:48px; margin-left:2px; float:none; }
|
|
46
|
+
#celestial-form input[type='button']:hover,
|
|
47
|
+
#celestial-form #datepick:hover,
|
|
48
|
+
#celestial-form input#download-png:hover,
|
|
49
|
+
#celestial-form input#download-svg:hover { background-color:#eee; cursor:pointer; }
|
|
50
|
+
|
|
51
|
+
#celestial-form input[type='text']:disabled,
|
|
52
|
+
#celestial-form input[type='number']:disabled,
|
|
53
|
+
#celestial-form input[type='color']:disabled { border: 1px solid #ccc; background:#eee }
|
|
54
|
+
|
|
55
|
+
#celestial-form input[type='text'],
|
|
56
|
+
#celestial-form input[type='number'],
|
|
57
|
+
#celestial-form input[type='color'],
|
|
58
|
+
#celestial-form select,
|
|
59
|
+
#celestial-form input#now,
|
|
60
|
+
#celestial-form input#here,
|
|
61
|
+
#celestial-form input#show,
|
|
62
|
+
#celestial-form input#download-png,
|
|
63
|
+
#celestial-form input#download-svg { border: 1px solid #000; border-radius:3px; height:24px; }
|
|
64
|
+
|
|
65
|
+
#celestial-form label { margin:0 2px 0 8px; }
|
|
66
|
+
#celestial-form label.header { font-weight:bold; }
|
|
67
|
+
#celestial-form input + span { margin:0 4px 0 2px; }
|
|
68
|
+
#celestial-form label:first-child,
|
|
69
|
+
#celestial-form br + label { margin-left:0; }
|
|
70
|
+
|
|
71
|
+
/* Zoom controls */
|
|
72
|
+
#celestial-zoomin,
|
|
73
|
+
#celestial-zoomout { width:32px; height:32px; left:8px; top:12px; background: rgba(255,255,255,0.5); border:1px solid #000; border-radius:3px; position:absolute; font: normal bold 24px/1 Consolas, Courier, 'Courier New', monospace; cursor:pointer; }
|
|
74
|
+
#celestial-zoomout { top: 48px; }
|
|
75
|
+
#celestial-zoomin:hover,
|
|
76
|
+
#celestial-zoomout:hover { background: rgba(255,255,255,0.7); }
|
|
77
|
+
#celestial-zoomin:disabled,
|
|
78
|
+
#celestial-zoomout:disabled { background: rgba(255,255,255,0.0); border:1px solid rgba(153,153,153,0.7); color:rgba(153,153,153,0.7); cursor:default; }
|
|
79
|
+
|
|
80
|
+
#celestial-date { position:absolute; top:-9999px; width:193px; text-align:center; border:1px solid #000; background:#fff; opacity:0; transition:.6s ease-in opacity; font: 13px/1 sans-serif; }
|
|
81
|
+
#celestial-date input, #celestial-date select { font:inherit; }
|
|
82
|
+
#celestial-date #yr, #celestial-date #mon { margin: 2px 3px; vertical-align:middle; }
|
|
83
|
+
#celestial-date #left, #celestial-date #right { display:inline-block; width:12px; height:24px; margin:0; vertical-align:-8px; cursor:pointer; background-image: url('images/dtpick.png'); }
|
|
84
|
+
#celestial-form #day-left, #celestial-form #day-right { display:inline-block; float:none; width:12px; height:24px; margin:0; padding:0; vertical-align:middle; cursor:pointer; border: 0 none; background-color:transparent; background-image: url('images/dtpick.png'); }
|
|
85
|
+
#celestial-form #day-right { position:relative; left:-30px; }
|
|
86
|
+
#celestial-date #left, #celestial-form #day-left { background-position: -8px 0px; }
|
|
87
|
+
#celestial-date #right, #celestial-form #day-right { background-position: -30px 0px; }
|
|
88
|
+
#celestial-date #hr, #celestial-date #min, #celestial-date #sec { margin: 0 0 2px 0; width:34px; }
|
|
89
|
+
#celestial-date #hr { border-right: 0px none; border-radius: 3px 0 0 3px; }
|
|
90
|
+
#celestial-date #min { border-right: 0px none; border-left: 0px none; border-radius: 0; }
|
|
91
|
+
#celestial-date #sec { border-left: 0px none; border-radius: 0 3px 3px 0; }
|
|
92
|
+
#celestial-date #tz { margin: 0 0 2px 4px; }
|
|
93
|
+
#celestial-date #cal { display:inline-block; width:182px; margin:0 4px; }
|
|
94
|
+
#celestial-date .date { display:inline-block; width:19px; height:14px; border:1px solid #fff; color:#000; font-weight: bold; text-align:right; vertical-align:middle; padding:2px 4px 2px 0; cursor:pointer; }
|
|
95
|
+
#celestial-date .grey { color:#ccc; }
|
|
96
|
+
#celestial-date .weekday { color:#666; font-sixe:11px; background:#eee; border:1px solid #eee; }
|
|
97
|
+
#celestial-date .weekend { color:#f00; }
|
|
98
|
+
#celestial-date .selected { border:1px solid #000; border-radius:3px; }
|
|
99
|
+
#celestial-date .today { background:#ff0; }
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@media print {
|
|
103
|
+
#celestial-zoomin, #celestial-zoomout, #celestial-form { display: none; }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* SVG styles
|
|
107
|
+
|
|
108
|
+
svg .constname {
|
|
109
|
+
fill: "#ffff99"; fill-opacity:0.7; font: bold 14px 'Lucida Sans Unicode', Trebuchet, Helvetica, Arial, sans-serif; text-anchor: middle
|
|
110
|
+
}
|
|
111
|
+
*/
|
|
Binary file
|
package/lib/geo-zoom.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as d3 from "../src/d3.js";
|
|
2
|
+
import versor from "versor";
|
|
3
|
+
|
|
4
|
+
// Spherical zoom and rotation: dragging turns the globe, the wheel zooms.
|
|
5
|
+
//
|
|
6
|
+
// The algorithm comes from Jason Davies' `d3.geo.zoom` plugin (2014,
|
|
7
|
+
// http://www.jasondavies.com/maps/rotate/). The quaternion mathematics is not
|
|
8
|
+
// copied from it: we use the `versor` package, which provides the same
|
|
9
|
+
// computation from Mike Bostock under the ISC licence — so distributing this
|
|
10
|
+
// fork is licence-clean. The D3 glue (v7 d3.zoom, d3.pointer) is ours.
|
|
11
|
+
//
|
|
12
|
+
// The outward interface deliberately stays that of the v3 `d3.geo.zoom`
|
|
13
|
+
// (projection, center, scaleExtent, scale, on), so that celestial.js's call
|
|
14
|
+
// sites did not have to change.
|
|
15
|
+
export function geoZoom() {
|
|
16
|
+
var projection,
|
|
17
|
+
selection_ = null, // what it was called on: the transform goes here
|
|
18
|
+
events = d3.dispatch("zoomstart", "zoom", "zoomend"),
|
|
19
|
+
view = { r: [0, 0, 0], k: 1 },
|
|
20
|
+
// Here d3.zoom's k is the projection scale itself (in pixels), not a
|
|
21
|
+
// factor around 1 — so scaleExtent receives the same numbers as in v3.
|
|
22
|
+
behavior = d3.zoom().on("start", onStart).on("zoom", onZoom).on("end", onEnd),
|
|
23
|
+
mouse0, rotate0, zoomPoint;
|
|
24
|
+
|
|
25
|
+
function zoom(selection) {
|
|
26
|
+
selection_ = selection;
|
|
27
|
+
selection.call(behavior);
|
|
28
|
+
behavior.transform(selection, d3.zoomIdentity.scale(view.k));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// d3.pointer returns [NaN, NaN] when the event carries no pointer position —
|
|
32
|
+
// for instance on a programmatic zoom.transform() call. v3's d3.mouse never
|
|
33
|
+
// saw such a case, because there the zoom always started from a real UI event.
|
|
34
|
+
// Left unhandled, the NaN travels through the quaternions and the projection's
|
|
35
|
+
// rotation becomes NaN.
|
|
36
|
+
function pointerOf(event_, el) {
|
|
37
|
+
var p = d3.pointer(event_, el);
|
|
38
|
+
return (isFinite(p[0]) && isFinite(p[1])) ? p : null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Use the projection's inverse to find which point of the sky is under the cursor.
|
|
42
|
+
function spherePoint(point_) {
|
|
43
|
+
var coord = projection.invert(point_);
|
|
44
|
+
return coord && isFinite(coord[0]) && isFinite(coord[1]) ? versor.cartesian(coord) : null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The angle subtended by the two pointer positions at the projection centre.
|
|
48
|
+
// This gives the "bank" component when the pointer slides off the globe.
|
|
49
|
+
function bank(p0, p1) {
|
|
50
|
+
var t = projection.translate(),
|
|
51
|
+
angle_ = Math.atan2(p0[1] - t[1], p0[0] - t[0]) - Math.atan2(p1[1] - t[1], p1[0] - t[0]);
|
|
52
|
+
return [Math.cos(angle_ / 2), 0, 0, Math.sin(angle_ / 2)];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function onStart(event_) {
|
|
56
|
+
mouse0 = pointerOf(event_, this);
|
|
57
|
+
rotate0 = versor(projection.rotate());
|
|
58
|
+
var point_ = mouse0 && spherePoint(mouse0);
|
|
59
|
+
if (point_) zoomPoint = point_;
|
|
60
|
+
events.call("zoomstart", zoom);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function onZoom(event_) {
|
|
64
|
+
projection.scale(view.k = event_.transform.k);
|
|
65
|
+
var mouse1 = pointerOf(event_, this);
|
|
66
|
+
// Without a pointer position only the scale changes; rotation is undefined.
|
|
67
|
+
if (mouse1 && mouse0) {
|
|
68
|
+
var point1 = spherePoint(mouse1),
|
|
69
|
+
between = zoomPoint && point1 ? versor.delta(zoomPoint, point1) : null;
|
|
70
|
+
rotate0 = between ? versor.multiply(rotate0, between)
|
|
71
|
+
: versor.multiply(bank(mouse0, mouse1), rotate0);
|
|
72
|
+
projection.rotate(view.r = versor.rotation(rotate0));
|
|
73
|
+
}
|
|
74
|
+
if (mouse1) mouse0 = mouse1;
|
|
75
|
+
events.call("zoom", zoom);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function onEnd() {
|
|
79
|
+
events.call("zoomend", zoom);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
zoom.projection = function(_) {
|
|
83
|
+
if (!arguments.length) return projection;
|
|
84
|
+
projection = _;
|
|
85
|
+
view = { r: projection.rotate(), k: projection.scale() };
|
|
86
|
+
return zoom;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// The focal point of v3's behavior.zoom. v7's d3.zoom zooms around the
|
|
90
|
+
// cursor and that cannot be pinned to a fixed point; the method is kept only
|
|
91
|
+
// because the call site expects it.
|
|
92
|
+
zoom.center = function(_) {
|
|
93
|
+
return arguments.length ? zoom : null;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
zoom.scaleExtent = function(_) {
|
|
97
|
+
if (!arguments.length) return behavior.scaleExtent();
|
|
98
|
+
behavior.scaleExtent(_);
|
|
99
|
+
return zoom;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
zoom.scale = function(_) {
|
|
103
|
+
if (!arguments.length) return view.k;
|
|
104
|
+
view.k = _;
|
|
105
|
+
if (selection_) behavior.transform(selection_, d3.zoomIdentity.scale(_));
|
|
106
|
+
return zoom;
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
zoom.on = function(type_, fn) {
|
|
110
|
+
if (arguments.length < 2) return events.on(type_);
|
|
111
|
+
events.on(type_, fn);
|
|
112
|
+
return zoom;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
return zoom;
|
|
116
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "celestial-chart",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Interactive celestial map for the browser — a modernised fork of d3-celestial (D3 v7, ES modules, TypeScript types, multiple maps per page)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"astronomy",
|
|
7
|
+
"star chart",
|
|
8
|
+
"sky map",
|
|
9
|
+
"celestial",
|
|
10
|
+
"constellations",
|
|
11
|
+
"planetarium",
|
|
12
|
+
"cartography",
|
|
13
|
+
"projection",
|
|
14
|
+
"d3",
|
|
15
|
+
"canvas",
|
|
16
|
+
"svg",
|
|
17
|
+
"visualization"
|
|
18
|
+
],
|
|
19
|
+
"type": "module",
|
|
20
|
+
"license": "BSD-3-Clause",
|
|
21
|
+
"author": "Fekete László",
|
|
22
|
+
"homepage": "https://celestial.blackit.hu",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/Fekete85/celestial-chart.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/Fekete85/celestial-chart/issues"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"main": "build/celestial.cjs",
|
|
35
|
+
"module": "build/celestial.mjs",
|
|
36
|
+
"types": "types/celestial.d.ts",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./types/celestial.d.ts",
|
|
40
|
+
"import": "./build/celestial.mjs",
|
|
41
|
+
"require": "./build/celestial.cjs"
|
|
42
|
+
},
|
|
43
|
+
"./package.json": "./package.json"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"CHANGELOG.md",
|
|
47
|
+
"LICENSE",
|
|
48
|
+
"NOTICE.md",
|
|
49
|
+
"README.md",
|
|
50
|
+
"build",
|
|
51
|
+
"celestial.css",
|
|
52
|
+
"images",
|
|
53
|
+
"lib",
|
|
54
|
+
"src",
|
|
55
|
+
"types/celestial.d.ts"
|
|
56
|
+
],
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "node build.mjs",
|
|
59
|
+
"prepare": "node build.mjs",
|
|
60
|
+
"test": "node --test test/*.test.mjs",
|
|
61
|
+
"types": "tsc -p types/check/tsconfig.json",
|
|
62
|
+
"selftest": "node harness/compare.mjs --selftest harness/reference-d3v3.json",
|
|
63
|
+
"check": "node harness/verify.mjs",
|
|
64
|
+
"check:all": "node harness/verify.mjs --all",
|
|
65
|
+
"verify": "npm run build && npm run test && npm run types && npm run selftest && npm run check:all",
|
|
66
|
+
"serve": "node harness/server.mjs"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"d3-dispatch": "^3.0.1",
|
|
70
|
+
"d3-fetch": "^3.0.1",
|
|
71
|
+
"d3-geo": "^3.1.1",
|
|
72
|
+
"d3-geo-projection": "^4.0.0",
|
|
73
|
+
"d3-interpolate": "^3.0.1",
|
|
74
|
+
"d3-scale": "^4.0.2",
|
|
75
|
+
"d3-selection": "^3.0.0",
|
|
76
|
+
"d3-shape": "^3.2.0",
|
|
77
|
+
"d3-time-format": "^4.1.0",
|
|
78
|
+
"d3-transition": "^3.0.1",
|
|
79
|
+
"d3-zoom": "^3.0.0",
|
|
80
|
+
"versor": "^0.2.0"
|
|
81
|
+
},
|
|
82
|
+
"devDependencies": {
|
|
83
|
+
"acorn": "^8.18.0",
|
|
84
|
+
"acorn-walk": "^8.3.5",
|
|
85
|
+
"esbuild": "^0.25.0",
|
|
86
|
+
"playwright": "^1.62.1",
|
|
87
|
+
"typescript": "^7.0.2"
|
|
88
|
+
}
|
|
89
|
+
}
|
package/src/add.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Celestial } from "./core.js";
|
|
2
|
+
import { has } from "./util.js";
|
|
3
|
+
|
|
4
|
+
//Add more JSON data to the map
|
|
5
|
+
var hasCallback = false;
|
|
6
|
+
|
|
7
|
+
Celestial.add = function(dat) {
|
|
8
|
+
var res = {};
|
|
9
|
+
//dat: {file: path, type:'json|raw', callback: func(), redraw: func()}
|
|
10
|
+
//or {file:file, size:null, shape:null, color:null} TBI
|
|
11
|
+
// with size,shape,color: "prop=val:result;.." || function(prop) { .. return res; }
|
|
12
|
+
if (!has(dat, "type")) return console.log("Missing type");
|
|
13
|
+
|
|
14
|
+
if ((dat.type === "dso" || dat.type === "json") && (!has(dat, "file") || !has(dat, "callback"))) return console.log("Can't add data file");
|
|
15
|
+
if ((dat.type === "line" || dat.type === "raw") && !has(dat, "callback")) return console.log("Can't add data");
|
|
16
|
+
|
|
17
|
+
if (has(dat, "file")) res.file = dat.file;
|
|
18
|
+
res.type = dat.type;
|
|
19
|
+
if (has(dat, "callback")) res.callback = dat.callback;
|
|
20
|
+
if (has(dat, "redraw")) res.redraw = dat.redraw;
|
|
21
|
+
if (has(dat, "save")) res.save = dat.save;
|
|
22
|
+
Celestial.data.push(res);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
Celestial.remove = function(i) {
|
|
26
|
+
if (i !== null && i < Celestial.data.length) {
|
|
27
|
+
return Celestial.data.splice(i,1);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
Celestial.clear = function() {
|
|
32
|
+
Celestial.data = [];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
Celestial.addCallback = function(dat) {
|
|
36
|
+
Celestial.callback = dat;
|
|
37
|
+
hasCallback = (dat !== null);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
Celestial.runCallback = function(dat) {
|
|
41
|
+
hasCallback = false; // avoid recursion
|
|
42
|
+
Celestial.callback();
|
|
43
|
+
hasCallback = true;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { hasCallback };
|
package/src/canvas.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { Celestial } from "./core.js";
|
|
2
|
+
import { functor } from "./util.js";
|
|
3
|
+
|
|
4
|
+
var Canvas = {};
|
|
5
|
+
|
|
6
|
+
Canvas.symbol = function () {
|
|
7
|
+
// parameters and default values
|
|
8
|
+
var type = functor("circle"),
|
|
9
|
+
size = functor(64),
|
|
10
|
+
age = functor(Math.PI), //crescent shape 0..2Pi
|
|
11
|
+
color = functor("#fff"),
|
|
12
|
+
text = functor(""),
|
|
13
|
+
padding = functor([2,2]),
|
|
14
|
+
pos;
|
|
15
|
+
|
|
16
|
+
function canvas_symbol(context) {
|
|
17
|
+
draw_symbol[type()](context);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var draw_symbol = {
|
|
21
|
+
"circle": function(ctx) {
|
|
22
|
+
var s = Math.sqrt(size()),
|
|
23
|
+
r = s/2;
|
|
24
|
+
ctx.arc(pos[0], pos[1], r, 0, 2 * Math.PI);
|
|
25
|
+
ctx.closePath();
|
|
26
|
+
return r;
|
|
27
|
+
},
|
|
28
|
+
"square": function(ctx) {
|
|
29
|
+
var s = Math.sqrt(size()),
|
|
30
|
+
r = s/1.7;
|
|
31
|
+
ctx.moveTo(pos[0]-r, pos[1]-r);
|
|
32
|
+
ctx.lineTo(pos[0]+r, pos[1]-r);
|
|
33
|
+
ctx.lineTo(pos[0]+r, pos[1]+r);
|
|
34
|
+
ctx.lineTo(pos[0]-r, pos[1]+r);
|
|
35
|
+
ctx.closePath();
|
|
36
|
+
return r;
|
|
37
|
+
},
|
|
38
|
+
"diamond": function(ctx) {
|
|
39
|
+
var s = Math.sqrt(size()),
|
|
40
|
+
r = s/1.5;
|
|
41
|
+
ctx.moveTo(pos[0], pos[1]-r);
|
|
42
|
+
ctx.lineTo(pos[0]+r, pos[1]);
|
|
43
|
+
ctx.lineTo(pos[0], pos[1]+r);
|
|
44
|
+
ctx.lineTo(pos[0]-r, pos[1]);
|
|
45
|
+
ctx.closePath();
|
|
46
|
+
return r;
|
|
47
|
+
},
|
|
48
|
+
"triangle": function(ctx) {
|
|
49
|
+
var s = Math.sqrt(size()),
|
|
50
|
+
r = s/Math.sqrt(3);
|
|
51
|
+
ctx.moveTo(pos[0], pos[1]-r);
|
|
52
|
+
ctx.lineTo(pos[0]+r, pos[1]+r);
|
|
53
|
+
ctx.lineTo(pos[0]-r, pos[1]+r);
|
|
54
|
+
ctx.closePath();
|
|
55
|
+
return r;
|
|
56
|
+
},
|
|
57
|
+
"ellipse": function(ctx) {
|
|
58
|
+
var s = Math.sqrt(size()),
|
|
59
|
+
r = s/2;
|
|
60
|
+
ctx.save();
|
|
61
|
+
ctx.translate(pos[0], pos[1]);
|
|
62
|
+
ctx.scale(1.6, 0.8);
|
|
63
|
+
ctx.beginPath();
|
|
64
|
+
ctx.arc(0, 0, r, 0, 2 * Math.PI);
|
|
65
|
+
ctx.closePath();
|
|
66
|
+
ctx.restore();
|
|
67
|
+
return r;
|
|
68
|
+
},
|
|
69
|
+
"marker": function(ctx) {
|
|
70
|
+
var s = Math.sqrt(size()),
|
|
71
|
+
r = s/2;
|
|
72
|
+
ctx.moveTo(pos[0], pos[1]-r);
|
|
73
|
+
ctx.lineTo(pos[0], pos[1]+r);
|
|
74
|
+
ctx.moveTo(pos[0]-r, pos[1]);
|
|
75
|
+
ctx.lineTo(pos[0]+r, pos[1]);
|
|
76
|
+
ctx.closePath();
|
|
77
|
+
return r;
|
|
78
|
+
},
|
|
79
|
+
"cross-circle": function(ctx) {
|
|
80
|
+
var s = Math.sqrt(size()),
|
|
81
|
+
r = s/2;
|
|
82
|
+
ctx.moveTo(pos[0], pos[1]-s);
|
|
83
|
+
ctx.lineTo(pos[0], pos[1]+s);
|
|
84
|
+
ctx.moveTo(pos[0]-s, pos[1]);
|
|
85
|
+
ctx.lineTo(pos[0]+s, pos[1]);
|
|
86
|
+
ctx.stroke();
|
|
87
|
+
ctx.beginPath();
|
|
88
|
+
ctx.moveTo(pos[0], pos[1]);
|
|
89
|
+
ctx.arc(pos[0], pos[1], r, 0, 2 * Math.PI);
|
|
90
|
+
ctx.closePath();
|
|
91
|
+
return r;
|
|
92
|
+
},
|
|
93
|
+
"stroke-circle": function(ctx) {
|
|
94
|
+
var s = Math.sqrt(size()),
|
|
95
|
+
r = s/2;
|
|
96
|
+
ctx.moveTo(pos[0], pos[1]-s);
|
|
97
|
+
ctx.lineTo(pos[0], pos[1]+s);
|
|
98
|
+
ctx.stroke();
|
|
99
|
+
ctx.beginPath();
|
|
100
|
+
ctx.moveTo(pos[0], pos[1]);
|
|
101
|
+
ctx.arc(pos[0], pos[1], r, 0, 2 * Math.PI);
|
|
102
|
+
ctx.closePath();
|
|
103
|
+
return r;
|
|
104
|
+
},
|
|
105
|
+
"crescent": function(ctx) {
|
|
106
|
+
var s = Math.sqrt(size()),
|
|
107
|
+
r = s/2,
|
|
108
|
+
ag = age(),
|
|
109
|
+
ph = 0.5 * (1 - Math.cos(ag)),
|
|
110
|
+
// The terminator's semi-minor axis is |cos(phase angle)| times the disc
|
|
111
|
+
// radius, which in terms of the illuminated fraction is
|
|
112
|
+
// |2*ph - 1| = 2*|ph - 0.5|. The factor of 1.6 drew a full moon 19% too
|
|
113
|
+
// narrow — as a gibbous disc (#130). 1.98 + 0.01 gives exactly 1 at full
|
|
114
|
+
// and new moon while keeping the guard against a degenerate ellipse at
|
|
115
|
+
// the quarters.
|
|
116
|
+
e = 1.98 * Math.abs(ph - 0.5) + 0.01,
|
|
117
|
+
dir = ag > Math.PI,
|
|
118
|
+
termdir = Math.abs(ph) > 0.5 ? dir : !dir,
|
|
119
|
+
moonFill = ctx.fillStyle,
|
|
120
|
+
darkFill = ph < 0.157 ? "#669" : "#557";
|
|
121
|
+
ctx.save();
|
|
122
|
+
ctx.fillStyle = darkFill;
|
|
123
|
+
ctx.beginPath();
|
|
124
|
+
ctx.moveTo(pos[0], pos[1]);
|
|
125
|
+
ctx.arc(pos[0], pos[1], r, 0, 2 * Math.PI);
|
|
126
|
+
ctx.closePath();
|
|
127
|
+
ctx.fill();
|
|
128
|
+
ctx.fillStyle = moonFill;
|
|
129
|
+
ctx.beginPath();
|
|
130
|
+
ctx.moveTo(pos[0], pos[1]);
|
|
131
|
+
ctx.arc(pos[0], pos[1], r, -Math.PI/2, Math.PI/2, dir);
|
|
132
|
+
ctx.scale(e, 1);
|
|
133
|
+
ctx.arc(pos[0]/e, pos[1], r, Math.PI/2, -Math.PI/2, termdir);
|
|
134
|
+
ctx.closePath();
|
|
135
|
+
ctx.fill();
|
|
136
|
+
ctx.restore();
|
|
137
|
+
|
|
138
|
+
return r;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
canvas_symbol.type = function(_) {
|
|
144
|
+
if (!arguments.length) return type;
|
|
145
|
+
type = functor(_);
|
|
146
|
+
return canvas_symbol;
|
|
147
|
+
};
|
|
148
|
+
canvas_symbol.size = function(_) {
|
|
149
|
+
if (!arguments.length) return size;
|
|
150
|
+
size = functor(_);
|
|
151
|
+
return canvas_symbol;
|
|
152
|
+
};
|
|
153
|
+
canvas_symbol.age = function(_) {
|
|
154
|
+
if (!arguments.length) return age;
|
|
155
|
+
age = functor(_);
|
|
156
|
+
return canvas_symbol;
|
|
157
|
+
};
|
|
158
|
+
canvas_symbol.text = function(_) {
|
|
159
|
+
if (!arguments.length) return text;
|
|
160
|
+
text = functor(_);
|
|
161
|
+
return canvas_symbol;
|
|
162
|
+
};
|
|
163
|
+
canvas_symbol.position = function(_) {
|
|
164
|
+
if (!arguments.length) return;
|
|
165
|
+
pos = _;
|
|
166
|
+
return canvas_symbol;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
return canvas_symbol;
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
Celestial.Canvas = Canvas;
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
/*var color = "#fff", angle = 0, align = "center", baseline = "middle", font = "10px sans-serif", padding = [0,0], aPos, sText;
|
|
176
|
+
|
|
177
|
+
canvas.text = function () {
|
|
178
|
+
|
|
179
|
+
function txt(ctx){
|
|
180
|
+
ctx.fillStyle = color;
|
|
181
|
+
ctx.textAlign = align;
|
|
182
|
+
ctx.textBaseline = baseline;
|
|
183
|
+
|
|
184
|
+
//var pt = projection(d.geometry.coordinates);
|
|
185
|
+
if (angle) {
|
|
186
|
+
canvas.save();
|
|
187
|
+
canvas.translate(aPos[0], aPos[1]);
|
|
188
|
+
canvas.rotate(angle);
|
|
189
|
+
canvas.fillText(sText, 0, 0);
|
|
190
|
+
canvas.restore();
|
|
191
|
+
} else
|
|
192
|
+
canvas.fillText(sText, aPos[0], aPos[1]);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
txt.angle = function(x) {
|
|
196
|
+
if (!arguments.length) return angle * 180 / Math.PI;
|
|
197
|
+
color = x * Math.PI / 180;
|
|
198
|
+
return txt;
|
|
199
|
+
};
|
|
200
|
+
txt.color = function(s) {
|
|
201
|
+
if (!arguments.length) return color;
|
|
202
|
+
color = s;
|
|
203
|
+
return txt;
|
|
204
|
+
};
|
|
205
|
+
txt.align = function(s) {
|
|
206
|
+
if (!arguments.length) return align;
|
|
207
|
+
align = s;
|
|
208
|
+
return txt;
|
|
209
|
+
};
|
|
210
|
+
txt.baseline = function(s) {
|
|
211
|
+
if (!arguments.length) return baseline;
|
|
212
|
+
baseline = s;
|
|
213
|
+
return txt;
|
|
214
|
+
};
|
|
215
|
+
txt.padding = function(a) {
|
|
216
|
+
if (!arguments.length) return padding;
|
|
217
|
+
padding = a;
|
|
218
|
+
return txt;
|
|
219
|
+
};
|
|
220
|
+
txt.text = function(s) {
|
|
221
|
+
if (!arguments.length) return sText;
|
|
222
|
+
sText = s;
|
|
223
|
+
return txt;
|
|
224
|
+
};
|
|
225
|
+
txt.font = function(s) {
|
|
226
|
+
if (!arguments.length) return font;
|
|
227
|
+
font = s;
|
|
228
|
+
return txt;
|
|
229
|
+
};
|
|
230
|
+
txt.style = function(o) {
|
|
231
|
+
if (!arguments.length) return;
|
|
232
|
+
if (o.fill) color = o.fill;
|
|
233
|
+
if (o.font) font = o.font;
|
|
234
|
+
return txt;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function ctxPath(d) {
|
|
240
|
+
var pt;
|
|
241
|
+
//d.map( function(axe, i) {
|
|
242
|
+
context.beginPath();
|
|
243
|
+
for (var i = 0; i < d.length; i++) {
|
|
244
|
+
pt = projection(d[i]);
|
|
245
|
+
if (i === 0)
|
|
246
|
+
context.moveTo(pt[0], pt[1]);
|
|
247
|
+
else
|
|
248
|
+
context.lineTo(pt[0], pt[1]);
|
|
249
|
+
}
|
|
250
|
+
context.fill();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
function ctxText(d, ang) {
|
|
255
|
+
var pt = projection(d.geometry.coordinates);
|
|
256
|
+
if (ang) {
|
|
257
|
+
canvas.save();
|
|
258
|
+
canvas.translate(pt[0], pt[1]);
|
|
259
|
+
canvas.rotate(Math.PI/2);
|
|
260
|
+
canvas.fillText(txt, 0, 0);
|
|
261
|
+
canvas.restore();
|
|
262
|
+
} else
|
|
263
|
+
canvas.fillText(d.properties.txt, pt[0], pt[1]);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
export { Canvas };
|