Versi terbaru Ext JS, terutama Modern Toolkit, menurunkan ambang batas untuk memasuki kerangka kerja (contoh Kitchen Sink), menyederhanakan pembuatan antarmuka yang diinginkan (Hai Sencha Architect), dan mencapai ukuran minimum untuk aplikasi web (Sencha Cmd).
Mungkin, Habr harus diencerkan dengan contoh penerapan "pusat situasional", di mana secara real time Anda dapat menonton kamera dan acara dari mereka (semua data palsu).

Mari kita mulai. Mari kita membuat proyek Spring Boot dengan 2 pengontrol yang akan memberikan daftar kamera, acara yang ada, serta kemampuan untuk berlangganan acara baru (melalui WebSocket).

Selanjutnya, tambahkan model, penyimpanan, tampilan, dan dependensi eksternal yang diperlukan:

Secara lebih rinci, tampilan peta berinteraksi dengan komponen Bereaksi peta.Ext.define('Cameras.view.override.Map', { override: 'Cameras.view.Map', config: { cameras: {}, react: null }, initialize: function() { let that = this; let e = React.createElement; this.setReact(ReactDOM.render(e(createReactClass({ getInitialState: function() { return { items: [], center: [55.751574, 37.573856]}; }, render: function() { let placemarks = []; for(let i=0; i < this.state.items.length; i++) { let location = this.state.items[i].get("location"); placemarks.push(e(window.ReactYandexMaps.Placemark, { geometry: [location.latitude, location.longitude], options: { preset: 'islands#blueCircleDotIconWithCaption', iconCaptionMaxWidth: '50' } })); } let map = e(window.ReactYandexMaps.Map, { state: { center: this.state.center, zoom: 10 }, width: '100%', height: '100%' }, placemarks); return e(window.ReactYandexMaps.YMaps, null, map); } })), this.mapContainer.dom)); }, getElementConfig: function() { return { reference: 'element', className: 'x-container', children: [{ reference: 'bodyElement', style: 'width: 100%; height: 100%', className: 'x-inner', children: [{ style: 'width: 100%; height: 100%', reference: 'mapContainer', className: Ext.baseCSSPrefix + 'map-container' }] }] }; }, addCamera: function(cameraModel) { if(!this.containsCamera(cameraModel)) { this.getCameras()[cameraModel.get("id")] = cameraModel; this.getReact().setState({ items: Object.values(this.getCameras()) }); this.fitCamera(cameraModel); } }, removeCamera: function(cameraModel) { if(this.containsCamera(cameraModel)) { delete this.getCameras()[cameraModel.get("id")]; this.getReact().setState({ items: Object.values(this.getCameras()) }); } }, fitCamera: function(cameraModel) { if(this.containsCamera(cameraModel)) { let location = this.getCameras()[cameraModel.get("id")].get("location"); this.getReact().setState({ center: [location.latitude, location.longitude] }); } }, privates: { containsCamera: function(cameraModel) { cameraId = "" + cameraModel.get("id"); return Object.keys(this.getCameras()).includes(cameraId); } } });
Kami juga setuju bahwa acara tersebut akan datang dari komponen CamerasGrid, seperti komponen inilah yang bertanggung jawab untuk menambah / menghapus kamera dari kartu.
Pengontrol komponen CamerasGrid yang menambahkan pembuatan acara ke komponen Ext.define('Cameras.view.CamerasGridViewController', { extend: 'Ext.app.ViewController', alias: 'controller.camerasgrid', init: function() { let socket = new WebSocket("ws://localhost:8080/events/sub"); socket.onopen = function(e) { console.log('onopen'); }; socket.onmessage = this.onMessage.bind(this); }, onMessage: function(event) { let data = Ext.decode(event.data); let gridData = this.getView().getStore().getData(); for(let i=0; i < gridData.length; i++) { let checked = gridData.getAt(i).get("checked"); if(checked !== undefined && checked) { if(gridData.getAt(i).get("id") == data.camera.id) { this.fireViewEvent("cameraRecognition", data); } } } } });
Hasilnya adalah antarmuka yang agak menghibur. Saya perhatikan bahwa dengan desain arsitektur aplikasi yang tepat (bahkan yang kecil), waktu untuk membuatnya sangat kecil, hingga beberapa jam.

Kode contoh tersedia di
github.com .