@ccp-nc/crystvis-js 0.4.13 → 0.5.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/.eslintrc.json +0 -0
- package/.github/workflows/test-mocha.yml +1 -1
- package/.vscode/settings.json +1 -2
- package/LICENSE +0 -0
- package/README.html +0 -0
- package/README.md +2 -2
- package/demo/index.html +14 -0
- package/demo/main.js +12 -0
- package/docs/.nojekyll +0 -0
- package/docs-tutorials/Events.md +0 -0
- package/docs-tutorials/Queries.md +0 -0
- package/fonts/OpenSans/OFL.txt +93 -0
- package/fonts/OpenSans/OpenSans-Italic-VariableFont_wdth,wght.ttf +0 -0
- package/fonts/OpenSans/OpenSans-VariableFont_wdth,wght.ttf +0 -0
- package/fonts/OpenSans/README.txt +100 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-Bold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-BoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-ExtraBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-ExtraBoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-Italic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-Light.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-LightItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-Medium.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-MediumItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-Regular.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-SemiBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans/OpenSans-SemiBoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Bold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-BoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-ExtraBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-ExtraBoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Italic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Light.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-LightItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Medium.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-MediumItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-Regular.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-SemiBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_Condensed/OpenSans_Condensed-SemiBoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Bold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-BoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-ExtraBoldItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Italic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Light.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-LightItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Medium.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-MediumItalic.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-Regular.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBold.ttf +0 -0
- package/fonts/OpenSans/static/OpenSans_SemiCondensed/OpenSans_SemiCondensed-SemiBoldItalic.ttf +0 -0
- package/fonts/Rubik/OFL.txt +0 -0
- package/fonts/Rubik/README.txt +0 -0
- package/fonts/Rubik/Rubik-Italic-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/Rubik-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Black.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BlackItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Bold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Italic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Light.ttf +0 -0
- package/fonts/Rubik/static/Rubik-LightItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Medium.ttf +0 -0
- package/fonts/Rubik/static/Rubik-MediumItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Regular.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBoldItalic.ttf +0 -0
- package/index.html +0 -0
- package/index.js +0 -0
- package/jsconf.json +0 -0
- package/lib/assets/fonts/OpenSans-Medium.fnt +157 -0
- package/lib/assets/fonts/OpenSans-Medium.png +0 -0
- package/lib/assets/fonts/Rubik-Medium.fnt +141 -89
- package/lib/assets/fonts/Rubik-Medium.png +0 -0
- package/lib/assets/fonts/bmpfonts.in.js +6 -1
- package/lib/assets/fonts/bmpfonts.js +10 -2
- package/lib/assets/fonts/font.js +0 -0
- package/lib/assets/fonts/index.js +4 -2
- package/lib/assets/fonts/threebmfont.js +0 -0
- package/lib/data.js +0 -0
- package/lib/formats/cell.js +26 -3
- package/lib/formats/cif.js +1 -1
- package/lib/formats/magres.js +37 -3
- package/lib/formats/xyz.js +7 -2
- package/lib/loader.js +0 -0
- package/lib/model.js +83 -8
- package/lib/modelview.js +35 -0
- package/lib/nmrdata.js +0 -0
- package/lib/primitives/atoms.js +0 -0
- package/lib/primitives/cell.js +25 -3
- package/lib/primitives/dither.js +0 -0
- package/lib/primitives/ellipsoid.js +29 -9
- package/lib/primitives/geometries.js +0 -0
- package/lib/primitives/isosurface.js +0 -0
- package/lib/primitives/shapes.js +0 -0
- package/lib/primitives/sprites.js +2 -2
- package/lib/query.js +0 -0
- package/lib/render.js +107 -5
- package/lib/selbox.js +0 -0
- package/lib/shaders/aura.frag +0 -0
- package/lib/shaders/aura.vert +0 -0
- package/lib/shaders/dither.frag +0 -0
- package/lib/shaders/dither.vert +0 -0
- package/lib/shaders/index.in.js +0 -0
- package/lib/shaders/index.js +0 -0
- package/lib/shaders/msdf300.frag +0 -0
- package/lib/shaders/msdf300.vert +0 -0
- package/lib/tensor.js +1 -1
- package/lib/utils.js +22 -1
- package/lib/visualizer.js +95 -4
- package/package.json +18 -18
- package/scripts/build-bundle.js +0 -0
- package/scripts/build-fonts.js +8 -3
- package/scripts/build-resources.js +0 -0
- package/scripts/plugins-shim.js +0 -0
- package/test/chemdata.js +1 -1
- package/test/data/CHA.cif +0 -0
- package/test/data/H2O.xyz +0 -0
- package/test/data/H2_bound.xyz +0 -0
- package/test/data/bohr.cell +11 -0
- package/test/data/ethanol.cell +0 -0
- package/test/data/example_single.cif +0 -0
- package/test/data/frac.cell +0 -0
- package/test/data/org.cif +0 -0
- package/test/data/pyridine.xyz +1 -1
- package/test/data/pyridine_nocell.xyz +13 -0
- package/test/data/si8.xyz +0 -0
- package/test/data/si8_noisy.xyz +10 -0
- package/test/loader.js +22 -1
- package/test/model.js +40 -9
- package/test/query.js +1 -1
- package/test/tensor.js +1 -1
- package/test/test-html/examples.js +0 -0
- package/test/test-html/index.html +0 -0
- package/test/test-html/index.js +35 -5
- package/tools/compile_colors.py +0 -0
- package/tools/compile_periodic.py +0 -0
- package/tools/ptable.json +0 -0
- package/tools/test +0 -0
package/lib/render.js
CHANGED
|
@@ -21,6 +21,29 @@ import {
|
|
|
21
21
|
|
|
22
22
|
import * as Primitives from './primitives/index.js';
|
|
23
23
|
|
|
24
|
+
import {
|
|
25
|
+
TextSprite
|
|
26
|
+
} from './primitives/index.js';
|
|
27
|
+
|
|
28
|
+
// themes:
|
|
29
|
+
const themes = {
|
|
30
|
+
dark: {
|
|
31
|
+
background: 0x000000,
|
|
32
|
+
foreground: 0xffffff,
|
|
33
|
+
highlight: 0x00ff00,
|
|
34
|
+
cell_line_color: 0xffffff,
|
|
35
|
+
label_color: 0xffffff,
|
|
36
|
+
|
|
37
|
+
},
|
|
38
|
+
light: {
|
|
39
|
+
background: 0xffffff,
|
|
40
|
+
foreground: 0x000000,
|
|
41
|
+
highlight: 0x00ff00,
|
|
42
|
+
cell_line_color: 0x000000,
|
|
43
|
+
label_color: 0x000000,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
24
47
|
|
|
25
48
|
class Renderer {
|
|
26
49
|
|
|
@@ -31,8 +54,9 @@ class Renderer {
|
|
|
31
54
|
* @param {int} width Desired width for the renderer
|
|
32
55
|
* @param {int} height Desired height for the renderer. If both this and width are zero, automatically
|
|
33
56
|
* resizes with the container
|
|
57
|
+
* @param {object} options Optional parameters for the WebGLRenderer
|
|
34
58
|
*/
|
|
35
|
-
constructor(target, width, height) {
|
|
59
|
+
constructor(target, width, height, options = {}) {
|
|
36
60
|
|
|
37
61
|
// Grab the target element
|
|
38
62
|
this._div = $(target);
|
|
@@ -42,8 +66,14 @@ class Renderer {
|
|
|
42
66
|
this._h = height;
|
|
43
67
|
this._updateSize();
|
|
44
68
|
|
|
69
|
+
// combine options with defaults
|
|
70
|
+
this._options = Object.assign({
|
|
71
|
+
antialias: true,
|
|
72
|
+
alpha: true,
|
|
73
|
+
}, options);
|
|
74
|
+
|
|
45
75
|
// Renderer
|
|
46
|
-
this._r = new THREE.WebGLRenderer();
|
|
76
|
+
this._r = new THREE.WebGLRenderer(this._options);
|
|
47
77
|
this._r.autoClear = true;
|
|
48
78
|
this._r.setPixelRatio(window.devicePixelRatio);
|
|
49
79
|
this._r.setSize(this._w, this._h);
|
|
@@ -81,11 +111,13 @@ class Renderer {
|
|
|
81
111
|
// Groups
|
|
82
112
|
this._groups = {
|
|
83
113
|
model: new THREE.Group(),
|
|
84
|
-
primitives: new THREE.Group()
|
|
114
|
+
primitives: new THREE.Group(),
|
|
115
|
+
notifications: new THREE.Group(),
|
|
85
116
|
};
|
|
86
117
|
|
|
87
118
|
this._s.add(this._groups.model);
|
|
88
119
|
this._s.add(this._groups.primitives);
|
|
120
|
+
this._s.add(this._groups.notifications);
|
|
89
121
|
|
|
90
122
|
// Selection box (multiple raycast)
|
|
91
123
|
this._sboxlist = [];
|
|
@@ -94,7 +126,7 @@ class Renderer {
|
|
|
94
126
|
this._sboxhelp.selectOverCallback = this._selectBoxEnd.bind(this);
|
|
95
127
|
|
|
96
128
|
// Color scheme
|
|
97
|
-
this.
|
|
129
|
+
this.theme = themes.dark;
|
|
98
130
|
this._cell_x_color = 0xff0000;
|
|
99
131
|
this._cell_y_color = 0x00ff00;
|
|
100
132
|
this._cell_z_color = 0x0000ff;
|
|
@@ -193,6 +225,51 @@ class Renderer {
|
|
|
193
225
|
}
|
|
194
226
|
}
|
|
195
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Draw list of notifications
|
|
230
|
+
* @param {Array} messages - List of (strings) messages to display
|
|
231
|
+
* @param {Object} parameters - Parameters for the messages
|
|
232
|
+
*
|
|
233
|
+
*/
|
|
234
|
+
addNotifications(messages, parameters={}) {
|
|
235
|
+
// TODO: adjust position of messages when camera is rotated
|
|
236
|
+
// currently this is only correct when camera is looking down the z-axis
|
|
237
|
+
//top of message should be the bottom left corner of the canvas
|
|
238
|
+
var position = [this._c.left, this._c.bottom, this._c.near];
|
|
239
|
+
// calculate height of messages
|
|
240
|
+
const messages_height = 0.05 * messages.length;
|
|
241
|
+
// todo: this should really be the x projection of the unit cell
|
|
242
|
+
// rather than the length of the 0th unit cell vector
|
|
243
|
+
// but it works for now...
|
|
244
|
+
const xshift = this.getOrbitCenter().x * 2;
|
|
245
|
+
const yshift = 0.05 * messages_height + this.getOrbitCenter().y + 0.5;
|
|
246
|
+
const defaults = {
|
|
247
|
+
position: position,
|
|
248
|
+
height: messages_height,
|
|
249
|
+
color: this.theme.label_color,
|
|
250
|
+
faceCamera: true,
|
|
251
|
+
fixScale: true,
|
|
252
|
+
shift: [xshift,yshift,0.0],
|
|
253
|
+
onOverlay: true,
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
parameters = _.merge(defaults, parameters);
|
|
257
|
+
|
|
258
|
+
// add text sprite to scene
|
|
259
|
+
// Create a TextSprite to hold the message
|
|
260
|
+
var messageSprite = new TextSprite(messages.join('\n'), parameters);
|
|
261
|
+
|
|
262
|
+
this._groups.notifications.add(messageSprite);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Remove all notifications from the scene
|
|
267
|
+
*/
|
|
268
|
+
clearNotifications() {
|
|
269
|
+
this._groups.notifications.remove(...this._groups.notifications.children);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
|
|
196
273
|
add(object, group = 'primitives') {
|
|
197
274
|
if (!(this._groups[group].children.includes(object)))
|
|
198
275
|
this._groups[group].add(object);
|
|
@@ -301,6 +378,11 @@ class Renderer {
|
|
|
301
378
|
this._oc.target = p;
|
|
302
379
|
}
|
|
303
380
|
|
|
381
|
+
getOrbitCenter() {
|
|
382
|
+
return this._oc.target;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
|
|
304
386
|
/**
|
|
305
387
|
* Remove all currently rendered objects.
|
|
306
388
|
*/
|
|
@@ -362,6 +444,25 @@ class Renderer {
|
|
|
362
444
|
this._sboxhelp.element.css({
|
|
363
445
|
'opacity': o
|
|
364
446
|
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// themes
|
|
450
|
+
get theme() {
|
|
451
|
+
return this._theme;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
set theme(t) {
|
|
455
|
+
this._theme = t;
|
|
456
|
+
// background color
|
|
457
|
+
this._r.setClearColor(t.background, 1);
|
|
458
|
+
// Cell color scheme
|
|
459
|
+
this._r._cell_line_color = t.cell_line_color;
|
|
460
|
+
// labels
|
|
461
|
+
this._label_color = t.label_color;
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
365
466
|
}
|
|
366
467
|
|
|
367
468
|
// This convenient wrapper is useful to keep the Primitives out of the Model's logic.
|
|
@@ -436,5 +537,6 @@ _addVectorField: function(points, vectors, colors, scale) {
|
|
|
436
537
|
|
|
437
538
|
|
|
438
539
|
export {
|
|
439
|
-
Renderer
|
|
540
|
+
Renderer,
|
|
541
|
+
themes
|
|
440
542
|
};
|
package/lib/selbox.js
CHANGED
|
File without changes
|
package/lib/shaders/aura.frag
CHANGED
|
File without changes
|
package/lib/shaders/aura.vert
CHANGED
|
File without changes
|
package/lib/shaders/dither.frag
CHANGED
|
File without changes
|
package/lib/shaders/dither.vert
CHANGED
|
File without changes
|
package/lib/shaders/index.in.js
CHANGED
|
File without changes
|
package/lib/shaders/index.js
CHANGED
|
File without changes
|
package/lib/shaders/msdf300.frag
CHANGED
|
File without changes
|
package/lib/shaders/msdf300.vert
CHANGED
|
File without changes
|
package/lib/tensor.js
CHANGED
|
@@ -37,7 +37,7 @@ class TensorData {
|
|
|
37
37
|
// Diagonalize
|
|
38
38
|
var eigs = mjs.eigs(this._Msymm);
|
|
39
39
|
// Sort by eigenvalue magnitude
|
|
40
|
-
var evecs =
|
|
40
|
+
var evecs = eigs.eigenvectors.map(e => e.vector._data);
|
|
41
41
|
eigs = _.zip(eigs.values._data, evecs);
|
|
42
42
|
eigs = _.sortBy(eigs, function(x) {
|
|
43
43
|
return x[0];
|
package/lib/utils.js
CHANGED
|
@@ -163,6 +163,27 @@ function hashCode(arg) {
|
|
|
163
163
|
return hash;
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Compare floating point numbers for equality with a given tolerance
|
|
169
|
+
*
|
|
170
|
+
* @param {float} a First number
|
|
171
|
+
* @param {float} b Second number
|
|
172
|
+
* @param {float} tol Tolerance (absolute)
|
|
173
|
+
*
|
|
174
|
+
* @return {bool} True if the numbers are equal within the tolerance
|
|
175
|
+
*
|
|
176
|
+
* TODO: could add relative tolerance as well
|
|
177
|
+
*/
|
|
178
|
+
function floatEqual(a, b, tol=1e-6) {
|
|
179
|
+
// check for NaNs
|
|
180
|
+
if (a !== a || b !== b) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return Math.abs(a-b) < tol;
|
|
185
|
+
}
|
|
186
|
+
|
|
166
187
|
export {
|
|
167
|
-
supercellGrid, supercellIndex, cellMatrix3, addStaticVar, shiftCpkColor, hashCode
|
|
188
|
+
supercellGrid, supercellIndex, cellMatrix3, addStaticVar, shiftCpkColor, hashCode, floatEqual
|
|
168
189
|
}
|
package/lib/visualizer.js
CHANGED
|
@@ -10,6 +10,8 @@ import * as _ from 'lodash';
|
|
|
10
10
|
import {
|
|
11
11
|
Renderer as Renderer
|
|
12
12
|
} from './render.js';
|
|
13
|
+
// themes
|
|
14
|
+
import {themes} from './render.js';
|
|
13
15
|
import {
|
|
14
16
|
Loader as Loader
|
|
15
17
|
} from './loader.js';
|
|
@@ -45,11 +47,12 @@ class CrystVis {
|
|
|
45
47
|
* @param {int} height Window height. If both this and width are
|
|
46
48
|
* set to 0, the window fits its context and
|
|
47
49
|
* automatically resizes with it
|
|
50
|
+
* @param {Object} rendererOptions Options for the renderer
|
|
48
51
|
*/
|
|
49
|
-
constructor(element, width = 0, height = 0) {
|
|
52
|
+
constructor(element, width = 0, height = 0, rendererOptions = {}) {
|
|
50
53
|
|
|
51
54
|
// Create a renderer
|
|
52
|
-
this._renderer = new Renderer(element, width, height);
|
|
55
|
+
this._renderer = new Renderer(element, width, height, rendererOptions);
|
|
53
56
|
this._loader = new Loader();
|
|
54
57
|
|
|
55
58
|
this._models = {};
|
|
@@ -58,6 +61,7 @@ class CrystVis {
|
|
|
58
61
|
this._current_mname = null;
|
|
59
62
|
this._displayed = null;
|
|
60
63
|
this._selected = null;
|
|
64
|
+
this._notifications = [];
|
|
61
65
|
|
|
62
66
|
// Handling events
|
|
63
67
|
this._atom_click_events = {};
|
|
@@ -158,6 +162,36 @@ class CrystVis {
|
|
|
158
162
|
}
|
|
159
163
|
}
|
|
160
164
|
|
|
165
|
+
get notifications() {
|
|
166
|
+
return this._notifications;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
set notifications(n) {
|
|
170
|
+
this._notifications = n;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
/** Theme
|
|
175
|
+
* @type {object}
|
|
176
|
+
*/
|
|
177
|
+
get theme() {
|
|
178
|
+
return this._renderer.theme;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
set theme(t) {
|
|
182
|
+
// if t is a string, try to find the corresponding theme
|
|
183
|
+
// from the list of themes
|
|
184
|
+
if (typeof t === 'string') {
|
|
185
|
+
if (themes[t]) {
|
|
186
|
+
t = themes[t];
|
|
187
|
+
} else {
|
|
188
|
+
throw new Error('Theme ' + t + ' not found');
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
this._renderer.theme = t;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
|
|
161
195
|
/**
|
|
162
196
|
* Set a callback function for an event where a user clicks on an atom. The
|
|
163
197
|
* function should take as arguments the atom image for the clicked atom and
|
|
@@ -305,6 +339,8 @@ class CrystVis {
|
|
|
305
339
|
* @return {Object} Names of the models we tried to load, and values of true/false for successful loading or not
|
|
306
340
|
*/
|
|
307
341
|
loadModels(contents, format = 'cif', prefix = null, parameters = {}) {
|
|
342
|
+
// clear existing notifications
|
|
343
|
+
this.clearNotifications();
|
|
308
344
|
|
|
309
345
|
parameters = _.merge(model_parameter_defaults, parameters);
|
|
310
346
|
|
|
@@ -320,6 +356,9 @@ class CrystVis {
|
|
|
320
356
|
|
|
321
357
|
if (this._loader.status == Loader.STATUS_ERROR) {
|
|
322
358
|
status[prefix] = this._loader.error_message;
|
|
359
|
+
// display error notification to user
|
|
360
|
+
this.addNotification('Error loading model: '+ prefix);
|
|
361
|
+
this.addNotification(this._loader.error_message);
|
|
323
362
|
return status;
|
|
324
363
|
}
|
|
325
364
|
|
|
@@ -336,6 +375,7 @@ class CrystVis {
|
|
|
336
375
|
var s = structs[n];
|
|
337
376
|
if (!s) {
|
|
338
377
|
status[nn] = 'Model could not load properly';
|
|
378
|
+
this.addNotification('Model '+ nn + ' could not load properly');
|
|
339
379
|
continue;
|
|
340
380
|
}
|
|
341
381
|
this._models[nn] = new Model(s, parameters);
|
|
@@ -352,6 +392,8 @@ class CrystVis {
|
|
|
352
392
|
* @param {Object} parameters Loading parameters as in .loadModels()
|
|
353
393
|
*/
|
|
354
394
|
reloadModel(name, parameters = {}) {
|
|
395
|
+
// clear existing notifications from scene
|
|
396
|
+
this.clearNotifications();
|
|
355
397
|
|
|
356
398
|
if (!(name in this._models)) {
|
|
357
399
|
throw 'The requested model does not exist';
|
|
@@ -382,6 +424,8 @@ class CrystVis {
|
|
|
382
424
|
displayModel(name = null) {
|
|
383
425
|
|
|
384
426
|
if (this._current_model) {
|
|
427
|
+
// clear notifications from previous model
|
|
428
|
+
this.clearNotifications();
|
|
385
429
|
this.selected = this._current_model.view([]);
|
|
386
430
|
this._current_model.renderer = null;
|
|
387
431
|
this._current_model = null;
|
|
@@ -395,6 +439,9 @@ class CrystVis {
|
|
|
395
439
|
}
|
|
396
440
|
|
|
397
441
|
if (!(name in this._models)) {
|
|
442
|
+
// in case the model does not exist, reset the orbit
|
|
443
|
+
this._renderer.resetOrbitCenter(5,5,5);
|
|
444
|
+
this.addNotification('The requested model does not exist')
|
|
398
445
|
throw 'The requested model does not exist';
|
|
399
446
|
}
|
|
400
447
|
|
|
@@ -454,16 +501,60 @@ class CrystVis {
|
|
|
454
501
|
this._renderer.remove(p);
|
|
455
502
|
}
|
|
456
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Add a notification to the list of notifications to be displayed
|
|
506
|
+
*/
|
|
507
|
+
addNotification(n) {
|
|
508
|
+
this._notifications.push(n);
|
|
509
|
+
this.addNotifications();
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Adds all notifications to the drawing
|
|
514
|
+
*
|
|
515
|
+
*/
|
|
516
|
+
addNotifications() {
|
|
517
|
+
// remove displayed notifications
|
|
518
|
+
// (doesn't remove them from this._notifications)
|
|
519
|
+
this._renderer.clearNotifications();
|
|
520
|
+
// add full list of notifications
|
|
521
|
+
this._renderer.addNotifications(this._notifications);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Removes notifications from the drawing
|
|
526
|
+
*/
|
|
527
|
+
clearNotifications() {
|
|
528
|
+
this._notifications = [];
|
|
529
|
+
this._renderer.clearNotifications();
|
|
530
|
+
}
|
|
531
|
+
|
|
457
532
|
/**
|
|
458
533
|
* Recover a data URL of a PNG screenshot of the current scene
|
|
459
534
|
*
|
|
460
535
|
* @return {String} A data URL of the PNG screenshot
|
|
461
536
|
*/
|
|
462
|
-
getScreenshotData() {
|
|
537
|
+
getScreenshotData(transparent = true, scale_pixels = 3) {
|
|
538
|
+
|
|
539
|
+
var renderer = this._renderer;
|
|
540
|
+
// save current alpha and antialias settings
|
|
541
|
+
var old_alpha = renderer._r.getClearAlpha();
|
|
542
|
+
var old_PixelRatio = renderer._r.getPixelRatio();
|
|
543
|
+
|
|
544
|
+
// set new alpha and antialias settings
|
|
545
|
+
renderer._r.setClearAlpha(transparent ? 0 : 1);
|
|
546
|
+
renderer._r.setPixelRatio(scale_pixels);
|
|
547
|
+
|
|
463
548
|
// Force a render
|
|
464
549
|
this._renderer._render();
|
|
465
550
|
// Grab the data from the canvas
|
|
466
|
-
|
|
551
|
+
var data = renderer._r.domElement.toDataURL();
|
|
552
|
+
|
|
553
|
+
// restore old alpha and antialias settings
|
|
554
|
+
renderer._r.setClearAlpha(old_alpha);
|
|
555
|
+
renderer._r.setPixelRatio(old_PixelRatio);
|
|
556
|
+
|
|
557
|
+
return data;
|
|
467
558
|
}
|
|
468
559
|
}
|
|
469
560
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ccp-nc/crystvis-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "A Three.js based crystallographic visualisation tool",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -69,36 +69,36 @@
|
|
|
69
69
|
},
|
|
70
70
|
"homepage": "https://github.com/ccp-nc/crystvis-js#readme",
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@jkshenton/three-bmfont-text": "
|
|
72
|
+
"@jkshenton/three-bmfont-text": "^3.0.5",
|
|
73
73
|
"buffer": "^6.0.3",
|
|
74
74
|
"chroma-js": "^2.4.2",
|
|
75
|
-
"crystcif-parse": "^0.2.9",
|
|
75
|
+
"@ccp-nc/crystcif-parse": "^0.2.9",
|
|
76
76
|
"isosurface": "^1.0.0",
|
|
77
|
-
"jquery": "^3.
|
|
77
|
+
"jquery": "^3.7.1",
|
|
78
78
|
"load-bmfont": "^1.4.1",
|
|
79
79
|
"lodash": "^4.17.21",
|
|
80
|
-
"mathjs": "^
|
|
81
|
-
"three": "^0.
|
|
80
|
+
"mathjs": "^12.3.0",
|
|
81
|
+
"three": "^0.137.0",
|
|
82
82
|
"yargs-parser": "^21.1.1"
|
|
83
83
|
},
|
|
84
84
|
"devDependencies": {
|
|
85
|
-
"@babel/eslint-parser": "^7.
|
|
86
|
-
"chai": "^
|
|
85
|
+
"@babel/eslint-parser": "^7.23.3",
|
|
86
|
+
"chai": "^5.0.0",
|
|
87
87
|
"chai-almost": "^1.0.1",
|
|
88
|
-
"clean-jsdoc-theme": "^4.
|
|
88
|
+
"clean-jsdoc-theme": "^4.2.17",
|
|
89
89
|
"datauri": "^4.1.0",
|
|
90
90
|
"elliptic": ">=6.5.4",
|
|
91
|
-
"esbuild": "^0.
|
|
92
|
-
"eslint": "^8.
|
|
93
|
-
"gh-pages": "^
|
|
94
|
-
"glob": "^
|
|
91
|
+
"esbuild": "^0.19.11",
|
|
92
|
+
"eslint": "^8.56.0",
|
|
93
|
+
"gh-pages": "^6.1.1",
|
|
94
|
+
"glob": "^10.3.10",
|
|
95
95
|
"jpeg-js": ">=0.4.4",
|
|
96
|
-
"jsdoc": "^
|
|
97
|
-
"minimist": "^1.2.
|
|
98
|
-
"mocha": "^10.
|
|
99
|
-
"msdf-bmfont-xml": "^2.
|
|
96
|
+
"jsdoc": "^4.0.2",
|
|
97
|
+
"minimist": "^1.2.8",
|
|
98
|
+
"mocha": "^10.2.0",
|
|
99
|
+
"msdf-bmfont-xml": "^2.7.0",
|
|
100
100
|
"npm-watch": "^0.11.0",
|
|
101
|
-
"serve": "^14.
|
|
101
|
+
"serve": "^14.2.1"
|
|
102
102
|
},
|
|
103
103
|
"overrides": {
|
|
104
104
|
"minimist": "$minimist"
|
package/scripts/build-bundle.js
CHANGED
|
File without changes
|
package/scripts/build-fonts.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import generateBMFont from 'msdf-bmfont-xml';
|
|
2
2
|
import fs from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import glob from 'glob';
|
|
4
|
+
import * as glob from 'glob';
|
|
5
|
+
|
|
5
6
|
|
|
6
7
|
// We update by hand whenever we want to build a new font
|
|
7
8
|
const fontList = [
|
|
8
|
-
'fonts/Rubik/static/Rubik-Medium.ttf'
|
|
9
|
+
'fonts/Rubik/static/Rubik-Medium.ttf',
|
|
10
|
+
'fonts/OpenSans/static/OpenSans/OpenSans-Medium.ttf'
|
|
9
11
|
];
|
|
10
12
|
|
|
13
|
+
const defaultCharset = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩŰ".split('');
|
|
14
|
+
|
|
15
|
+
|
|
11
16
|
const savePath = 'lib/assets/fonts';
|
|
12
17
|
|
|
13
18
|
// Clean up the destination path!
|
|
@@ -19,7 +24,7 @@ old_files.forEach((fname, index) => {
|
|
|
19
24
|
for (var i in fontList) {
|
|
20
25
|
const fname = fontList[i];
|
|
21
26
|
|
|
22
|
-
generateBMFont(fname, (error, textures, font) => {
|
|
27
|
+
generateBMFont(fname, {charset: defaultCharset}, (error, textures, font) => {
|
|
23
28
|
|
|
24
29
|
textures.forEach((texture, index) => {
|
|
25
30
|
|
|
File without changes
|
package/scripts/plugins-shim.js
CHANGED
|
File without changes
|
package/test/chemdata.js
CHANGED
package/test/data/CHA.cif
CHANGED
|
File without changes
|
package/test/data/H2O.xyz
CHANGED
|
File without changes
|
package/test/data/H2_bound.xyz
CHANGED
|
File without changes
|
package/test/data/ethanol.cell
CHANGED
|
File without changes
|
|
File without changes
|
package/test/data/frac.cell
CHANGED
|
File without changes
|
package/test/data/org.cif
CHANGED
|
File without changes
|
package/test/data/pyridine.xyz
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
11
|
|
2
|
-
Pyridine molecule (source: Wikipedia)
|
|
2
|
+
Lattice="10 0 0 0 10 0 0 0 10" Properties=species:S:1:pos:R:3 pbc="T T T" Label="Pyridine molecule (source: Wikipedia)"
|
|
3
3
|
C -0.180226841 0.360945118 -1.120304970
|
|
4
4
|
C -0.180226841 1.559292118 -0.407860970
|
|
5
5
|
C -0.180226841 1.503191118 0.986935030
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
11
|
|
2
|
+
Pyridine molecule (source: Wikipedia)
|
|
3
|
+
C -0.180226841 0.360945118 -1.120304970
|
|
4
|
+
C -0.180226841 1.559292118 -0.407860970
|
|
5
|
+
C -0.180226841 1.503191118 0.986935030
|
|
6
|
+
N -0.180226841 0.360945118 1.685965030
|
|
7
|
+
C -0.180226841 -0.781300882 0.986935030
|
|
8
|
+
C -0.180226841 -0.837401882 -0.407860970
|
|
9
|
+
H -0.180226841 0.360945118 -2.206546970
|
|
10
|
+
H -0.180226841 2.517950118 -0.917077970
|
|
11
|
+
H -0.180226841 2.421289118 1.572099030
|
|
12
|
+
H -0.180226841 -1.699398882 1.572099030
|
|
13
|
+
H -0.180226841 -1.796059882 -0.917077970
|
package/test/data/si8.xyz
CHANGED
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
8
|
|
2
|
+
Lattice="5.47545112629462 4.96819156878786e-36 1.10608096941637e-36 4.96819156878786e-36 5.47545112629462 -3.12695835139248e-36 1.10608096941637e-36 -3.12695835139248e-36 5.47545112629462" Properties=species:S:1:pos:R:3:initial_magmoms:R:1:castep_labels:S:1 pbc="T T T"
|
|
3
|
+
Si 0.00000000 0.00000000 0.00000000 0.00000000 NULL
|
|
4
|
+
Si 4.10658834 4.10658834 1.36886278 0.00000000 NULL
|
|
5
|
+
Si 2.73772556 0.00000000 2.73772556 0.00000000 NULL
|
|
6
|
+
Si 4.10658834 1.36886278 4.10658834 0.00000000 NULL
|
|
7
|
+
Si 0.00000000 2.73772556 2.73772556 0.00000000 NULL
|
|
8
|
+
Si 1.36886278 1.36886278 1.36886278 0.00000000 NULL
|
|
9
|
+
Si 1.36886278 4.10658834 4.10658834 0.00000000 NULL
|
|
10
|
+
Si 2.73772556 2.73772556 -0.00000000 0.00000000 NULL
|
package/test/loader.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
import chai from 'chai'
|
|
3
|
+
import * as chai from 'chai';
|
|
4
4
|
import chaiAlmost from 'chai-almost'
|
|
5
5
|
|
|
6
6
|
import fs from 'fs'
|
|
@@ -55,6 +55,20 @@ describe('#loading', function() {
|
|
|
55
55
|
[1.7848106706548383, 1.959874486240255, 12.914460443940394]
|
|
56
56
|
]);
|
|
57
57
|
});
|
|
58
|
+
it ('should load a noisy .xyz file', function() {
|
|
59
|
+
|
|
60
|
+
var loader = new Loader();
|
|
61
|
+
|
|
62
|
+
var xyz = fs.readFileSync(path.join(__dirname, 'data', 'si8_noisy.xyz'), "utf8");
|
|
63
|
+
var a = loader.load(xyz, 'xyz')['xyz'];
|
|
64
|
+
|
|
65
|
+
expect(a.get_cell()).to.deep.almost.equal([
|
|
66
|
+
[5.475, 0, 0],
|
|
67
|
+
[0, 5.475, 0],
|
|
68
|
+
[0, 0, 5.475]
|
|
69
|
+
]);
|
|
70
|
+
});
|
|
71
|
+
|
|
58
72
|
it('should load properly a Magres file', function() {
|
|
59
73
|
|
|
60
74
|
var loader = new Loader();
|
|
@@ -103,5 +117,12 @@ describe('#loading', function() {
|
|
|
103
117
|
expect(a.get_cell()).to.almost.deep.equal([[10.0, 0, 0], [10.0, 10.0, 0], [0, 0, 10.0]]);
|
|
104
118
|
expect(a.get_positions()[0]).to.almost.deep.equal([10.0, 5.0, 5.0]);
|
|
105
119
|
|
|
120
|
+
|
|
121
|
+
// Test an example with ABC lattice and ABS positions but with bohr units
|
|
122
|
+
cell = fs.readFileSync(path.join(__dirname, 'data', 'bohr.cell'), "utf8");
|
|
123
|
+
a = loader.load(cell, 'cell')['cell'];
|
|
124
|
+
|
|
125
|
+
expect(a.get_cell()).to.almost.deep.equal([[3.7042404756, 0, 0], [0, 3.7042404756, 0], [0, 0, 3.7042404756]]);
|
|
126
|
+
expect(a.get_positions()[1]).to.almost.deep.equal([1.8521202378, 0.0, 0.0]);
|
|
106
127
|
});
|
|
107
128
|
});
|