neo.mjs 4.0.2 → 4.0.5

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.
@@ -1,4 +1,17 @@
1
1
  [
2
+ {
3
+ "author" : "Tobias Uhlig",
4
+ "authorImage" : "author_TobiasUhlig.jpeg",
5
+ "date" : "Apr 13, 2022",
6
+ "id" : 52,
7
+ "image" : "safari-now-fully-supports-sharedworkers.png",
8
+ "name" : "Safari now fully supports SharedWorkers",
9
+ "provider" : "Medium",
10
+ "publisher" : "ITNEXT",
11
+ "selectedInto": [],
12
+ "type" : "Blog Post",
13
+ "url" : "https://itnext.io/safari-now-fully-supports-sharedworkers-534733b56b4c?source=friends_link&sk=97b83b39629cf79dbe8feff0042c19b3"
14
+ },
2
15
  {
3
16
  "author" : "Tobias Uhlig",
4
17
  "authorImage" : "author_TobiasUhlig.jpeg",
@@ -0,0 +1,38 @@
1
+ import Button from '../../../../src/button/Base.mjs';
2
+ import CesiumJSComponent from '../../../../src/component/wrapper/CesiumJS.mjs';
3
+ import MainContainerController from './MainContainerController.mjs';
4
+ import Toolbar from '../../../../src/container/Toolbar.mjs';
5
+ import Viewport from '../../../../src/container/Viewport.mjs';
6
+
7
+ /**
8
+ * @class Neo.examples.component.wrapper.cesiumJS.MainContainer
9
+ * @extends Neo.container.Viewport
10
+ */
11
+ class MainContainer extends Viewport {
12
+ static getConfig() {return {
13
+ className : 'Neo.examples.component.wrapper.cesiumJS.MainContainer',
14
+ autoMount : true,
15
+ controller: MainContainerController,
16
+ layout : {ntype: 'vbox', align: 'stretch'},
17
+
18
+ items: [{
19
+ module : CesiumJSComponent,
20
+ flex : 1,
21
+ reference: 'cesium-component'
22
+ }, {
23
+ module: Toolbar,
24
+ flex : 'none',
25
+ style : {margin: '20px'},
26
+ items : [{
27
+ module : Button,
28
+ handler: 'onFlyToButtonClick',
29
+ iconCls: 'fa-solid fa-plane',
30
+ text : 'Fly to San Fran'
31
+ }]
32
+ }]
33
+ }}
34
+ }
35
+
36
+ Neo.applyClassConfig(MainContainer);
37
+
38
+ export default MainContainer;
@@ -0,0 +1,30 @@
1
+ import ComponentController from '../../../../src/controller/Component.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.component.wrapper.cesiumJS.MainContainerController
5
+ * @extends Neo.controller.Component
6
+ */
7
+ class MainContainerController extends ComponentController {
8
+ static getConfig() {return {
9
+ /**
10
+ * @member {String} className='Neo.examples.component.wrapper.cesiumJS.MainContainerController'
11
+ * @protected
12
+ */
13
+ className: 'Neo.examples.component.wrapper.cesiumJS.MainContainerController'
14
+ }}
15
+
16
+ /**
17
+ * @param {Object} data
18
+ */
19
+ onFlyToButtonClick(data) {
20
+ this.getReference('cesium-component').flyTo({
21
+ destination: [-122.4175, 37.655, 400],
22
+ heading : 0.0,
23
+ pitch : -15.0
24
+ });
25
+ }
26
+ }
27
+
28
+ Neo.applyClassConfig(MainContainerController);
29
+
30
+ export default MainContainerController;
@@ -0,0 +1,7 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.component.wrapper.cesiumJS'
6
+ });
7
+
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Neo CesiumJS Component</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,8 @@
1
+ {
2
+ "appPath" : "examples/component/wrapper/cesiumJS/app.mjs",
3
+ "basePath" : "../../../../",
4
+ "cesiumJsToken" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI4NGY3Y2YyNi1hODY3LTQ2YmMtYWIzNS01NzIxOTM5YzQ5MTUiLCJpZCI6MjQ3NDAsInNjb3BlcyI6WyJhc3IiLCJnYyJdLCJpYXQiOjE1ODU2OTUzMjB9._j_owvL1zmT8KMPPWEWknoryJCIdVL8bY_E3vgoN8KI",
5
+ "environment" : "development",
6
+ "mainPath" : "./Main.mjs",
7
+ "mainThreadAddons": ["CesiumJS", "Stylesheet"]
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "4.0.2",
3
+ "version": "4.0.5",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -34,6 +34,15 @@ const DefaultConfig = {
34
34
  * @type String
35
35
  */
36
36
  basePath: './',
37
+ /**
38
+ * Pass a token in case you are using the CesiumJS main thread addon
39
+ * See: https://github.com/neomjs/neo/blob/dev/src/main/addon/CesiumJS.mjs
40
+ * @default null
41
+ * @memberOf! module:Neo
42
+ * @name config.cesiumJsToken
43
+ * @type String|null
44
+ */
45
+ cesiumJsToken: null,
37
46
  /**
38
47
  * The current environment. Valid values: 'development', 'dist/development', 'dist/production'
39
48
  * This config will get auto-generated
@@ -44,7 +53,7 @@ const DefaultConfig = {
44
53
  */
45
54
  environment: 'dist/production',
46
55
  /**
47
- * In case you are using the GoogleAnalytics mainThreadAddon or useGoogleAnalytics: true,
56
+ * In case you are using the GoogleAnalytics main thread addon or useGoogleAnalytics: true,
48
57
  * you can change the gtag id here. Required for the online examples (gh pages)
49
58
  * @default 'UA-153734404-1'
50
59
  * @memberOf! module:Neo
package/src/Main.mjs CHANGED
@@ -170,7 +170,7 @@ class Main extends core.Base {
170
170
  availWidth : screen.availWidth,
171
171
  colorDepth : screen.colorDepth,
172
172
  height : screen.height,
173
- orientation: {angle: screen.orientation.angle, type: screen.orientation.type},
173
+ orientation: {angle: screen.orientation?.angle, type: screen.orientation?.type},
174
174
  pixelDepth : screen.pixelDepth,
175
175
  width : screen.width
176
176
  },
@@ -0,0 +1,104 @@
1
+ import Component from '../Base.mjs';
2
+
3
+ /**
4
+ * Convenience class to render a CesiumJS component
5
+ * Requires adding the CesiumJS main thread addon
6
+ * @class Neo.component.wrapper.CesiumJS
7
+ * @extends Neo.component.Base
8
+ */
9
+ class CesiumJS extends Component {
10
+ static getConfig() {return {
11
+ /**
12
+ * @member {String} className='Neo.component.wrapper.CesiumJS'
13
+ * @protected
14
+ */
15
+ className: 'Neo.component.wrapper.CesiumJS',
16
+ /**
17
+ * @member {String} ntype='cesiumjs-component'
18
+ * @protected
19
+ */
20
+ ntype: 'cesiumjs-component',
21
+ /**
22
+ * @member {Boolean} createOsmBuildings=true
23
+ */
24
+ createOsmBuildings: true,
25
+ /**
26
+ * @member {Object} _vdom
27
+ */
28
+ _vdom:
29
+ {style: {position: 'relative', height: '100%', width: '100%'}, cn: [
30
+ {style: {position: 'absolute', height: '100%', width: '100%'}, }
31
+ ]}
32
+ }}
33
+
34
+ /**
35
+ * Triggered after the mounted config got changed
36
+ * @param {Boolean} value
37
+ * @param {Boolean} oldValue
38
+ * @protected
39
+ */
40
+ afterSetMounted(value, oldValue) {
41
+ let me = this;
42
+
43
+ if (value === false && oldValue !== undefined) {
44
+ Neo.main.addon.CesiumJS.destroy({
45
+ appName: me.appName,
46
+ id : me.id
47
+ });
48
+ }
49
+
50
+ super.afterSetMounted(value, oldValue);
51
+
52
+ if (value) {
53
+ let opts = {
54
+ appName : me.appName,
55
+ createOsmBuildings: me.createOsmBuildings,
56
+ id : me.id
57
+ };
58
+
59
+ setTimeout(() => {
60
+ Neo.main.addon.CesiumJS.create(opts).then(() => {
61
+ me.onComponentMounted();
62
+ });
63
+ }, 50);
64
+ }
65
+ }
66
+
67
+ /**
68
+ * @param {Object} data
69
+ * @param {Number[]} data.destination
70
+ * @param {Number} data.heading
71
+ * @param {Number} data.pitch
72
+ */
73
+ flyTo(data) {
74
+ Neo.main.addon.CesiumJS.flyTo({
75
+ ...data,
76
+ id: this.id
77
+ });
78
+ }
79
+
80
+ /**
81
+ *
82
+ */
83
+ getVdomRoot() {
84
+ return this.vdom.cn[0];
85
+ }
86
+
87
+ /**
88
+ *
89
+ */
90
+ getVnodeRoot() {
91
+ return this.vnode.childNodes[0];
92
+ }
93
+
94
+ /**
95
+ *
96
+ */
97
+ onComponentMounted() {
98
+ console.log('onComponentMounted', this.id);
99
+ }
100
+ }
101
+
102
+ Neo.applyClassConfig(CesiumJS);
103
+
104
+ export default CesiumJS;
@@ -169,7 +169,7 @@ class Xhr extends Base {
169
169
  if (!opts.url) {
170
170
  console.error('Neo.Xhr.request without a given url' + JSON.stringify(opts));
171
171
  } else {
172
- if (!opts.insideNeo && location.href.includes('/node_modules/neo.mjs/') && !location.href.includes('https://neomjs.github.io/')) {
172
+ if (!opts.insideNeo && location.href.includes('/node_modules/neo.mjs/') && !location.href.startsWith('https://neomjs.github.io/')) {
173
173
  if (opts.url.startsWith('./') || opts.url.startsWith('../')) {
174
174
  opts.url = '../../' + opts.url;
175
175
  }
@@ -61,11 +61,12 @@ class Card extends Base {
61
61
  * @protected
62
62
  */
63
63
  async afterSetActiveIndex(value, oldValue) {
64
- let me = this,
65
- containerId = me.containerId,
66
- container = Neo.getComponent(containerId) || Neo.get(containerId), // the instance might not be registered yet
67
- sCfg = me.getStaticConfig(),
68
- needsUpdate = false,
64
+ let me = this,
65
+ containerId = me.containerId,
66
+ container = Neo.getComponent(containerId) || Neo.get(containerId), // the instance might not be registered yet
67
+ sCfg = me.getStaticConfig(),
68
+ needsUpdate = false,
69
+ removeInactiveCards = me.removeInactiveCards,
69
70
  cls, i, isActiveIndex, item, items, len, module, proto, vdom;
70
71
 
71
72
  if (Neo.isNumber(value) && container) {
@@ -119,14 +120,14 @@ class Card extends Base {
119
120
  NeoArray.remove(cls, isActiveIndex ? sCfg.inactiveItemCls : sCfg.activeItemCls);
120
121
  NeoArray.add( cls, isActiveIndex ? sCfg.activeItemCls : sCfg.inactiveItemCls);
121
122
 
122
- if (me.removeInactiveCards || needsUpdate) {
123
+ if (removeInactiveCards || needsUpdate) {
123
124
  item._cls = cls; // silent update
124
125
  item.getVdomRoot().cls = cls;
125
126
 
126
127
  if (isActiveIndex) {
127
128
  delete item.vdom.removeDom;
128
129
  item.activate?.();
129
- } else {
130
+ } else if (removeInactiveCards) {
130
131
  item.mounted = false;
131
132
  item.vdom.removeDom = true;
132
133
  }
@@ -136,7 +137,7 @@ class Card extends Base {
136
137
  }
137
138
  }
138
139
 
139
- if (me.removeInactiveCards || needsUpdate) {
140
+ if (removeInactiveCards || needsUpdate) {
140
141
  container.vdom = vdom;
141
142
  }
142
143
  }
@@ -0,0 +1,126 @@
1
+ import Base from '../../core/Base.mjs';
2
+ import DomAccess from '../DomAccess.mjs';
3
+
4
+ /**
5
+ * See: https://github.com/CesiumGS/cesium
6
+ * @class Neo.main.addon.CesiumJS
7
+ * @extends Neo.core.Base
8
+ * @singleton
9
+ */
10
+ class CesiumJS extends Base {
11
+ /**
12
+ * @member {Object} viewers={}
13
+ * @protected
14
+ */
15
+ viewers = {}
16
+
17
+ static getConfig() {return {
18
+ /**
19
+ * @member {String} className='Neo.main.addon.CesiumJS'
20
+ * @protected
21
+ */
22
+ className: 'Neo.main.addon.CesiumJS',
23
+ /**
24
+ * Remote method access for other workers
25
+ * @member {Object} remote
26
+ * @protected
27
+ */
28
+ remote: {
29
+ app: [
30
+ 'create',
31
+ 'createOsmBuildings',
32
+ 'destroy',
33
+ 'flyTo'
34
+ ]
35
+ },
36
+ /**
37
+ * @member {Boolean} singleton=true
38
+ * @protected
39
+ */
40
+ singleton: true
41
+ }}
42
+
43
+ /**
44
+ * @param {Object} config
45
+ */
46
+ construct(config) {
47
+ super.construct(config);
48
+ this.loadFiles();
49
+ }
50
+
51
+ /**
52
+ * @param {Object} data
53
+ * @param {Boolean} data.createOsmBuildings
54
+ * @param {String} data.id
55
+ */
56
+ create(data) {
57
+ this.viewers[data.id] = new Cesium.Viewer(data.id, {
58
+ terrainProvider: Cesium.createWorldTerrain()
59
+ });
60
+
61
+ data.createOsmBuildings && this.createOsmBuildings({
62
+ id: data.id
63
+ });
64
+ }
65
+
66
+ /**
67
+ * @param {Object} data
68
+ * @param {String} data.id
69
+ */
70
+ createOsmBuildings(data) {
71
+ this.viewers[data.id].scene.primitives.add(Cesium.createOsmBuildings());
72
+ }
73
+
74
+ /**
75
+ * @param {Object} data
76
+ * @param {String} data.id
77
+ */
78
+ destroy(data) {
79
+ // todo
80
+ console.log('main.addon.CesiumJS: destroy()', data);
81
+ }
82
+
83
+ /**
84
+ * @param {Object} data
85
+ * @param {Number[]} data.destination
86
+ * @param {Number} data.heading
87
+ * @param {String} data.id
88
+ * @param {Number} data.pitch
89
+ */
90
+ flyTo(data) {
91
+ this.viewers[data.id].camera.flyTo({
92
+ destination: Cesium.Cartesian3.fromDegrees(...data.destination),
93
+ orientation: {
94
+ heading: Cesium.Math.toRadians(data.heading),
95
+ pitch : Cesium.Math.toRadians(data.pitch),
96
+ }
97
+ });
98
+ }
99
+
100
+ /**
101
+ * @protected
102
+ */
103
+ loadFiles() {
104
+ Promise.all([
105
+ DomAccess.loadScript( 'https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Cesium.js'),
106
+ DomAccess.loadStylesheet('https://cesium.com/downloads/cesiumjs/releases/1.92/Build/Cesium/Widgets/widgets.css')
107
+ ]).then(() => {
108
+ this.onFilesLoaded();
109
+ });
110
+ }
111
+
112
+ /**
113
+ *
114
+ */
115
+ onFilesLoaded() {
116
+ Cesium.Ion.defaultAccessToken = Neo.config.cesiumJsToken;
117
+ }
118
+ }
119
+
120
+ Neo.applyClassConfig(CesiumJS);
121
+
122
+ let instance = Neo.create(CesiumJS);
123
+
124
+ Neo.applyToGlobalNs(instance);
125
+
126
+ export default instance;
@@ -0,0 +1,40 @@
1
+ import Base from './Base.mjs';
2
+
3
+ /**
4
+ * @class Neo.manager.RemotesApi
5
+ * @extends Neo.manager.Base
6
+ * @singleton
7
+ */
8
+ class RemotesApi extends Base {
9
+ static getConfig() {return {
10
+ /**
11
+ * @member {String} className='Neo.manager.RemotesApi'
12
+ * @protected
13
+ */
14
+ className: 'Neo.manager.RemotesApi',
15
+ /**
16
+ * @member {Boolean} singleton=true
17
+ * @protected
18
+ */
19
+ singleton: true
20
+ }}
21
+
22
+ /**
23
+ *
24
+ * @param msg
25
+ * @returns {Promise<any>}
26
+ */
27
+ async onMessage(msg) {
28
+ let response = await Neo.Fetch.get(msg);
29
+
30
+ return response;
31
+ }
32
+ }
33
+
34
+ Neo.applyClassConfig(RemotesApi);
35
+
36
+ let instance = Neo.create(RemotesApi);
37
+
38
+ Neo.applyToGlobalNs(instance);
39
+
40
+ export default instance;
@@ -37,15 +37,15 @@ class Canvas extends Base {
37
37
  *
38
38
  */
39
39
  afterConnect() {
40
- let me = this,
41
- channel = new MessageChannel(),
42
- port = channel.port2;
40
+ let me = this,
41
+ channel = new MessageChannel(),
42
+ {port1, port2} = channel;
43
43
 
44
- channel.port1.onmessage = me.onMessage.bind(me);
44
+ port1.onmessage = me.onMessage.bind(me);
45
45
 
46
- me.sendMessage('app', {action: 'registerPort', transfer: port}, [port]);
46
+ me.sendMessage('app', {action: 'registerPort', transfer: port2}, [port2]);
47
47
 
48
- me.channelPorts.app = channel.port1;
48
+ me.channelPorts.app = port1;
49
49
  }
50
50
 
51
51
  /**
@@ -14,6 +14,12 @@ import Xhr from '../Xhr.mjs';
14
14
  * @singleton
15
15
  */
16
16
  class Data extends Base {
17
+ /**
18
+ * @member {Boolean} remotesManagerLoaded=false
19
+ * @protected
20
+ */
21
+ remotesManagerLoaded = false
22
+
17
23
  static getConfig() {return {
18
24
  /**
19
25
  * @member {String} className='Neo.worker.Data'
@@ -36,15 +42,15 @@ class Data extends Base {
36
42
  *
37
43
  */
38
44
  afterConnect() {
39
- let me = this,
40
- channel = new MessageChannel(),
41
- port = channel.port2;
45
+ let me = this,
46
+ channel = new MessageChannel(),
47
+ {port1, port2} = channel;
42
48
 
43
- channel.port1.onmessage = me.onMessage.bind(me);
49
+ port1.onmessage = me.onMessage.bind(me);
44
50
 
45
- me.sendMessage('app', {action: 'registerPort', transfer: port}, [port]);
51
+ me.sendMessage('app', {action: 'registerPort', transfer: port2}, [port2]);
46
52
 
47
- me.channelPorts.app = channel.port1;
53
+ me.channelPorts.app = port1;
48
54
  }
49
55
 
50
56
  /**
@@ -57,21 +63,33 @@ class Data extends Base {
57
63
  /**
58
64
  * @param {Object} msg
59
65
  */
60
- async onRpc(msg) {
61
- console.log('onRpc', msg);
62
-
63
- let response = await Neo.Fetch.get(msg);
66
+ onRegisterNeoConfig(msg) {
67
+ super.onRegisterNeoConfig(msg);
64
68
 
65
- this.resolve(msg, response);
69
+ Neo.config.remotesApiUrl && import('../manager/RemotesApi.mjs').then(module => {
70
+ this.remotesManagerLoaded = true
71
+ })
66
72
  }
67
73
 
68
74
  /**
69
- * Just for testing
70
- * @param {Number} ms
71
- * @returns {Promise<unknown>}
75
+ * @param {Object} msg
72
76
  */
73
- timeout(ms) {
74
- return new Promise(resolve => setTimeout(resolve, ms));
77
+ async onRpc(msg) {
78
+ console.log('onRpc', msg);
79
+
80
+ let me = this,
81
+ response;
82
+
83
+ if (!me.remotesManagerLoaded) {
84
+ // todo: we could store calls which arrive too early and pass them to the manager once it is ready
85
+ console.warn('manager.RemotesApi not loaded yet', msg);
86
+
87
+ me.reject(msg);
88
+ } else {
89
+ response = await Neo.manager.RemotesApi.onMessage(msg);
90
+
91
+ me.resolve(msg, response);
92
+ }
75
93
  }
76
94
  }
77
95
 
@@ -160,21 +160,25 @@ class Manager extends Base {
160
160
  * Calls createWorker for each worker inside the this.workers config.
161
161
  */
162
162
  createWorkers() {
163
- let me = this,
164
- hash = location.hash,
163
+ let me = this,
164
+ config = Neo.clone(NeoConfig, true),
165
+ hash = location.hash,
165
166
  key, value;
166
167
 
168
+ // remove configs which are not relevant for the workers scope
169
+ delete config.cesiumJsToken;
170
+
167
171
  // pass the initial hash value as Neo.configs
168
172
  if (hash) {
169
- NeoConfig.hash = {
173
+ config.hash = {
170
174
  hash : DomEvents.parseHash(hash.substr(1)),
171
175
  hashString: hash.substr(1)
172
176
  };
173
177
  }
174
178
 
175
179
  for ([key, value] of Object.entries(me.workers)) {
176
- if (key === 'canvas' && !NeoConfig.useCanvasWorker ||
177
- key === 'vdom' && !NeoConfig.useVdomWorker
180
+ if (key === 'canvas' && !config.useCanvasWorker ||
181
+ key === 'vdom' && !config.useVdomWorker
178
182
  ) {
179
183
  continue;
180
184
  }
@@ -189,7 +193,7 @@ class Manager extends Base {
189
193
 
190
194
  me.sendMessage(key, {
191
195
  action: 'registerNeoConfig',
192
- data : NeoConfig
196
+ data : config
193
197
  });
194
198
  }
195
199
  }
@@ -116,18 +116,18 @@ class ServiceBase extends Base {
116
116
  * @param {Client} client
117
117
  */
118
118
  createMessageChannel(client) {
119
- let me = this,
120
- channel = new MessageChannel(),
121
- port = channel.port2;
119
+ let me = this,
120
+ channel = new MessageChannel(),
121
+ {port1, port2} = channel;
122
122
 
123
- channel.port1.onmessage = me.onMessage.bind(me);
123
+ port1.onmessage = me.onMessage.bind(me);
124
124
 
125
- me.sendMessage('app', {action: 'registerPort', transfer: port}, [port]);
125
+ me.sendMessage('app', {action: 'registerPort', transfer: port2}, [port2]);
126
126
 
127
127
  me.channelPorts.push({
128
128
  clientId : client.id,
129
129
  destination: 'app',
130
- port : channel.port1
130
+ port : port1
131
131
  });
132
132
  }
133
133
 
@@ -35,11 +35,11 @@ class VDom extends Base {
35
35
  afterConnect() {
36
36
  let me = this,
37
37
  channel = new MessageChannel(),
38
- port = channel.port2;
38
+ {port2} = channel;
39
39
 
40
40
  channel.port1.onmessage = me.onMessage.bind(me);
41
41
 
42
- me.sendMessage('app', {action: 'registerPort', transfer: port}, [port]);
42
+ me.sendMessage('app', {action: 'registerPort', transfer: port2}, [port2]);
43
43
  }
44
44
  }
45
45