I am using the Dabeng Orgchart library, but I would like to customize the nodes, specifically creating a diamond instead of the squares they have in most examples. I have seen the createNode method, and I have found various CSS for creating a diamond but I can't figure out how to integrate it in dabeng org chart. What I want to do is display a diamond if some conditions are met, and the default square shapes if others are met. I have searched the web, but no example for changing the shape.
I am currently using the nodeTemplate attribute for the orgchart. Example:
var oc = $('#container').orgchart({
...
'nodeTemplate': orgTemplate,
...
});
In your orgtemplate function, data is whatever you have included in your orgchart data (in the example it would be name and title). You can stuff this object with other flags. For example, I have a chart in which I create new nodes and allow users to enter data into the node before committing it to the graph. I have a flag in my data object for data.isSaved to tell my template whether or not this node is saved or not. If it is saved, I have inline html checks (in AngularJS using ngIf's and the like, if you're familiar with AngularJS at all) to change the template based on the data.
In VanillaJS, you can just return pure HTML without the $compile and all that attached to pump in your own node template. You could actually do your check within the function for example:
function orgTemplate(data) {
if(data.isDiamond) {
return '<div class="diamond">...</div>';
} else {
return '<div class="square">...</div>';
}
}
I'm using AngularJS in my website so I define new scopes and use angular directives to make it more expandable. This is for reference for anyone else who stumbles upon this. My orgTemplate function is defined below.
function orgTemplate(data) {
var newScope = $scope.$new(true);
newScope.data = data;
return ( $compile('<div data-ng-include="\'.../template.html\'"></div>')(newScope));
}
Here's the orgChart Github as I'm sure you've browsed many times. If you look at the bottom you will see the nodeTemplate attribute definition I mention above. Hope this helps!
Side Note: I have had some trouble with styling when using custom templates, especially when defining different graph directions (i.e. 'l2r').
You can now customize your own node structure or shape with option "ndoeTemplate":
var nodeTemplate = function(data) {
return `
<span class="office">${data.office}</span>
<div class="title">${data.name}</div>
<div class="content">${data.title}</div>
`;
}
var oc = $('#chart-container').orgchart({
'data' : ds,
'nodeTemplate': nodeTemplate
});
Feel free to play around with this demo.
I would suggest you to use getorgchart instead it is highly customizable
http://www.getorgchart.com/Demos/Create-Your-Own-Theme-4
Related
So, I am doing a small project in Google Apps Script, to make adding/exporting leads from it...less painful.
How do I plan to do this?
I plan on doing this via adding some Actions menu, for the importing and exporting of leads. The imported sheet will, for now, be assumed to be of the same columns as the Google Sheet this script is bound to. (We can support some sheet column conversion features later, but it's probably a YAGNI for my use case.) The exported sheet will be converted from the columns of this sheet, to some simplified, ready-to-send-to-the-mailers columns.
How do I plan to code this (or how am I coding this)?
I am using MVVM design pattern, and have spent last night plugging away at writing MVVM wrappers for everything that I need to (keeping KISS in mind).
The MenuItemViewModels have some name,functionName that the Google Apps Script seem to be looking for. I note that there is some major pain-in-the-ass limitation, though: Google Apps Script wants function NAME and it cannot be method!
OK, show me some code or gtfo
I have some SpreadsheetPageViewModel that look like this:
class SpreadsheetPageViewModel extends BaseViewModel {
init() {
this.exportVM = new ExportSpreadsheetEditViewModel();
this.importVM = new ImportSpreadsheetEditViewModel();
this.menuVM = new MenuViewModel(new MenuModel(),
[
'exportLeads', // this is utility function. I want/need to use openExport method
'importLeads', // this is utility function. I want/need to use openImport method
]);
this.childEditVM = null;
}
openExport() {
this.childEditVM = this.exportVM;
this.childEditVM.view.doShow();
}
openImport() {
this.childEditVM = this.importVM;
this.childEditVM.view.doShow();
}
}
The business logic for the modals that spawn on menu item click, will live in the child view models to this: the ExportSpreadsheetEditViewModel and ImportSpreadsheetEditViewModel.
I was trying to get around the limitation via this hack:
changing
function onOpen(event) {
// show the menu here....
new SpreadsheetPageView().doShow();
}
to something like:
var mainView;
function onOpen(event) {
mainView = new SpreadsheetPageView();
// show the menu here....
mainView.doShow();
}
and then, in the MenuActionUtils.gs, crawling down that mainView like:
function exportLeads() {
mainView.viewModel.showExport();
}
function importLeads() {
mainView.viewModel.showImport();
}
What was the result of that hack?
It didn't work. Why? Because when Google Apps Script fired that exportLeads (or importLeads), mainView was no longer defined!!
Does this mean I have to give up my approach?
How can I use the main view/view model in the onClick of the menu items?
Failing all that, is there a way to create our menu, using this MVVM design pattern (and some HTML/React/....), and inject it in?
By using Google Apps Script it's not possible to modify the look and feel of a Google Workspace editor (Docs, Forms, Sheets, Slides) custom menu, in other words, it's not possible to use HTML/React for this but you might use them in dialogs/sidebars.
Regarding using a design pattern, you might use any design pattern that you want but you should have in mind that every time that a Google Apps Script is triggered by an event the whole project is loaded, so if you need that some objects persist between events then you should find a place to save those objects.
To store an object you might use the Google Apps Script Properties Service and/or the Cache Service, just bear in mind that you should convert it to JSON before saving it. Also you might use a Google spreadsheet but this has several limitations or you might use an external service, i.e. nosql database, by using Google Apps Script URL Fetch service.
Related
using and modifying global variables within handler functions
Styling a custom spreadsheet menu item using Google Apps Script
How to define global variable in Google Apps Script
Google Apps Script (V8); why can't I use an object instance inside of onOpen?
With #Ruben's help, I was able to get this working!
What I did
I didn't give up on the MVVM/OOP design.
Instead, I created singleton static method on the drive class, like so:
static GetMainInstance() {
if (!this._mainInstance) {
this._mainInstance = new this();
}
return this._mainInstance;
}
and use it instead of directly creating the new drive object.
Also, it is view's responsibility to spawn stuff, so I did some refactoring:
In PageView.gs I added the following methods:
showExport() {
this.viewModel.showExport((childVM) => {
this.editView.viewModel = childVM;
this.editView.doShow();
})
}
showImport() {
this.viewModel.showImport((childVM) => {
this.editView.viewModel = childVM;
this.editView.doShow();
})
}
in the PageViewModel.gs, I changed the methods to accept onDone callback:
showExport(onDone) {
this.childEditVM = this.exportVM;
onDone(this.childEditVM);
}
showImport(onDone) {
this.childEditVM = this.importVM;
onDone(this.childEditVM);
}
Simple fix, it works, while staying consistent with the principles!
First, I am fairly unfamiliar with javascript and its library d3.js, but I am familiar with R. Creating dashboards using Shiny has been fun and easy (thanks to stackoverflow). Now I want to expand it by connect d3 elements to it.
I'm looking for information sources on how to actually bind javascript to Shiny (R dashboard) and explain what is actually going on.
Background:
I did the tutorial on js and jquery on w3schools and learned (a bit) about d3 using Scott Murray's book (Interactive Data visualization for the web). I hoped this would be enough to make me understand the examples and explanation concerning how to build custom input/output bindings on the Shiny website:
http://shiny.rstudio.com/articles/building-inputs.html
But unfortunately I don't and I can't seem to find any examples which are in minimal working code. Many examples on github are to complex for me to dissect, most probably because of my little experience with javascript. Here is an examples of custom input binding with javascript:
https://github.com/jcheng5/shiny-js-examples/tree/master/input
Here is an example of an input & output binding I try to unfold:
<script src="http://d3js.org/d3.v3.js"></script>
<script type="text/javascript">
(function(){
// Probably not idiomatic javascript.
this.countValue=0;
// BEGIN: FUNCTION
updateView = function(message) {
var svg = d3.select(".d3io").select("svg")
svg.append("text")
.transition()
.attr("x",message[0])
.attr("y",message[1])
.text(countValue)
.each("end",function(){
if(countValue<100) {
countValue+=1;
$(".d3io").trigger("change");
}
})
}
// END: FUNCTION
//BEGIN: OUTPUT BINDING
var d3OutputBinding = new Shiny.OutputBinding();
$.extend(d3OutputBinding, {
find: function(scope) {
return $(scope).find(".d3io");
},
renderError: function(el,error) {
console.log("Foe");
},
renderValue: function(el,data) {
updateView(data);
console.log("Friend");
}
});
Shiny.outputBindings.register(d3OutputBinding);
//END: OUTPUT BINDING
//BEGIN: INPUT BINDING
var d3InputBinding = new Shiny.InputBinding();
$.extend(d3InputBinding, {
find: function(scope) {
return $(scope).find(".d3io");
},
getValue: function(el) {
return countValue;
},
subscribe: function(el, callback) {
$(el).on("change.d3InputBinding", function(e) {
callback();
});
}
});
Shiny.inputBindings.register(d3InputBinding);
//END: OUTPUT BINDING
})()
</script>
Where "d3io" is a div element in the ui, updateView() is a function. Here is the ui:
#UI
library(shiny)
d3IO <- function(inputoutputID) {
div(id=inputoutputID,class=inputoutputID,tag("svg","")) #; eerst zat ; erbij, maar werkt blijkbaar ook zonder
}
# Define UI for shiny d3 chatter application
shinyUI(pageWithSidebar(
# Application title
headerPanel("D3 Javascript chatter",
"Demo of how to create D3 I/O and cumulative data transfer"),
sidebarPanel(
tags$p("This widget is a demonstration of how to wire shiny direct to javascript, without any input elements."),
tags$p("Each time a transition ends, the client asks the server for another packet of information, and adds it
to the existing set"),
tags$p("I can't claim this is likely to be idiomatic javascript, because I'm a novice, but it allows d3 apps
to do progressive rendering. In real use, a more complex request/response protocol will probably be
required. -AlexBBrown")
),
mainPanel(
includeHTML("d3widget.js"),
d3IO("d3io") #Creates div element that d3 selects
)
))
Here is the server file:
# SERVER
library(shiny)
# Define server logic required to respond to d3 requests
shinyServer(function(input, output) {
# Generate a plot of the requested variable against mpg and only
# include outliers if requested
output$d3io <- reactive(function() {
if (is.null(input$d3io)) {
0;
} else {
list(rnorm(1)*400+200,rnorm(1)*400+200);
}
})
})
Specific questions:
1) The server.r seems to get input called "d3io" (input$d3io) since this is not defined in ui.r, I reasoned it must come from the javascript file. Which element does it actually refer to?
2) I have trouble understanding the custom binding part:
var d3OutputBinding = new Shiny.OutputBinding();
$.extend(d3OutputBinding, {
find: function(scope) {
return $(scope).find(".d3io");
},
renderError: function(el,error) {
console.log("Foe");
},
renderValue: function(el,data) {
updateView(data);
console.log("Friend");
}
});
Shiny.outputBindings.register(d3OutputBinding);
My understanding is:
Create a new shiny outputbinding, first find the class .d3io (div element), if error then write to console "Foe" (is this special code?), if not error then renderValue using the function updateView using data (Where does it receive this value from?) and write to console "Friend". Finally register output.
Hope you guys can help! I'm creating a document with the steps on "The necessary steps to learn how to implement javascript into shiny when you don't know any javascript", I would love that!:)
Cheers,
Long
Hi Sweetbabyjesus (so fun to say). You had two questions:
1) The server.r seems to get input called "d3io" (input$d3io) since this is not defined in ui.r, I reasoned it must come from the javascript file. Which element does it actually refer to?
That phrase input$d3io has the following components:
input is a parameter passed into the function - it's a list that
stores the current values of all the widgets in the app.
$ is the member selector.
d3io refers to the content of the div element with that id
('d3IO("d3io")') in the mainPanel of the UI.
2) I have trouble understanding the custom binding part:
var d3OutputBinding = new Shiny.OutputBinding();
That's right, this creates an instance of Shiny.OutputBinding and assigns it to the variable d3OutputBinding.
$.extend(d3OutputBinding, {
find: function(scope) {
return $(scope).find(".d3io");
},
renderError: function(el,error) {
console.log("Foe");
},
renderValue: function(el,data) {
updateView(data);
console.log("Friend");
}
});
This code extends the behaviour of d3OutputBinding with three functions called find, renderError and renderValue. Those three functions are required for a Shiny.OutputBinding.
find is the key because it returns a list of elements that should be passed into the two render functions via their el parameter. Notice it's returning elements whose css class is "d3io" - that's the same div mentioned earlier.
Note that extend() is a function of jQuery javascript library, and the $ in this context is an alias for the jQuery object.
Shiny.outputBindings.register(d3OutputBinding);
Lets Shiny know that this newly configured object should be put to use now.
Cheers, Nick
I'm going to take a step back and assume you want the amazing results D3 is capable of, but aren't necessarily tied to D3. Essentially, I'll be answering this question:
What are the necessary steps to learn how to implement JavaScript into Shiny when you don't know any JavaScript?
While D3 is amazingly powerful, it's also notoriously difficult to master - even for many folks who are quite comfortable with JavaScript. While I love D3 and use it almost every day, I'd recommend against it in this case. Instead, there's library called Plotly, which uses D3 in the background, but is built specifically for the scientific community and data scientists, so it's very friendly to the R community.
They have a thorough tutorial for connecting to Shiny and even have a ggplot2 converter if you're already familiar with that syntax, as many in the R world are. Unless your needs are very unusual, Plotly will likely serve your needs just as well as writing directly in D3, with a much more friendly learning curve.
Are you familiar with the rCharts package? It can work pretty well with Shiny and most of the output options are based on D3 variants. Two examples.
Very busy with work, I haven't had the chance to post it. Note that this is a workaround using the customMessageHandler (and I'm not using custom input/output binding). Here goes:
Objective: Send data from data frame to create a D3JS tree using customMessageHandler.
Path: I've managed to send data in data.frame format to a d3js tree. After you click the actionbutton, it changes the data in the data frame to JSON format, then sends it to the js file which creates the tree. The data of the tree is hard-coded on "server.r".
Where's the code? On my github!
https://github.com/SweetBabyJesus/shiny-d3js-simple-binding
Original: I created a tree algorithm based on CHAID to create insights from large datasets. People can upload their csv to the dashboard which then spits out the d3js tree:) The code is somewhat lengthy, therefore I cut it down for you and created a minimal code example.
Hope you like it.
Cheers,
Long
I'm a big fan of ICanHaz, and I'm trying to directly intregrate it into a new Marionette application I'm building. However, going off this post, I have written this that reaches into the render method and changes it in Marionette:
// Set up Initalizer
APP.addInitializer(function() {
//Reach into Marionette and switch out templating system to ICH
Backbone.Marionette.Renderer.render = function(template, data){
return ich[template](data);
}
//Create Router
new APP.Routers.GlobalRouter();
//Start Backbone History
Backbone.history.start();
});
If I walk through this function, all the data seems to work fine. However, when put into use and trying to use it for layouts and Item Views, nothing gets appended or inserted. This is from my GlobalRouter:
//Grab the main Layout
var layout = new APP.Views.LayoutView();
//Render that layout
layout.render();
//Make the model
var userModel = new APP.Models.UserModel({
"user_name" : "nweingartner#awesome.com",
"tenant" : "Ginger Ale is Great"
});
//Make the Header Region
var headerRegion = new APP.Views.HeaderView({model: userModel});
layout.header.show(headerRegion);
This all happens in a method that gets called when index is hit. There are no JS errors so I have nothing to go on. However, it in the render function I append the data to the body, it will add (however ruining my layout and region structure).
I am storing my templates in index.html.
Can anyone help with this?
Okay, I couldn't find an easy way to do this using ICH. However, due to another SO I found, very similar functionality can be found just using Mustache.
Using this code:
Backbone.Marionette.TemplateCache.prototype.compileTemplate = function(rawTemplate) {
return Mustache.compile(rawTemplate);
}
Lets you change the renderer so you can pull mustache templates from index.html using Marionette's template call. A mustache template looks like this:
<script id="headerTemplate" type="text/template">
<p>{{user_name}}</p>
<p>{{tenant}}</p>
</script>
The difference is that the type is 'text/template' as opposed to 'text/html'. Otherwise it acts very similar.
Hope this helps someone else.
So basically, I'm trying to introduce modifications in OpenERP's POS inteface from version 6.1. I see that the layout of this view can be found at /static/src/xml/pos.xml. What I want is to modify this view from my own addon (thus, not altering the original pos addon) and as far as I know, there is no way of inheriting this view to add changes (or is there?). So after studying the module, I'm trying to override its js function to slip in my own pos.xml with all my modifications (a copy of the original pos.xml, but with name 'PointOfSale_Mine' and other modifications). So far, I have added my own .js as follows:
openerp.my_pos = function(db) {
db.point_of_sale.PointOfSale = db.point_of_sale.PointOfSale.extend({
render: function() {
this._super.apply(this,arguments);
return qweb_template("PointOfSale_Mine")();
//return this._super.qweb_template("PointOfSale_Mine")();
//return db.point_of_sale.qweb_template("PointOfSale_Mine")();
}
})
};
And of course, I'm getting the error "qweb_template is not defined" as my JS skills and my knowledge regarding OpenERP6.1's new web framework is quite limited. I would really like to know how can I call the same method that the original 'render' function calls (You can see my useless attempts commented in the code above). Or is my whole approach wrong and there is a better way of introducing my changes to the template?
Thanks in advance. Any help will be appreciated.
Ok. After some trial and errors I came up with this code to do the trick:
openerp.my_pos = function(db) {
db.point_of_sale.PointOfSale = db.point_of_sale.PointOfSale.extend({
render: function() {
var rend = this._super();
var jdoc = $(rend);
jdoc.find('.pos-payment-container').prepend('<input type="text" value=""/>')
return jdoc[0].outerHTML;
}
})
};
It does not replace the entire pos.xml template as I was initially attempting, but it is probably better as you inherit the current template and introduce your modifications only (even if you have to .prepend() a big chunk of html code)
i'm currently writing a large scale application heavily based on the dojo toolkit. The whole app is working and standing, but one issue i can not find my way out with, is the creation of custom widgets. It would be useful because it would clean up my source code and also i can reuse this 'widgets' in later projects.
For example: i have a main toolbar, which i would like to call using
myapp.toolbar = new myapp.mainToolbar();
instead of using
myapp.toolbar = new new dijit.Toolbar({}, containerID);
var button1 = new dijit.form.Button({
label: 'Delete',
id: 'toolbarbutton1',
showLabel: true,
iconClass: "dijitEditorIcon dijitEditorIcon Delete"
});
myapp.toolbar.addChild(button1);
...
So in short: how do i set up the whole toolbar somewhere else and call it as a simple object? Trying to figure out dojo.declare('myapp.mainToolbar', dijit.Toolbar, {...}) but then i get a bunch of errors like 'startup function not existing' etc...
I'd like to do all this programmatically, so without the template html and css files in a custom widget.
A link to a good tutorial or howto would be nice, although google nor yahoo! will reveal any extra's on this matter for me... :)
There are multiple ways to do this.
It seems like your method of extending Toolbar should work (not sure why it didn't).
You can also declare a class that embeds Toolbar and the buttons, using widgetsInTemplate:
dojo.declare("MyToolbar", [dijit._Widget, dijit._Templated], {
_widgetsInTemplate: true,
templateString: '<div> <div dojoType=dijit.Toolbar>' +
' <button dojoType=dijit.form.Button ...
Note that the top node in MyToolbar can't have a dojoType, so I put Toolbar one level down.
Alternately you can do the same thing by using dijit.Declaration, see http://docs.dojocampus.org/dijit/Declaration.
It works for me when I use declare with the superclass inside of an array:
dojo.declare('myapp.mainToolbar', [ dijit.Toolbar ],
{
....
}
);
var x = new myapp.mainToolbar({ ... });
x.startup();
Which kind of violates the docs. It should take one Function or an array of Functions.