From 4fe1c8813348cd6d35672e1e72fc4535fde127bf Mon Sep 17 00:00:00 2001 From: Alex Lalejini Date: Tue, 9 Jun 2020 18:22:51 -0400 Subject: [PATCH] Add find_function to library_d3.js, start re-implementing SelectionOrTransition wrapper --- source/web/d3/library_d3.js | 6 +++ source/web/d3/selection.h | 102 ++++++++++++++++++++++++++++++++++++ source/web/d3/test.cc | 7 +++ 3 files changed, 115 insertions(+) create mode 100644 source/web/d3/selection.h diff --git a/source/web/d3/library_d3.js b/source/web/d3/library_d3.js index 45ccf92063..cf7eee3863 100644 --- a/source/web/d3/library_d3.js +++ b/source/web/d3/library_d3.js @@ -2,6 +2,12 @@ var D3Library = { $emp_d3: {objects: {}, counts: {}, next_id:0}, get_emp_d3: function() { return this.emp_d3; + }, + find_function: function(sel) { + return (window["d3"][sel] === "function") ? window["d3"][sel] : + (window["emp"][sel] === "function") ? window["emp"][sel] : + (window[sel] === "function") ? window[sel] : + sel; } }; diff --git a/source/web/d3/selection.h b/source/web/d3/selection.h new file mode 100644 index 0000000000..f235f8626b --- /dev/null +++ b/source/web/d3/selection.h @@ -0,0 +1,102 @@ +// This file is part of Empirical, https://github.com/devosoft/Empirical +// Copyright (C) Michigan State University, 2016-2020. +// Released under the MIT Software license; see doc/LICENSE + +#ifndef __SELECTION_H__ +#define __SELECTION_H__ + +#include "d3_init.h" + +#include +#include +#include +#include +#include + +#include "../../base/assert.h" +#include "../js_utils.h" +#include "../JSWrap.h" + +namespace D3 { + +namespace internal { + + /// You probably never want to instantiate this class. Its sole purpose is to hold code for + /// methods that are common to selections and transitions. + /// + /// Developer note: It's also handy if you want to allow a function to accept either a selection + /// or transition. This is a good idea any time you are only using methods that are applicable to + /// either, and the person calling the function may want to animate its results. + template + class SelectionOrTransition : public D3_Base { + public: + + SelectionOrTransition() { ; } + SelectionOrTransition(int id) : D3_Base(id) { ; } + SelectionOrTransition(const SelectionOrTransition & s) : D3_Base(s) { ; } + + /// Create a new selection/transition containing the first element matching the + /// [selector] string that are within this current selection/transition + DERIVED Select(const std::string & selector) const { + const int new_id = NextD3ID(); + + EM_ASM({ + const id = $0; + const selector = UTF8ToString($1); + const new_id = $2; + var new_selection = emp_d3.objects[id].select(selector); + emp_d3.objects[new_id] = new_selection; + }, this->id, selector.c_str(), new_id); + + return DERIVED(new_id); + } + + /// Create a new selection/transition containing all elements matching the [selector] + /// string that are within this current selection/transition + DERIVED SelectAll(const std::string & selector) const { + const int new_id = NextD3ID(); + + EM_ASM({ + const id = $0; + const selector = UTF8ToString($1); + const new_id = $2; + var new_selection = emp_d3.objects[id].selectAll(selector); + emp_d3.objects[new_id] = new_selection; + }, this->id, selector.c_str(), new_id); + + return DERIVED(new_id); + } + + // TODO - Consider re-implementing the 'Call' wrapper but allow for arbitrary arguments to the + // function being called. + + /// Returns a new selection/transition, representing the current selection/transition + /// filtered by [selector]. [selector] can be a C++ function that returns a bool, a + /// string representing a function in either the d3, emp, or window namespaces that + /// returns a bool, or a string containing a selector to filter by. + /// + /// For more information see the + /// [D3 documentation](https://github.com/d3/d3-3.x-api-reference/blob/master/Selections.md#filter) + DERIVED Filter(const std::string & selector) const { + const int new_id = NextD3ID(); + + EM_ASM({ + const id = $0; + const new_id = $1; + const selector_str = UTF8ToString($2); + var sel = emp_d3.find_function(selector_str); + emp_d3.objects[new_id] = emp_d3.objects[id].filter(sel); + }, this->id, new_id, selector.c_str()); + + return DERIVED(new_id); + } + + + + }; + +} + +} + +#endif diff --git a/source/web/d3/test.cc b/source/web/d3/test.cc index b295d1f825..bae3e5ed35 100644 --- a/source/web/d3/test.cc +++ b/source/web/d3/test.cc @@ -8,14 +8,21 @@ #include "web/init.h" #include "web/Document.h" #include "d3_init.h" +#include "selection.h" // namespace UI = emp::web; // UI::Document doc("emp_d3_test"); +// EM_JS(const char*, hello, (), { +// const js_str = "Hello World!"; +// return js_str; +// }); + int main() { D3::internal::get_emp_d3(); size_t id = D3::internal::NextD3ID(); std::cout << "This is the ID you got: " << id << std::endl; + // std::cout << "This string is from javascript: " << hello() << std::endl; } \ No newline at end of file