diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6bba7a6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +{ + "files.associations": { + "*.ipp": "cpp", + "array": "cpp", + "atomic": "cpp", + "complex": "cpp", + "deque": "cpp", + "list": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "iterator": "cpp", + "memory_resource": "cpp", + "optional": "cpp", + "string_view": "cpp", + "rope": "cpp", + "slist": "cpp", + "initializer_list": "cpp", + "stop_token": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "valarray": "cpp" + } +} \ No newline at end of file diff --git a/cpp/lib/telegraph/local/dummy_device.cpp b/cpp/lib/telegraph/local/dummy_device.cpp index ebfd461..830a57d 100644 --- a/cpp/lib/telegraph/local/dummy_device.cpp +++ b/cpp/lib/telegraph/local/dummy_device.cpp @@ -55,6 +55,9 @@ namespace telegraph { std::vector labels{"On", "Off"}; auto status_type = value_type("Status", std::move(labels)); auto childC = new variable(4, "c", "C", "", status_type); + + auto childD = new variable(5, "d", "D", "", value_type::Bool); + std::vector test_labels = {"option1", "option2", "option3"}; value_type test_enum = value_type("test_enum", test_labels); @@ -67,17 +70,21 @@ namespace telegraph { auto action4 = new action(4, "action4", "action4", "", test_enum, test_enum); auto action5 = new action(5, "action5", "action5", "", short_enum, short_enum); - std::vector children{childA, childB, childC, action1, action2, action3, action4, action5}; + std::vector children{childA, childB, childC, childD, action1, action2, action3, action4, action5}; auto root = std::make_unique(1, "foo", "Foo", "", "", 1, std::move(children)); auto dev = std::make_shared(ioc, name, std::move(root)); auto a_publisher = std::make_shared(ioc, value_type::Float); auto b_publisher = std::make_shared(ioc, value_type::Int32); auto c_publisher= std::make_shared(ioc, status_type); + auto d_publisher= std::make_shared(ioc, value_type::Bool); + dev->add_publisher(childA, a_publisher); dev->add_publisher(childB, b_publisher); dev->add_publisher(childC, c_publisher); + dev->add_publisher(childD, d_publisher); + // add action dev->add_handler(action1, [] (io::yield_ctx& yield, value val) -> value { @@ -133,6 +140,19 @@ namespace telegraph { val++; } }); + + io::spawn(ioc, [&ioc, w, d_publisher](io::yield_context yield) { + // create a timer + io::deadline_timer timer{ioc}; + bool val= false; + while (true) { + timer.expires_from_now(boost::posix_time::seconds(2)); + timer.async_wait(yield); + { auto dev = w.lock(); if (!dev) break; } + (*d_publisher) << value{val}; + val = !val; + } + }); return dev; } } \ No newline at end of file diff --git a/gui/src/dashboard/Control.vue b/gui/src/dashboard/Control.vue index 87983f1..1ee788d 100644 --- a/gui/src/dashboard/Control.vue +++ b/gui/src/dashboard/Control.vue @@ -1,6 +1,6 @@ @@ -31,6 +33,7 @@ import FlatButton from "../components/FlatButton.vue"; import NumberField from "../components/NumberField.vue"; import { NamespaceQuery, Variable } from "telegraph"; import TimeChart from 'timechart' +import interact from "interactjs"; export default { @@ -44,8 +47,10 @@ export default { data() { return { variables: [], - history: [], + history: [[]], chart: null, + srs: [], + currColor: 'blue', timespan: 20, useTimespan: true, @@ -64,7 +69,7 @@ export default { }, nodeQuery() { return this.nsQuery.contexts - .extract((x) => x.name == this.history.ctx) + .extract((x) => x.name == this.history[0].ctx) .fetch() .fromPath(this.data.node); }, @@ -80,12 +85,29 @@ export default { this.width = this.$refs["chart-container"].offsetWidth; this.height = this.$refs["chart-container"].offsetHeight; this.setup(); + interact(this.$refs["chart-container"]) + .dropzone({ + overlap: "pointer", + accept: ".node-bubble", + }) + .on("dragenter", (event) => { + this.dragOver = true; + }) + .on("dragleave", (event) => { + this.dragOver = false; + }) + .on("drop", (event) => { + this.drop(event.interaction.data); + }); }, unmounted() {}, methods: { setup() { + this.srs.push({ name : 'Series 1', data: this.history[0], color: 'blue' }); this.chart = new TimeChart(this.$refs["chart"], { - series: [{ name : 'Series 1', data: this.history, color: 'blue' }], + // series: [ + // { name : 'Series 1', data: this.history[0], color: 'blue' }], + series: this.srs, realTime: true, baseTime: Date.now() - performance.now(), xRange: { min: 0, max: 20 * 1000 }, @@ -95,6 +117,7 @@ export default { this.chart.model.resize(this.width, this.height); }, toggleLive() { + this.live = !this.live; }, updateTimespan() { }, @@ -102,6 +125,43 @@ export default { }, updateVariable(v) { }, + drop(data) { + this.chart.dispose(); + this.history.push([]); + // console.log(this.history.length); + this.nextColor(); + + this.srs.push({ + name : ('Series '+(this.history.length)), + data: this.history[this.history.length-1], + color: this.currColor}); + + + this.chart = new TimeChart(this.$refs["chart"], { + series: this.srs, + realTime: true, + baseTime: Date.now() - performance.now(), + xRange: { min: 0, max: 20 * 1000 }, + }); + + this.chart.update(); + }, + nextColor() { + switch (this.currColor) { + case 'blue': + this.currColor = 'red'; + break; + case 'red': + this.currColor = 'yellow'; + break; + case 'yellow': + this.currColor = 'blue'; + break; + default: + this.currColor = 'red'; + } + } + }, watch: { nodeQuery(n, o) { @@ -113,7 +173,13 @@ export default { // callback for adding data setInterval(() => { const time = performance.now(); - this.history.push({x: time, y: Math.sin(time * 0.002)}); + var yVal = Math.sin(time * 0.002); + // this.history[0].push({x: time, y: yVal}); + if (this.live) { + for (let i = 0; i < this.history.length; i++) { + this.history[i].push({x : time, y : (yVal + i)}); + } + } this.chart.update(); }, 100); this.nodeQuery.register(this.updateVariable); diff --git a/gui/src/dashboard/GraphMinMax.vue b/gui/src/dashboard/GraphMinMax.vue new file mode 100644 index 0000000..52d2367 --- /dev/null +++ b/gui/src/dashboard/GraphMinMax.vue @@ -0,0 +1,332 @@ + + + + + + + diff --git a/gui/src/dashboard/Placeholder.vue b/gui/src/dashboard/Placeholder.vue index b658804..c7f4de6 100644 --- a/gui/src/dashboard/Placeholder.vue +++ b/gui/src/dashboard/Placeholder.vue @@ -3,12 +3,14 @@
@@ -28,8 +30,9 @@ export default { height: null, // TODO: Make a registry options: [ - { type: "ControlPanel", icon: "sliders-h" }, - { type: "Graph", icon: "chart-bar" }, + { type: "ControlPanel", icon: "sliders-h", title: "Control Panel"}, + { type: "Graph", icon: "chart-bar", title: "Graph"}, + { type: "GraphMinMax", icon: "chart-line", title: "Min/Max Graph"}, ], }; }, diff --git a/gui/src/main.js b/gui/src/main.js index 14e3d4c..28fd5bb 100644 --- a/gui/src/main.js +++ b/gui/src/main.js @@ -28,6 +28,7 @@ import { faSatelliteDish, faCircle, faSquare, + fas, } from "@fortawesome/free-solid-svg-icons"; import { faTrashAlt } from "@fortawesome/free-regular-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"; @@ -56,7 +57,8 @@ library.add( faCircle, faSquare, faPlay, - faClock + faClock, + fas ); Vue.component("font-awesome-icon", FontAwesomeIcon);