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.
@@ -0,0 +1,233 @@
1
+ import * as d3 from "./d3.js";
2
+
3
+ import { testNumber } from "./form.js";
4
+ import { dateDiff, isNumber, classes_, px, styles_ } from "./util.js";
5
+
6
+ // Date and time picker belonging to one map. It receives the instance because
7
+ // its fields live on that map's settings form.
8
+ var datetimepicker = function(sky, callback) {
9
+ var cfg = sky.cfg;
10
+ var $form = sky.form.$form;
11
+ var date = new Date(),
12
+ tzFormat = d3.timeFormat("%Z"),
13
+ tz = [{"−12:00":-720}, {"−11:00":-660}, {"−10:00":-600}, {"−09:30":-570}, {"−09:00":-540}, {"−08:00":-480}, {"−07:00":-420}, {"−06:00":-360}, {"−05:00":-300}, {"−04:30":-270}, {"−04:00":-240}, {"−03:30":-210}, {"−03:00":-180}, {"−02:30":-150}, {"−02:00":-120}, {"−01:00":-60}, {"±00:00":0}, {"+01:00":60}, {"+02:00":120}, {"+03:00":180}, {"+03:30":210}, {"+04:00":240}, {"+04:30":270}, {"+05:00":300}, {"+05:30":330}, {"+05:45":345}, {"+06:00":360}, {"+06:30":390}, {"+07:00":420}, {"+08:00":480}, {"+08:30":510}, {"+08:45":525}, {"+09:00":540}, {"+09:30":570}, {"+10:00":600}, {"+10:30":630}, {"+11:00":660}, {"+12:00":720}, {"+12:45":765}, {"+13:00":780}, {"+14:00":840}],
14
+ months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
15
+ days = ["Su", "M", "Tu", "W", "Th", "F", "Sa"],
16
+ years = getYears(date),
17
+ dateFormat = d3.timeFormat("%Y-%m-%d"),
18
+ dateParse = d3.timeParse("%Y-%m-%d"),
19
+ dtrange = cfg.daterange || [];
20
+
21
+ var picker = d3.select(sky.parentElement + " ~ #celestial-form").append("div").attr("id", "celestial-date");
22
+ nav("left");
23
+ monSel();
24
+ yrSel();
25
+ nav("right");
26
+
27
+ var cal = picker.append("div").attr("id", "cal");
28
+
29
+ daySel();
30
+
31
+ timeSel();
32
+ tzSel();
33
+
34
+ function daySel() {
35
+ var mo = $form("mon").value, yr = $form("yr").value,
36
+ curdt = new Date(yr, mo, 1),
37
+ cal = d3.select(sky.parentElement + " ~ #celestial-form").select("#cal"),
38
+ today = new Date();
39
+ yr = parseInt(yr);
40
+ mo = parseInt(mo);
41
+ curdt.setDate(curdt.getDate() - curdt.getDay());
42
+ var nd = cal.node();
43
+ while (nd.firstChild) nd.removeChild(nd.firstChild);
44
+
45
+ for (var i=0; i<7; i++) {
46
+ classes_(cal.append("div"), {"date": true, "weekday": true}).html(days[i]);
47
+ }
48
+ for (i=0; i<42; i++) {
49
+ var curmon = curdt.getMonth(), curday = curdt.getDay(), curid = dateFormat(curdt);
50
+ classes_(cal.append("div"), {
51
+ "date": true,
52
+ "grey": curmon !== mo,
53
+ "weekend": curmon === mo && (curday === 0 || curday === 6),
54
+ "today": dateDiff(curdt, today) === 0,
55
+ "selected": dateDiff(curdt, date) === 0
56
+ }).attr("id", curid)
57
+ .on("click", pick)
58
+ .html(curdt.getDate().toString());
59
+
60
+ curdt.setDate(curdt.getDate()+1);
61
+ }
62
+ }
63
+
64
+ function yrSel() {
65
+ picker.append("select").attr("title", "Year").attr("id", "yr").on("change", daySel);
66
+
67
+ fillYrSel();
68
+ }
69
+
70
+ function fillYrSel() {
71
+ var sel = d3.select(sky.parentElement + " ~ #celestial-form").select("select#yr"),
72
+ year = date.getFullYear(),
73
+ selected = 0,
74
+ years = getYears(date);
75
+
76
+ sel.selectAll("*").remove();
77
+ sel.selectAll('option').data(years).enter().append('option')
78
+ .text(function (d, i) {
79
+ if (d === year) selected = i;
80
+ return d.toString();
81
+ });
82
+ sel.property("selectedIndex", selected);
83
+ }
84
+
85
+ function monSel() {
86
+ var sel = picker.append("select").attr("title", "Month").attr("id", "mon").on("change", daySel),
87
+ selected = 0,
88
+ month = date.getMonth();
89
+
90
+ sel.selectAll('option').data(months).enter().append('option')
91
+ .attr("value", function (d, i) {
92
+ if (i === month) selected = i;
93
+ return i;
94
+ })
95
+ .text(function (d) { return d; });
96
+ sel.property("selectedIndex", selected);
97
+ }
98
+
99
+ function nav(dir) {
100
+ var lnk = picker.append("div").attr("id", dir).on("click", function () {
101
+ var mon = $form("mon"), yr = $form("yr");
102
+
103
+ if (dir === "left") {
104
+ if (mon.selectedIndex === 0) {
105
+ mon.selectedIndex = 11;
106
+ yr.selectedIndex--;
107
+ } else mon.selectedIndex--;
108
+ } else {
109
+ if (mon.selectedIndex === 11) {
110
+ mon.selectedIndex = 0;
111
+ yr.selectedIndex++;
112
+ } else mon.selectedIndex++;
113
+ }
114
+ daySel();
115
+ });
116
+ }
117
+
118
+ function timeSel() {
119
+ picker.append("input").attr("type", "number").attr("id", "hr").attr("title", "Hours").attr("max", "24").attr("min", "-1").attr("step", "1").attr("value", date.getHours()).on("change", function () { if (testNumber(this) === true) pick(); });
120
+
121
+ picker.append("input").attr("type", "number").attr("id", "min").attr("title", "Minutes").attr("max", "60").attr("min", "-1").attr("step", "1").attr("value", date.getMinutes()).on("change", function () { if (testNumber(this) === true) pick(); });
122
+
123
+ picker.append("input").attr("type", "number").attr("id", "sec").attr("title", "Seconds").attr("max", "60").attr("min", "-1").attr("step", "1").attr("value", date.getSeconds()).on("change", function () { if (testNumber(this) === true) pick(); });
124
+ }
125
+
126
+ function tzSel() {
127
+ var sel = picker.append("select").attr("title", "Time zone offset from UTC").attr("id", "tz").on("change", pick),
128
+ selected = 15,
129
+ tzOffset = -date.getTimezoneOffset();
130
+ sel.selectAll('option').data(tz).enter().append('option')
131
+ .attr("value", function (d, i) {
132
+ var k = Object.keys(d)[0];
133
+ if (d[k] === tzOffset) selected = i;
134
+ return d[k];
135
+ })
136
+ .text(function (d) { return Object.keys(d)[0]; });
137
+ sel.property("selectedIndex", selected);
138
+ }
139
+
140
+ function getYears(dt) {
141
+ var r = getDateRange(dt.getFullYear()), res = [];
142
+ for (var i = r[0]; i <= r[1]; i++) res.push(i);
143
+ return res;
144
+ }
145
+
146
+ function getDateRange(yr) {
147
+ if (!dtrange || dtrange.length < 1) return [yr - 10, yr + 10];
148
+
149
+ if (dtrange.length === 1 && isNumber(dtrange[0])) {
150
+ if (dtrange[0] >= 100) return [dtrange[0] - 10, dtrange[0] + 10];
151
+ else return [yr - dtrange[0], yr + dtrange[0]];
152
+ }
153
+ if (dtrange.length === 2 && isNumber(dtrange[0])&& isNumber(dtrange[1])) {
154
+ if (dtrange[1] >= 100) return [dtrange[0], dtrange[1]];
155
+ else return [dtrange[0] - dtrange[1], dtrange[0] + dtrange[1]];
156
+ }
157
+ return [yr - 10, yr + 10];
158
+ }
159
+
160
+ function select(id, val) {
161
+ var sel = $form(id);
162
+ for (var i=0; i<sel.childNodes.length; i++) {
163
+ if (sel.childNodes[i].value == val) {
164
+ sel.selectedIndex = i;
165
+ break;
166
+ }
167
+ }
168
+ }
169
+
170
+ function set(dt) {
171
+ if (dt) date.setTime(dt.valueOf());
172
+
173
+ select("yr", date.getFullYear());
174
+ select("mon", date.getMonth());
175
+ daySel();
176
+ $form("hr").value = date.getHours();
177
+ $form("min").value = date.getMinutes();
178
+ $form("sec").value = date.getSeconds();
179
+ }
180
+
181
+ this.show = function(dt, tz) {
182
+ var nd = $form("celestial-date"),
183
+ src = $form("datepick"),
184
+ left = src.offsetLeft + src.offsetWidth - nd.offsetWidth,
185
+ top = src.offsetTop - nd.offsetHeight - 1;
186
+
187
+ if (nd.offsetTop === -9999) {
188
+ date.setTime(dt.valueOf());
189
+ select("tz", tz);
190
+ set();
191
+ styles_(d3.select(sky.parentElement + " ~ #celestial-form").select("#celestial-date"),
192
+ {"top": px(top), "left": px(left), "opacity": 1});
193
+ d3.select(sky.parentElement + " ~ #celestial-form").select("#datepick").classed("active", true);
194
+ } else {
195
+ vanish();
196
+ }
197
+ };
198
+
199
+ this.isVisible = function () {
200
+ if (!document.getElementById("datepick")) return false;
201
+ return d3.select(sky.parentElement + " ~ #celestial-form").select("#datepick").classed("active") === true;
202
+ };
203
+
204
+ this.hide = function () {
205
+ vanish();
206
+ };
207
+
208
+ function vanish() {
209
+ d3.select(sky.parentElement + " ~ #celestial-form").select("#celestial-date").style("opacity", 0);
210
+ styles_(d3.select("#error"), {top:"-9999px", left:"-9999px", opacity:0});
211
+ d3.select(sky.parentElement + " ~ #celestial-form").select("#datepick").classed("active", false);
212
+ setTimeout(function () { $form("celestial-date").style.top = px(-9999); }, 600);
213
+ }
214
+
215
+ function pick() {
216
+ var h = $form("hr").value, m = $form("min").value,
217
+ s = $form("sec").value, tz = $form("tz").value;
218
+
219
+ if (this.id && this.id.search(/^\d/) !== -1) {
220
+ date = dateParse(this.id);
221
+ }
222
+ fillYrSel();
223
+
224
+ date.setHours(h, m, s);
225
+ set();
226
+
227
+ callback(date, tz);
228
+ }
229
+
230
+
231
+ };
232
+
233
+ export { datetimepicker };