@ccp-nc/crystvis-js 0.6.1 → 0.7.1
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/.mocharc.yml +4 -0
- package/.vscode/settings.json +5 -1
- package/CHANGELOG.md +54 -16
- package/README.md +75 -2
- package/audit.txt +12 -25
- package/changes.txt +1 -26
- package/demo/demo.css +15 -10
- package/demo/index.html +32 -5
- package/demo/main.js +149 -42
- package/lib/formats/magres.js +156 -1
- package/lib/model.js +31 -0
- package/lib/modelview.js +24 -0
- package/lib/render.js +97 -2
- package/lib/selbox.js +18 -4
- package/lib/visualizer.js +237 -1
- package/outdated.txt +9 -12
- package/package.json +7 -5
- package/test/data/hf_mu_test.magres +62 -0
- package/test/data/hf_test.magres +61 -0
- package/test/data/optimized_muon_65-hf.magres +1424 -0
- package/test/loader.js +115 -1
- package/test/model.js +118 -0
- package/test/setup-dom.cjs +147 -0
- package/test/visualizer.js +475 -0
- package/docs/data/search.json +0 -1
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/index.html +0 -10
- package/docs/lib_model.module_js-AtomImage.html +0 -3
- package/docs/lib_model.module_js-BondImage.html +0 -3
- package/docs/lib_model.module_js-Model.html +0 -3
- package/docs/lib_model.module_js.html +0 -3
- package/docs/lib_modelview.module_js-ModelView.html +0 -12
- package/docs/lib_modelview.module_js.html +0 -3
- package/docs/lib_visualizer.module_js-CrystVis.html +0 -3
- package/docs/lib_visualizer.module_js.html +0 -3
- package/docs/model.js.html +0 -2160
- package/docs/modelview.js.html +0 -449
- package/docs/scripts/core.js +0 -726
- package/docs/scripts/core.min.js +0 -23
- package/docs/scripts/resize.js +0 -90
- package/docs/scripts/search.js +0 -265
- package/docs/scripts/search.min.js +0 -6
- package/docs/scripts/third-party/Apache-License-2.0.txt +0 -202
- package/docs/scripts/third-party/fuse.js +0 -9
- package/docs/scripts/third-party/hljs-line-num-original.js +0 -369
- package/docs/scripts/third-party/hljs-line-num.js +0 -1
- package/docs/scripts/third-party/hljs-original.js +0 -5171
- package/docs/scripts/third-party/hljs.js +0 -1
- package/docs/scripts/third-party/popper.js +0 -5
- package/docs/scripts/third-party/tippy.js +0 -1
- package/docs/scripts/third-party/tocbot.js +0 -672
- package/docs/scripts/third-party/tocbot.min.js +0 -1
- package/docs/styles/clean-jsdoc-theme-base.css +0 -1159
- package/docs/styles/clean-jsdoc-theme-dark.css +0 -412
- package/docs/styles/clean-jsdoc-theme-light.css +0 -482
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +0 -30
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +0 -1
- package/docs/styles/clean-jsdoc-theme.min.css +0 -1
- package/docs/tutorial-Events.html +0 -13
- package/docs/tutorial-Queries.html +0 -16
- package/docs/tutorial-ThreejsMigration.html +0 -25
- package/docs/visualizer.js.html +0 -574
package/test/loader.js
CHANGED
|
@@ -259,8 +259,122 @@ H 0.0 1.0 0.0`;
|
|
|
259
259
|
expect(loader.error_message).to.equal('Invalid Magres file format: block opened without closing');
|
|
260
260
|
|
|
261
261
|
});
|
|
262
|
-
it('should load properly a CELL file', function() {
|
|
263
262
|
|
|
263
|
+
it('should parse hyperfine tensors from magres_old block', function() {
|
|
264
|
+
|
|
265
|
+
var loader = new Loader();
|
|
266
|
+
|
|
267
|
+
// Test with the synthetic HF tensor test file (non-zero values)
|
|
268
|
+
var magres = fs.readFileSync(path.join(__dirname, 'data', 'hf_test.magres'), "utf8");
|
|
269
|
+
var a = loader.load(magres, 'magres')['magres'];
|
|
270
|
+
|
|
271
|
+
expect(loader.status).to.equal(Loader.STATUS_SUCCESS);
|
|
272
|
+
expect(a.length()).to.equal(2);
|
|
273
|
+
|
|
274
|
+
// hf array should exist
|
|
275
|
+
var hf = a.get_array('hf');
|
|
276
|
+
expect(hf).to.have.lengthOf(2);
|
|
277
|
+
|
|
278
|
+
// Each entry should be a TensorData object
|
|
279
|
+
expect(hf[0]).to.have.property('data');
|
|
280
|
+
expect(hf[1]).to.have.property('data');
|
|
281
|
+
|
|
282
|
+
// Check H 1 tensor matrix values
|
|
283
|
+
expect(hf[0].data).to.deep.almost.equal([
|
|
284
|
+
[ 1.2345, -0.5678, 0.1234],
|
|
285
|
+
[-0.5678, 2.3456, 0.4567],
|
|
286
|
+
[ 0.1234, 0.4567, 3.4567]
|
|
287
|
+
]);
|
|
288
|
+
|
|
289
|
+
// Check C 1 tensor matrix values
|
|
290
|
+
expect(hf[1].data).to.deep.almost.equal([
|
|
291
|
+
[5.0, 1.0, 0.0],
|
|
292
|
+
[1.0, 5.0, 0.0],
|
|
293
|
+
[0.0, 0.0, 3.0]
|
|
294
|
+
]);
|
|
295
|
+
|
|
296
|
+
// Check isotropic values (trace/3)
|
|
297
|
+
expect(hf[0].isotropy).to.almost.equal((1.2345 + 2.3456 + 3.4567) / 3);
|
|
298
|
+
expect(hf[1].isotropy).to.almost.equal((5.0 + 5.0 + 3.0) / 3);
|
|
299
|
+
|
|
300
|
+
// Check eigenvalues of C 1 (symmetric: known values 3, 4, 6)
|
|
301
|
+
var c_evals = hf[1].eigenvalues;
|
|
302
|
+
expect(c_evals).to.deep.almost.equal([3.0, 4.0, 6.0]);
|
|
303
|
+
|
|
304
|
+
// Check gamma ratios parsed from the synthetic file
|
|
305
|
+
var ratios = a.info['hf-gyromagnetic-ratios'];
|
|
306
|
+
expect(ratios).to.exist;
|
|
307
|
+
expect(ratios['H']).to.exist;
|
|
308
|
+
expect(ratios['H'].isotope).to.equal(1);
|
|
309
|
+
expect(ratios['H'].gamma).to.almost.equal(2.6752e8);
|
|
310
|
+
expect(ratios['C']).to.exist;
|
|
311
|
+
expect(ratios['C'].isotope).to.equal(13);
|
|
312
|
+
expect(ratios['C'].gamma).to.almost.equal(6.7283e7);
|
|
313
|
+
|
|
314
|
+
// Test with optimized_muon_65-hf.magres (real CASTEP output with non-zero HF tensors and H:Mu)
|
|
315
|
+
var muon_magres = fs.readFileSync(path.join(__dirname, 'data', 'optimized_muon_65-hf.magres'), "utf8");
|
|
316
|
+
var am = loader.load(muon_magres, 'magres')['magres'];
|
|
317
|
+
|
|
318
|
+
expect(am.length()).to.equal(69); // 16 H + 1 H:Mu + 28 C + 4 Fe + 2 N + 12 O + 4 S + 2 Br
|
|
319
|
+
|
|
320
|
+
var hf_m = am.get_array('hf');
|
|
321
|
+
expect(hf_m).to.have.lengthOf(69);
|
|
322
|
+
|
|
323
|
+
// All entries should be TensorData objects (not null)
|
|
324
|
+
hf_m.forEach(function(t) {
|
|
325
|
+
expect(t).to.have.property('data');
|
|
326
|
+
expect(t.data).to.have.lengthOf(3);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// H 1 tensor values are non-trivial
|
|
330
|
+
expect(hf_m[0].data).to.deep.almost.equal([
|
|
331
|
+
[-2.5897, 2.2293, 0.4459],
|
|
332
|
+
[ 2.2293, 0.8275, -0.5108],
|
|
333
|
+
[ 0.4459, -0.5108, 0.9140]
|
|
334
|
+
]);
|
|
335
|
+
|
|
336
|
+
// H:Mu 1 is the last atom; check its isotropy
|
|
337
|
+
expect(hf_m[68].isotropy).to.almost.equal(-431.5713);
|
|
338
|
+
|
|
339
|
+
// Gamma ratios should include H:Mu as user-defined
|
|
340
|
+
var ratios_m = am.info['hf-gyromagnetic-ratios'];
|
|
341
|
+
expect(ratios_m['H:Mu'].isotope).to.equal(null);
|
|
342
|
+
expect(ratios_m['H:Mu'].gamma).to.almost.equal(8.5162e8);
|
|
343
|
+
});
|
|
344
|
+
it('should handle custom species (H:Mu) in magres files', function() {
|
|
345
|
+
|
|
346
|
+
var loader = new Loader();
|
|
347
|
+
|
|
348
|
+
var magres = fs.readFileSync(path.join(__dirname, 'data', 'hf_mu_test.magres'), "utf8");
|
|
349
|
+
var a = loader.load(magres, 'magres')['magres'];
|
|
350
|
+
|
|
351
|
+
expect(loader.status).to.equal(Loader.STATUS_SUCCESS);
|
|
352
|
+
expect(a.length()).to.equal(2);
|
|
353
|
+
|
|
354
|
+
// H:Mu should be stored as element H (colon-suffix stripped)
|
|
355
|
+
expect(a.get_chemical_symbols()).to.deep.equal(['H', 'H']);
|
|
356
|
+
|
|
357
|
+
// Both atoms should have HF tensors
|
|
358
|
+
var hf = a.get_array('hf');
|
|
359
|
+
expect(hf).to.have.lengthOf(2);
|
|
360
|
+
expect(hf[0]).to.have.property('data');
|
|
361
|
+
expect(hf[1]).to.have.property('data');
|
|
362
|
+
|
|
363
|
+
// H 1 tensor is diagonal [1,2,3]
|
|
364
|
+
expect(hf[0].eigenvalues).to.deep.almost.equal([1.0, 2.0, 3.0]);
|
|
365
|
+
|
|
366
|
+
// H:Mu 1 tensor was stored (check isotropy ~ -20)
|
|
367
|
+
expect(hf[1].isotropy).to.almost.equal((-10 - 20 - 30) / 3);
|
|
368
|
+
|
|
369
|
+
// Gamma ratios: standard H and user-defined H:Mu
|
|
370
|
+
var ratios = a.info['hf-gyromagnetic-ratios'];
|
|
371
|
+
expect(ratios['H'].isotope).to.equal(1);
|
|
372
|
+
expect(ratios['H'].gamma).to.almost.equal(2.6752e8);
|
|
373
|
+
expect(ratios['H:Mu'].isotope).to.equal(null);
|
|
374
|
+
expect(ratios['H:Mu'].gamma).to.almost.equal(8.5162e8);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
it('should load properly a CELL file', function() {
|
|
264
378
|
var loader = new Loader();
|
|
265
379
|
|
|
266
380
|
var cell = fs.readFileSync(path.join(__dirname, 'data', 'ethanol.cell'), "utf8");
|
package/test/model.js
CHANGED
|
@@ -394,4 +394,122 @@ describe('#modelview', function() {
|
|
|
394
394
|
expect(newMV.length).to.equal(1);
|
|
395
395
|
expect(newMV._indices.sort()).to.deep.equal([72]);
|
|
396
396
|
});
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
// ---------------------------------------------------------------------------
|
|
400
|
+
// Tests: ModelView serialisation (§6.1, §6.3) and Model reconstruction (§6.2, §6.3)
|
|
401
|
+
// ---------------------------------------------------------------------------
|
|
402
|
+
|
|
403
|
+
describe('ModelView#toIndices', function() {
|
|
404
|
+
|
|
405
|
+
it('returns a plain array equal to the view indices', function() {
|
|
406
|
+
var mv = h2omodel.find({ elements: ['O'] });
|
|
407
|
+
var result = mv.toIndices();
|
|
408
|
+
expect(result).to.deep.equal(mv.indices);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it('returns a copy — mutating it does not affect the view', function() {
|
|
412
|
+
var mv = h2omodel.find({ elements: ['O'] });
|
|
413
|
+
var result = mv.toIndices();
|
|
414
|
+
result.push(999);
|
|
415
|
+
expect(mv.indices.length).to.equal(result.length - 1);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
it('returns an empty array for an empty view', function() {
|
|
419
|
+
var mv = h2omodel.view([]);
|
|
420
|
+
expect(mv.toIndices()).to.deep.equal([]);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
describe('ModelView#toLabels', function() {
|
|
426
|
+
|
|
427
|
+
it('returns one crystLabel per atom in the view', function() {
|
|
428
|
+
var mv = h2omodel.find({ elements: ['O'] });
|
|
429
|
+
var labels = mv.toLabels();
|
|
430
|
+
expect(labels).to.be.an('array');
|
|
431
|
+
expect(labels.length).to.equal(mv.length);
|
|
432
|
+
labels.forEach(l => expect(l).to.be.a('string').and.have.length.above(0));
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
it('all labels contain the element symbol', function() {
|
|
436
|
+
var mv = h2omodel.find({ elements: ['H'] });
|
|
437
|
+
mv.toLabels().forEach(l => expect(l).to.match(/^H/));
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
it('returns an empty array for an empty view', function() {
|
|
441
|
+
var mv = h2omodel.view([]);
|
|
442
|
+
expect(mv.toLabels()).to.deep.equal([]);
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('round-trips: toLabels then viewFromLabels gives the same indices', function() {
|
|
446
|
+
// Use a multi-site structure for a meaningful round-trip
|
|
447
|
+
var mv = chamodel.find({ elements: ['O'] });
|
|
448
|
+
var labels = mv.toLabels();
|
|
449
|
+
var restored = chamodel.viewFromLabels(labels);
|
|
450
|
+
expect(restored.indices.sort((a,b)=>a-b))
|
|
451
|
+
.to.deep.equal(mv.indices.slice().sort((a,b)=>a-b));
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
describe('Model#viewFromIndices', function() {
|
|
457
|
+
|
|
458
|
+
it('produces a view with exactly the specified indices', function() {
|
|
459
|
+
var indices = [0, 2, 4];
|
|
460
|
+
var mv = h2omodel.viewFromIndices(indices);
|
|
461
|
+
expect(mv.indices).to.deep.equal(indices);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('is equivalent to model.view(indices)', function() {
|
|
465
|
+
var indices = [1, 3];
|
|
466
|
+
var a = h2omodel.viewFromIndices(indices);
|
|
467
|
+
var b = h2omodel.view(indices);
|
|
468
|
+
expect(a.indices).to.deep.equal(b.indices);
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
it('defaults to an empty view when called with no arguments', function() {
|
|
472
|
+
var mv = h2omodel.viewFromIndices();
|
|
473
|
+
expect(mv.length).to.equal(0);
|
|
474
|
+
});
|
|
475
|
+
|
|
476
|
+
it('round-trips with toIndices()', function() {
|
|
477
|
+
var original = h2omodel.find({ elements: ['H'] });
|
|
478
|
+
var restored = h2omodel.viewFromIndices(original.toIndices());
|
|
479
|
+
expect(restored.indices).to.deep.equal(original.indices);
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('Model#viewFromLabels', function() {
|
|
485
|
+
|
|
486
|
+
it('finds atoms matching the given labels', function() {
|
|
487
|
+
var mv = chamodel.find({ elements: ['Si'] });
|
|
488
|
+
var labels = mv.toLabels();
|
|
489
|
+
var restored = chamodel.viewFromLabels(labels);
|
|
490
|
+
expect(restored.length).to.equal(mv.length);
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
it('returns an empty view for an empty label array', function() {
|
|
494
|
+
var mv = chamodel.viewFromLabels([]);
|
|
495
|
+
expect(mv.length).to.equal(0);
|
|
496
|
+
});
|
|
497
|
+
|
|
498
|
+
it('ignores unknown labels', function() {
|
|
499
|
+
// Grab a real label dynamically, then mix it with a nonsense one
|
|
500
|
+
var validLabel = chamodel._atom_images[0].crystLabel;
|
|
501
|
+
var mv = chamodel.viewFromLabels([validLabel, 'DOES_NOT_EXIST']);
|
|
502
|
+
expect(mv.length).to.be.greaterThan(0);
|
|
503
|
+
mv.toLabels().forEach(l => expect(l).to.not.equal('DOES_NOT_EXIST'));
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
it('round-trips with toLabels() across a different supercell model', function() {
|
|
507
|
+
// Use the unit-cell model to get labels, then restore on the same model
|
|
508
|
+
var mv = chamodel.find({ elements: ['O'] });
|
|
509
|
+
var labels = mv.toLabels();
|
|
510
|
+
var restored = chamodel.viewFromLabels(labels);
|
|
511
|
+
expect(restored.indices.sort((a,b)=>a-b))
|
|
512
|
+
.to.deep.equal(mv.indices.slice().sort((a,b)=>a-b));
|
|
513
|
+
});
|
|
514
|
+
|
|
397
515
|
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* test/setup-dom.cjs
|
|
3
|
+
*
|
|
4
|
+
* Mocha --require hook (CommonJS) that installs a minimal jsdom window as
|
|
5
|
+
* global so that DOM-dependent ES modules (THREE.js texture loader, jQuery,
|
|
6
|
+
* etc.) can be imported in the Node.js test environment without crashing.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { JSDOM } = require('jsdom');
|
|
12
|
+
|
|
13
|
+
const dom = new JSDOM('<!DOCTYPE html><html><body><div id="crystvis"></div></body></html>', {
|
|
14
|
+
pretendToBeVisual: true,
|
|
15
|
+
resources: 'usable',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// Helper: set a global, falling back to Object.defineProperty for read-only
|
|
19
|
+
// properties (e.g. navigator in Node.js 23+).
|
|
20
|
+
function setGlobal(name, value) {
|
|
21
|
+
try {
|
|
22
|
+
global[name] = value;
|
|
23
|
+
} catch (_) {
|
|
24
|
+
Object.defineProperty(global, name, { value, writable: true, configurable: true });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Expose browser globals expected by THREE.js, jQuery, etc.
|
|
29
|
+
setGlobal('window', dom.window);
|
|
30
|
+
setGlobal('document', dom.window.document);
|
|
31
|
+
setGlobal('navigator', dom.window.navigator);
|
|
32
|
+
setGlobal('HTMLElement', dom.window.HTMLElement);
|
|
33
|
+
setGlobal('HTMLCanvasElement', dom.window.HTMLCanvasElement);
|
|
34
|
+
setGlobal('Image', dom.window.Image);
|
|
35
|
+
setGlobal('ImageData', dom.window.ImageData);
|
|
36
|
+
setGlobal('XMLHttpRequest', dom.window.XMLHttpRequest);
|
|
37
|
+
setGlobal('requestAnimationFrame', (cb) => setTimeout(cb, 16));
|
|
38
|
+
setGlobal('cancelAnimationFrame', (id) => clearTimeout(id));
|
|
39
|
+
setGlobal('ResizeObserver', class ResizeObserver {
|
|
40
|
+
observe() {}
|
|
41
|
+
unobserve() {}
|
|
42
|
+
disconnect() {}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Stub WebGL context so THREE.WebGLRenderer does not crash on getContext()
|
|
46
|
+
const canvasProto = dom.window.HTMLCanvasElement.prototype;
|
|
47
|
+
const _origGetContext = canvasProto.getContext;
|
|
48
|
+
canvasProto.getContext = function (type, ...args) {
|
|
49
|
+
if (type === 'webgl' || type === 'webgl2' || type === 'experimental-webgl') {
|
|
50
|
+
// Return a minimal WebGL stub that THREE can interrogate without causing
|
|
51
|
+
// errors. Only the methods referenced during renderer initialisation
|
|
52
|
+
// need to be present.
|
|
53
|
+
return {
|
|
54
|
+
canvas: this,
|
|
55
|
+
drawingBufferWidth: 300,
|
|
56
|
+
drawingBufferHeight: 150,
|
|
57
|
+
getExtension: () => null,
|
|
58
|
+
getParameter: () => null,
|
|
59
|
+
getShaderPrecisionFormat: () => ({ rangeMin: 127, rangeMax: 127, precision: 23 }),
|
|
60
|
+
createTexture: () => ({}),
|
|
61
|
+
bindTexture: () => {},
|
|
62
|
+
texParameteri: () => {},
|
|
63
|
+
pixelStorei: () => {},
|
|
64
|
+
enable: () => {},
|
|
65
|
+
disable: () => {},
|
|
66
|
+
blendEquation: () => {},
|
|
67
|
+
blendFunc: () => {},
|
|
68
|
+
depthFunc: () => {},
|
|
69
|
+
depthMask: () => {},
|
|
70
|
+
colorMask: () => {},
|
|
71
|
+
clearColor: () => {},
|
|
72
|
+
clearDepth: () => {},
|
|
73
|
+
clearStencil: () => {},
|
|
74
|
+
scissor: () => {},
|
|
75
|
+
viewport: () => {},
|
|
76
|
+
clear: () => {},
|
|
77
|
+
useProgram: () => {},
|
|
78
|
+
frontFace: () => {},
|
|
79
|
+
cullFace: () => {},
|
|
80
|
+
createBuffer: () => ({}),
|
|
81
|
+
bindBuffer: () => {},
|
|
82
|
+
bufferData: () => {},
|
|
83
|
+
createFramebuffer: () => ({}),
|
|
84
|
+
bindFramebuffer: () => {},
|
|
85
|
+
createRenderbuffer: () => ({}),
|
|
86
|
+
bindRenderbuffer: () => {},
|
|
87
|
+
renderbufferStorage: () => {},
|
|
88
|
+
framebufferRenderbuffer: () => {},
|
|
89
|
+
framebufferTexture2D: () => {},
|
|
90
|
+
createProgram: () => ({}),
|
|
91
|
+
createShader: () => ({}),
|
|
92
|
+
shaderSource: () => {},
|
|
93
|
+
compileShader: () => {},
|
|
94
|
+
attachShader: () => {},
|
|
95
|
+
linkProgram: () => {},
|
|
96
|
+
getProgramParameter: (p, pname) => {
|
|
97
|
+
// LINK_STATUS
|
|
98
|
+
if (pname === 35714) return true;
|
|
99
|
+
return null;
|
|
100
|
+
},
|
|
101
|
+
getShaderParameter: () => true,
|
|
102
|
+
getUniformLocation: () => ({}),
|
|
103
|
+
getAttribLocation: () => 0,
|
|
104
|
+
uniform1i: () => {},
|
|
105
|
+
uniform1f: () => {},
|
|
106
|
+
uniform2f: () => {},
|
|
107
|
+
uniform3f: () => {},
|
|
108
|
+
uniform4f: () => {},
|
|
109
|
+
uniformMatrix3fv: () => {},
|
|
110
|
+
uniformMatrix4fv: () => {},
|
|
111
|
+
vertexAttribPointer: () => {},
|
|
112
|
+
enableVertexAttribArray: () => {},
|
|
113
|
+
disableVertexAttribArray: () => {},
|
|
114
|
+
drawArrays: () => {},
|
|
115
|
+
drawElements: () => {},
|
|
116
|
+
deleteBuffer: () => {},
|
|
117
|
+
deleteTexture: () => {},
|
|
118
|
+
deleteProgram: () => {},
|
|
119
|
+
deleteShader: () => {},
|
|
120
|
+
deleteFramebuffer: () => {},
|
|
121
|
+
deleteRenderbuffer: () => {},
|
|
122
|
+
isContextLost: () => false,
|
|
123
|
+
getError: () => 0,
|
|
124
|
+
// WebGL2 extras
|
|
125
|
+
createVertexArray: () => ({}),
|
|
126
|
+
bindVertexArray: () => {},
|
|
127
|
+
deleteVertexArray: () => {},
|
|
128
|
+
texImage2D: () => {},
|
|
129
|
+
texImage3D: () => {},
|
|
130
|
+
texStorage2D: () => {},
|
|
131
|
+
texStorage3D: () => {},
|
|
132
|
+
blitFramebuffer: () => {},
|
|
133
|
+
readBuffer: () => {},
|
|
134
|
+
drawBuffers: () => {},
|
|
135
|
+
renderbufferStorageMultisample: () => {},
|
|
136
|
+
createSampler: () => ({}),
|
|
137
|
+
deleteSampler: () => {},
|
|
138
|
+
bindSampler: () => {},
|
|
139
|
+
samplerParameteri: () => {},
|
|
140
|
+
samplerParameterf: () => {},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (_origGetContext) {
|
|
144
|
+
return _origGetContext.call(this, type, ...args);
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
};
|