var state = {}; var localstate = { manual: {}, recipe: 0, page: ['General', 'Dashboard'], maxpoints: 1000 }; var menu_items = [ {name: "General", subitems:[ {name: "Dashboard"}, {name: "Sensors & Plots"} ] }, {name: "Recipes", subitems:[ {name: "Recipes Editor", link: 'recipe-editor'}, {name: "New Recipe"} ] }, {name: "Configuration", subitems:[ {name: "Settings"} ] } ]; function applyState(newstate) { if (newstate !== undefined) { state = JSON.parse(JSON.stringify(newstate)); } // preprocess state.manual["dismissed"] = localstate.manual["dismissed"]; let selected_recipe = null; for (let i = 0; i < state.recipes.length; i++) { state.recipes[i].idx = i; if (localstate.recipe == i) selected_recipe = state.recipes[i]; state.recipes[i].selected = localstate.recipe == i; } state.selected_recipe = JSON.parse(JSON.stringify(selected_recipe)); for (let i = 0; i < menu_items.length; i++) { let group_match = menu_items[i].name == localstate.page[0]; for (let sub = 0; sub < menu_items[i].subitems.length; sub++) { let sub_match = menu_items[i].subitems[sub].name == localstate.page[1]; menu_items[i].subitems[sub].current = group_match && sub_match; menu_items[i].subitems[sub].path = JSON.stringify([ menu_items[i].name, menu_items[i].subitems[sub].name]); } } state.menu_items = menu_items; console.log('Apply state '+JSON.stringify(state)); // apply render_sidebar(state); manual_modal(state.manual); current_recipe(state.recipe); render_load_recipe(state); render_plot(); } var enable_draw = true; var plot_data = {}; function add_plot_data(newpoints, render=true) { for (var i = 0; i < newpoints.length; ++i) { let point = newpoints[i] let key = point[0]; if (!(key in plot_data)) { plot_data[key] = { x: [], y: [], type: 'scatter', name: key } } plot_data[key].x.push(point[1]); plot_data[key].y.push(point[2]); if (plot_data[key].x.length > localstate.maxpoints) { plot_data[key].x.shift(); plot_data[key].y.shift(); } } if (render) render_plot(); } function render_plot() { if (enable_draw && document.getElementById("data-plot") !== null) { Plotly.newPlot('data-plot', Object.values(plot_data)); } } function render_sensors(sensordata) { let html = document.getElementById("sensor-list"); if (state.sensors === undefined || html === null) return; let template = `
{{#sensors}}

{{what}}

{{^data}}No sensors found{{/data}} {{/sensors}}
`; let data = []; for (let i = 0, k = Object.keys(state.sensors.units); i < k.length; ++i) { let what = k[i]; let unit = state.sensors.units[k[i]]; let sensors = Object.keys( Object.keys(state.sensors.found).reduce(function (filtered, key) { if (state.sensors.found[key] == what) filtered[key] = state.sensors.found[key]; return filtered; }, {})); let req_data = []; for (let j = 0; j < sensordata.length; ++j) { if (sensors.includes(sensordata[j][0])) { req_data.push([sensordata[j][0], sensordata[j][2]]); } } data.push({what: what, unit: unit, data: req_data}); } console.log({sensors:data}); html.innerHTML = Mustache.render(template, {sensors:data}); } function navigate(path, link) { console.log(link); localstate.page = path; applyState(); } function render_sidebar(data) { let html = document.getElementById("sidebar"); let template = `` html.innerHTML = Mustache.render(template, data); } function respond_manual(response) { socket.emit('manual response', response); } function select_recipe(idx) { localstate.recipe = idx; applyState(); } function load_recipe() { socket.emit('load recipe idx', localstate.recipe); } function dismiss_modal() { applyState(state); } function render_load_recipe(data) { let html = document.getElementById("load-recipe"); if (html === null) return; let template = `

Load Recipe

{{#selected_recipe}} {{description}} Controllers: {{#controllers}} {{.}} {{/controllers}} {{#phases}}

{{name}}

{{text}}
Ranges: FIXME
On Load: {{onload}}
Exit When: {{nextcond}}
On Exit: {{onexit}}
{{/phases}} {{/selected_recipe}}
` html.innerHTML = Mustache.render(template, data); } function current_recipe(data) { let html = document.getElementById("current-recipe"); if (html === null) return; if (data === null) { html.innerHTML = ''; return; } let template = `

Active Recipe: {{name}}

{{description}}
`; html.innerHTML = Mustache.render(template, data); } function manual_modal(data) { let modal = document.getElementById("manual-modal"); let template = ``; modal.innerHTML = Mustache.render(template, data); } let items = document.querySelectorAll('#items-list > li') items.forEach(item => { $(item).prop('draggable', true) item.addEventListener('dragstart', dragStart) item.addEventListener('drop', dropped) item.addEventListener('dragenter', cancelDefault) item.addEventListener('dragover', cancelDefault) }) function dragStart (e) { var index = $(e.target).index() e.dataTransfer.setData('text/plain', index) } function dropped (e) { cancelDefault(e) // get new and old index let oldIndex = e.dataTransfer.getData('text/plain') let target = $(e.target) let newIndex = target.index() // remove dropped items at old place let dropped = $(this).parent().children().eq(oldIndex).remove() // insert the dropped items at new place if (newIndex < oldIndex) { target.before(dropped) } else { target.after(dropped) } } function cancelDefault (e) { e.preventDefault() e.stopPropagation() return false }