SenchaCon 2016: Ext JS App Modernization Showcase - Richard Milone
SenchaCon 2016: A Data-Driven Application for the Embedded World - Jean-Philippe Ehret
-
Upload
sencha -
Category
Technology
-
view
69 -
download
0
Transcript of SenchaCon 2016: A Data-Driven Application for the Embedded World - Jean-Philippe Ehret
A Data-Driven Application for the Embedded World
Jean-Philippe EHRETLas Vegas, November 6th 2016
A History of User Interfaces...
Embedded Systems’ Humble Beginnings
A simple message, and only this one : “It’s WORKING! Or is it?!”
3
The blinking LED
Embedded Systems’ Evolved
BETTER! But user-friendly?
4
Switches and lights
Expectations Nowadays
5
Interactive data-driven dashboards
Expectations Nowadays
6
Interactive data-driven dashboards
Real Time
Expectations Nowadays
7
Interactive data-driven dashboards
Real Time
Interactive
Expectations Nowadays
8
Interactive data-driven dashboards
Real Time
Interactive
Data Driven
Expectations Nowadays
9
Interactive data-driven dashboards
Real Time
Interactive
Data Driven
Reliable
Expectations Nowadays
10
Interactive data-driven dashboards
Real Time
Interactive
Data Driven
Reliable
And nice looking!
Expectations Nowadays
11
Interactive data-driven dashboards
Real Time
Interactive
Data Driven
Reliable
And nice looking!
NOT ONLYon powerful machines!
Expectations Nowadays
12
Interactive data-driven dashboards
Real Time
Interactive
Data Driven
Reliable
And nice looking!
Everywhere
Hardware Constraints
Embedded Generally Means
You don’t have that…
14
Non-extensible computing power…
Embedded Generally Means
But more something like that!
15
Already limited to start with…
Embedded Generally Means
16
For a slight difference!
EnterpriseServer
EmbeddedEquipment
RAM 32 GB+ 1 MB to 1 GBCPU Core i7, Octo Xeon, etc. ARM
Hard Drive RAID hard drives NopeLocal Storage Several dozens GB Up to a few GB
Embedded Generally Means
17
You don’t have this
Embedded Generally Means
18
You have that
Consequences for Developers
You Have to Be Really Smart!
• Because people want real-time, rich and reactive interfaces- And of course adaptive and working on many kind of devices : tablets, laptops, desktops...
But more something like that
20
You Have to Be Really Smart!
BUT!
21
You Have to Be Really Smart!
• But YOU HAVE GOT very limited resources
22
You Have to Be Really Smart!
• But YOU HAVE GOT very limited resources- The only resources you have are in a few components
But more something like that
23
You Have to Be Really Smart!
AND
24
You Have to Be Really Smart!
• You cannot develop on your computer leaving the question of performance for later:
25
You Have to Be Really Smart!
• You cannot develop on your computer leaving the question of performance for later:
26
Patching an embedded device remotely may just NOT BE POSSIBLE!
Real Life Application
HAGER in a Few WordsBasic stats
12,000 people
€1.6bn ($1.77bn) turnover
HQ in Germany, present in 23 countries
Clients in over 80 countries
Building EfficiencyA large step towards intelligent buildings
Agardio system contributes to the management of low voltage (LV) electrical system:
• Optimizing the building’s energy consumption:- Saving money and preserving the environment
• Maintaining service continuity:- Preventing operational losses
- Providing stable conditions for occupants
Building EfficiencyHager’s Agardio™ system
Building EfficiencyHager’s Agardio™ system
Technical details
Building EfficiencyHager’s Agardio™ system
Target Architecture
How to Include Ext JS in an Embedded Project?
How to Include Ext JS in an Embedded Project?Modularity
• Multilingual and modular across Python backend and Ext JS frontend
How to Include Ext JS in an Embedded Project?No configuration
• Must be available through tablets without any configuration
• Directly served by the equipment
What does it mean in Ext JS?
What does it mean in Ext JS?Sencha CMD
Small Memory FootprintYou definitely want to use Sencha CMD• Tablets will download the application from the equipment
• Heavy app is not such a problem in terms of memory, but the power of the CPU used to deliver the app is a different story
What does it mean in Ext JS?Dynamic Loading
Dynamic LoadingLoad a resource only when neededHager’s product is fully modular:
• Depending on the physical modules installed (light sensor, temperature sensor…), backend and frontend will have different features.
Additionally:
• The new modules can be plugged without any reboot
• Configuration files can be uploaded on-the-fly
• A new piece of UI can serve many purposes across multiple modules
-
Dynamic LoadingLoad a resource only when needed
The magic is that all of this is loaded dynamically like a sort of “plugin” :
• The Ext JS app CANNOT be deployed as a single JS as we are used to.
Dynamic LoadingLoad a resource only when needed
The magic is that all of this is loaded dynamically like a sort of “plugin” :
• The Ext JS app CANNOT be deployed as a single JS as we are used to.
• Each physical module brings its piece of extra Ext JS and resources within a dedicated Ext JS package
Dynamic LoadingLoad a resource only when needed
The magic is that all of this is loaded dynamically like a sort of “plugin” :
• The Ext JS app CANNOT be deployed as a single JS as we are used to.
• Each physical module brings its piece of extra Ext JS and resources within a dedicated Ext JS package
• Sencha CMD is to produce MULTIPLE JavaScript files, one per package / module
What does it mean in Ext JS?Data Driven Dynamic Charts
Data RepresentationMassive usage of d3.js visualizations Why d3.js?
• Hager needed custom visualizations and behaviors
• D3.js was the best pick due to that (SVG low-level building)
Data RepresentationMassive usage of d3.js visualizations Why not Sencha’s implementation?
• The project started before Sencha’s announcement of d3.js native support
Data RepresentationMassive usage of d3.js visualizations What’s next?
• Many issues with browser support due to very different behaviors of the SVG manipulation
• Long-term approach : switch to Sencha’s official implementation
Data RepresentationExt.define('Hes.common.d3.Chart', { extend: 'Ext.Component', xtype: 'd3-chart', fieldMappings: {}, autoEl: { tag: 'svg' }, … onBoxReady: function(…) {…}, createChart:function(w, he) { … this.setChart(this.getChartGenerator(w, he));
… this.getChart().updateChart( Hes.util.Format.storeToD3Data(chartDataStore, this.fieldMappings)); } },…});
Data RepresentationExt.define('Hes.common.d3.Chart', { extend: 'Ext.Component', xtype: 'd3-chart', fieldMappings: {}, autoEl: { tag: 'svg' }, … onBoxReady: function(…) {…}, …
Data DrivenMust deal with various software- modules-specific data
this.setChart( this.getChartGenerator(w, he));…this.getChart().updateChart( Hes.util.Format.storeToD3Data( chartDataStore, this.fieldMappings));
Transform Data to D3 Data
storeToD3Data: function(chartData, fieldMappings) { var data = [];
fieldMappings = fieldMappings || {}; if (chartData && Ext.isFunction(chartData.each)) { chartData.each(function(datum) { var dataObj = datum.data; var seriesData = {}; var dataKeys = Ext.Object.getKeys(dataObj); dataKeys.forEach(function(key) { seriesData[fieldMappings[key] || key] = datum.get(key); }); data.push(seriesData); });} return data;}
Transform Data to D3 Data
storeToD3Data: function(chartData, fieldMappings) { var data = [];
fieldMappings = fieldMappings || {}; if (chartData && Ext.isFunction(chartData.each)) { chartData.each(function(datum) { var dataObj = datum.data; var seriesData = {}; var dataKeys = Ext.Object.getKeys(dataObj); dataKeys.forEach(function(key) { pieData[fieldMappings[key] || key] = datum.get(key); }); data.push(pieData); });} return data;}
To find axis and all important D3 data types
var dataKeys = Ext.Object.getKeys(dataObj); dataKeys.forEach(function(key) { seriesData[fieldMappings[key] || key] =
datum.get(key); });
A Generator
Ext.define('Hes.common.d3.line.LineGenerator', { extend: 'Ext.Base', mixins: ['Ext.mixin.Observable'],…updateChart: function(data) { var seriesFields = this.chartOwner.getSeriesFields() || ['value']; this.data = data; this.seriesData = seriesFields.map(function(fieldName) { return { id: fieldName, values: data.map(function(d) { return { date: d.date, value: d[fieldName] };})};});
… this.svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + this.height + ")") .call(this.xAxis) .append("text") .style("font-size", "1.6em") .attr("y", -this.height) .attr("x", 15) .attr("fill", "#000") .text(this.chartOwner.getXTitle()); this.svg.append("g") .attr("class", "y axis") …
A Generator
Ext.define('Hes.common.d3.line.LineGenerator', { extend: 'Ext.Base', mixins: ['Ext.mixin.Observable'],…updateChart: function(data) { var seriesFields = this.chartOwner.getSeriesFields() || ['value']; this.data = data; this.seriesData = seriesFields.map(function(fieldName) { return { id: fieldName, values: data.map(function(d) { return { date: d.date, value: d[fieldName] };})};});
… this.svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + this.height + ")") .call(this.xAxis) .append("text") .style("font-size", "1.6em") .attr("y", -this.height) .attr("x", 15) .attr("fill", "#000") .text(this.chartOwner.getXTitle()); this.svg.append("g") .attr("class", "y axis") …
updateChartOverride for specific drawing
updateChart:function(data) {…
Data-drivenGeneric whatever is the property
return { date: d.date, value: d[fieldName]}
What does it involve in ExtJS?Dynamic Internationalization
InternationalizationOne app to rule them allWe use an approach with elements on top of Sencha’s official guidelines:
• One multilingual build instead of one build per language
• Dynamic loading to switch language as required
• Easily extendable for multiple language support
• Contents can be translated by non developers through specific products
• No redeployment needed
For more information about internationalization, please read our blogpost on sencha.com
Internationalization
Json result is language specific{"button": "Mon Bouton",
"title": "Mon titre"}
Ext.define('Jnesis.Labels', { singleton: true, button: 'My english button', title: 'My english title'});…Ext.define ('Jnesis.Application', { launch: function () { Ext.Ajax.request({ url: 'get-localization', params:{locale:'fr'}, callback: function (options, success, response) { var data = Ext.decode(response.responseText, true); Ext.override(Jnesis.Labels, data); Ext.create('Jnesis.view.main.Main'); } }); }});
InternationalizationExt.define('Jnesis.Labels', { singleton: true, button: 'My english button', title: 'My english title'});…Ext.define ('Jnesis.Application', { launch: function () { Ext.Ajax.request({ url: 'get-localization', params:{locale:'fr'}, callback: function (options, success, response) { var data = Ext.decode(response.responseText, true); Ext.override(Jnesis.Labels, data); Ext.create('Jnesis.view.main.Main'); } }); }});
Override with selected languageThe singleton gets new values
url: 'get-localization', params:{locale:'fr'},…Ext.override(Jnesis.Labels, data);
InternationalizationExt.define('overrides.localized.Component', { override: 'Ext.Component', initComponent: function() { var me = this, localized = me.localized, value; if (Ext.isObject(localized)) { for (var prop in localized) { value = localized[prop]; if (value) { me[prop] = eval(value); }}} me.callParent(arguments);});
Ext.define('Jnesis.view.main.Main', { extend: 'Ext.panel.Panel', localized: { title: 'Jnesis.Labels.title' }, buttons: [{ localized: { text: 'Jnesis.Labels.button' }, handler: 'onClickButton' }]});
Ext.define('overrides.localized.Component', { override: 'Ext.Component', initComponent: function() { var me = this, localized = me.localized, value; if (Ext.isObject(localized)) { for (var prop in localized) { value = localized[prop]; if (value) { me[prop] = eval(value); }}} me.callParent(arguments);});
Ext.define('Jnesis.view.main.Main', { extend: 'Ext.panel.Panel', localized: { title: 'Jnesis.Labels.title' }, buttons: [{ localized: { text: 'Jnesis.Labels.button' }, handler: 'onClickButton' }]});
Localized property“Bind like” property
localized: { title: 'Jnesis.Labels.title'},
Override Ext Components Ext.define('overrides.localized.Component', { override: 'Ext.Component',
What does it involves in ExtJS?Various Performance Optimizations
Application OptimizationSome best practices for embedding • Don’t blame the backend guy! Every REST call can harm the resources!
• Store locally every time it is possible (inside the end-user device):
Application OptimizationSome best practices for embedding • Don’t blame the backend guy! Every REST call can harm the resources!
• Store locally every time it is possible (inside the end-user device):
duplicate data = need for optimization
Application OptimizationSome best practices for embedding • You have to be reasonable in the use of websocket / SSE data exchanges
Application OptimizationSome best practices for embedding • Don’t forget to ask for compression in the backend!
Application OptimizationSome best practices for embedding • What can be performed on the frontend must be done on the frontend (e.g. CSV export,
data sorting, …)
Is ExtJS Fit for Embedded?
YES! But developers MUST understand what‘s happening behind the scene, although Sencha did a good job sparing this to developers in most other cases.
To Summarize
• Keep in mind that resources are scarce
To Summarize
• Keep in mind that resources are scarce
• Be smart not just comprehensive:
To Summarize
• Keep in mind that resources are scarce
• Be smart not just comprehensive:
- Design modular!
To Summarize
• Keep in mind that resources are scarce
• Be smart not just comprehensive- Design modular!
• Test, re-test, re-re-test before releasing, you work in an embedded system
To Conclude
Making Ext JS work with « Things » is nothing much than legitimate expectation.
To Conclude
Making Ext JS work with « Things » is nothing much than legitimate expectation.
Jnesis is always looking for solutions to use Ext JS wherever it can be in a beneficial way for its clients, check us out at the sponsor zone!