cancel
Showing results for 
Search instead for 
Did you mean: 

Is it possible to include d3 v3 into Design Studio SDK Component?

mike_howles4
Active Contributor
0 Kudos

It looks like Design Studio 1.3 uses D3 v2.10.  I'd like to leverage D3 v3 for a component.  Has anyone successfully managed to include d3 v3 into Design Studio?  If so, do we know if this is a valid use of the SDK or does it violate any principle since CVOM charts rely on a certain version of d3?

I see where did it for Lumira here () however I don't think Design Studio uses require.js nor am I sure if his inclusion of d3 v3 is also technically a bad idea for Lumira since it also uses CVOM charts?

Just wondering if there's any answers before I go trying to use d3 v3!

Thanks!

Accepted Solutions (1)

Accepted Solutions (1)

reiner_hille-doering
Active Contributor
0 Kudos

Clear answer: No! Design Studio and Lumira both use CVOM, which is based on D3.v2.js.

As with most frameworks, D3 creates at least one global variable. If you would include another version of D3 with your component, you would overwrite the current one. Nobody knows what effect this could have.

In Lumira they havily use Require.js that could theoretically support multiple versions of the same lib. So it could work there, but I would not guarantee. In Design Studio it would definitly cause problems.

Reiner.

mike_howles4
Active Contributor
0 Kudos

Thanks, Reiner.  You've confirmed what common sense was telling me in the back of my head.  I'll bookmark this post in case the question surfaces again, as they tend to do here

Appreciate the authoritative answer!

(Any plans to move to v3, by the way?  )

reiner_hille-doering
Active Contributor
0 Kudos

Perfekt . We get D3 from CVOM. If they upgrade to v3, we will also in the next release.

mike_howles4
Active Contributor
0 Kudos

Reiner,

I got Require.js to load d3 v3 without it disrupting the global d3 v2 variable that is pulled in via stdInclude:


require.config({paths: {d3: "http://d3js.org/d3.v3.min"}});

  require(["d3"], function(d3v3) {

  alert(d3v3.version + "\n\n" + d3.version);

  });

Result:

reiner_hille-doering
Active Contributor
0 Kudos

Hi Michael,

yes, this could work, but:

  1. It is not guaranteed that require.js is contained. In current Design Studio version require.js "accidently" comes with CVOM.
  2. It is almost impossible to configure require.js correctly to load d3 or other libraries from the SDK extension, as this path is dependent on the platform. In your sample you loaded it thus from d3s.org.
  3. I'm not sure if d3.v3 is correctly prepared for loading by require. If not, if still might overwrite the global "d3" variable with the newer version.
  4. As require.js is asynchronous, it might be difficult to do something usefull with the delayed-loaded d3 object. In the moment of your callback your rendering might have already happened or not...

Regards,

Reiner.

mike_howles4
Active Contributor
0 Kudos

Hey Reiner,

Thanks for the feedback.  A few responses:

1) I am actually including my own require.js - I'd actually hoped that require.js came along for the ride in DS, however I had to include it myself in my contribution.xml file.

2) In my example I did load from d3js.org just for quick and dirty proof-of-concept.  I'm actually a little disappointed about the pains we have to go through to include libraries via SDK extension because of what you just mentioned, these path issues.  Guess if I was really stubborn I could just Base-64 encode the JS contents into the URI and move on

3) It will register itself as an AMD module if require is present, I did some reading on this and I was able to see it work as expected with proper configuration of require.js and also using shims if needed.

4) In my small snippet, that was executed during init() and in the real world, I'd ensure the loading was completed so that the call back occurs at the right part in the component lifecycle.

Hopefully d3.v3 will just come "standard" one day with a newer version of CVOM, but for now I have a path.

reiner_hille-doering
Active Contributor
0 Kudos

Hi Michael,

  1. Be careful, as next version of Design Studio will likely include require.js.
  2. Yes, it is a problem not to know the path of your extension. This is e.g. also a problem if you want to use an <img> element and set the src to the correct picture from your SDK extension. I'll post a blog on this topic soon. In future version I will provide a JS API to get the root URL of your SDK extension lib. You could use it to configure your Require context - or we might event build this in.
    For today, you could try the following trick (I didn't try it):
    var ourScript = $("script:last");
    var url = ourScript.attr("src");
    var iTocut = url.indexOf("/js/component.js");
    url = url.substring(0, iTocut);
  3. Yes, I could have seen this in your screenshot - I just remember that older d3-versions were not AMD-enabled.
  4. We might also provide a little more support for require.js in the future, e.g. to delay the initial rendering until all required modules are loaded. So far you might get some interesting effects if your d3-content is drawn later than the rest of the application.

Reiner.

mike_howles4
Active Contributor
0 Kudos
  1. Good to know that it is likely in a future version.  For now, it is what it is.
  2. Deriving the root SDK URL will be terrific!  Also I think your trick (or some form of it by using jQuery to figure out the path from the src attribute of the script object) is a great stop-gap for now.  Thanks for that idea!
  3. Perhaps since D3 is now AMD enabled, CVOM-powered products like Lumira and DS will benefit from newer versions!
  4. Yes, this is price I pay to be an "early adopter" I'd gather.  Also, would this impact SAPUI5 libraries?  I may be asking the wrong person, I've just not done reading on whether SAPUI5/OpenUI5 is AMD enabled as well.

As always thank you for your information and hints on what may be to come, it's helpful.

mike_howles4
Active Contributor
0 Kudos

Reiner,

As a follow-up, it actually appears that what you were alluding to in a previous post where RequireJs 2.1.5 is loaded in sap.viz.js, so yes, it is "sneaked in" with the CVOM libs are you mentioned.

It does appear to check if requirejs object already exists and will not overwrite it in the event that it is already loaded:

if (typeof define !== 'undefined') {

        //If a define is already in play via another AMD loader,

        //do not overwrite.

        return;

    }

    if (typeof requirejs !== 'undefined') {

        if (isFunction(requirejs)) {

            //Do not overwrite and existing requirejs instance.

            return;

        }

        cfg = requirejs;

        requirejs = undefined;

    }

    //Allow for a require config object

    if (typeof require !== 'undefined' && !isFunction(require)) {

        //assume it is a config object.

        cfg = require;

        require = undefined;

    }

This at least gives me some hope as I'm now running into the following issue with an AMD-enabled lib:

http://requirejs.org/docs/errors.html#mismatch

Basically, the lib runs fine until a CVOM chart is brought into DS, at which point RequireJS is loaded, and since they use a define with an anonymous function, things "break".

I think it would be great if we had a way to include .js files using the modularization capabilities of RequireJS in DS rather than them being rendered as script tags when using as they work with jsInclude today.  Any thoughts of alternative options coming in the future?

reiner_hille-doering
Active Contributor
0 Kudos

Hi Michael,

thanks for checking this.

I'm currently implementing in our code line for 1.4 release a simple RequireJS support:

Inside of one of your "normal" includes you could use

sap.zen.Dispatcher.instance.require(<modules>, <callback>);

This function is a simple wrapper on normal "require" function, but

  • Modules are automatically loaded with relative path to the calling script
  • Dispatching of our JSON is delayed until all modules are loaded (thus callback is called).
  • Thus you could implements your handler inside of the callback and use all required modules safely.

I also think if I will also automatically use an own context per such call.

This should enable you any side-by-side usage of different versions of AMD-enabled libs.

What do you think about this approach?

Reiner.

mike_howles4
Active Contributor
0 Kudos

Reiner,

I think this is definitely a worthwhile approach and I will take a look at the sap.zen.Dispatcher.instance.require to see if I can get it to work.  Also I am glad to hear that this may be a bit more suitable path for a side-by-side usage which really is the ultimate goal for me, so that I do not step on other versions of the delivered library versions (or even other SDK components from other vendors which may be present.)

Thanks as always for taking the time to help!

reiner_hille-doering
Active Contributor
0 Kudos

To get it work you might need to wait some month . This feature is not available yet in the shipped products.

XaviPolo
Active Contributor
0 Kudos

Same problem with another JS library that uses require.js.

In this project I can't update to 1.4, any idea how to solve this in 1.3?

Is possible to change require definition to not be anonymous?:

     if("function"==typeof define&&define.amd) define([],e)

to something like this?

     if("function"==typeof define&&define.amd) define('NOT_A',[],e)

sorry I have no experience with require.js

thx

mike_howles4
Active Contributor
0 Kudos

Xavier,


I've developed a love/hate relationship with the whole RequireJS thing.

Are you wanting your JS lib to IGNORE if Require is loaded or do you want to guarantee that Require IS loaded so that your JS lib will use it?  I've had to do both in the past...  Some times, modify some libs to BECOME require-aware and also prior to 1.4, make components become unaware of Require that were require-sensitive.

If you want to make Require available in 1.3, simply add stdInclude for CVOM (also I think D3 stdInclude) and they both will pull in require.

Can you share which JS Lib?  I might be able to show you how to make it AMD/Require compatible, or also how to break the compatibility for 1.3 support.

XaviPolo
Active Contributor
0 Kudos

The library is rasterizeHTML.js

A customer needs to print a DS with some modifications.

I made a SDK component extending SAPUI5 button, that calls this library to export the DS (with charts) to IMG.

this is an html demo http://jsfiddle.net/xavipolo/pv3fmqp6/ (only chrome)

The error is thrown by require loaded by sap.viz.js. and anonymous define function (inside rasterizeHTML)

Thanks!

mike_howles4
Active Contributor
0 Kudos

Hey Xavier,

If I have the right amount of gin and time tonight, I will see if I can come up with a hack for you.

mike_howles4
Active Contributor
0 Kudos

Here you are:

sap.zen.Dispatcher.instance.pauseDispatching();

var myRequire = require.config({

  context : "rasterizeSDK",

  paths: {

  rasterizeHTML : "http://cburgmer.github.com/rasterizeHTML.js/rasterizeHTML.allinone"

  }

});

myRequire(["require","rasterizeHTML"],function(require,rasterizeHTML){

  sap.ui.commons.Button.extend("com.yourcomponent.Whatever", {

/* your code here */

});
sap.zen.Dispatcher.instance.resumeDispatching();

});

XaviPolo
Active Contributor
0 Kudos

Thank You !

I'll try it.

Answers (2)

Answers (2)

Former Member
0 Kudos

Hi all,

quick thought: why don't you just modify your copy of d3 as such, that you pass a different context to the d3-closure?

Then it doesn't register on the window, but on your own "namespace". As far as I can see D3 sticks to the context and doesn't fiddle outside of it, so a second instance of D3 should be safe ...

Like so:

var myNamespace = {};

(function(){

     // D3 definition

}).call(myNamespace);

Now your D3 sits inside

myNamespace.d3.xxxx ... or do I miss any problems with that?

Regards,

Jonas

reiner_hille-doering
Active Contributor
0 Kudos

Many libraries declare their globals like "window.d3 = <something>", so in the end you somehow need to copy and modify a lib like d3 to be sure that it doesn't harm Design Studio.

I think that require.js is the way to go in future, but we need some time to make it right...

Former Member
0 Kudos

D3 declares it with

this.d3 = <something>

where "this" is the window context.

Well, you need to modify it anyway.

MustafaBensan
Active Contributor
0 Kudos

Hi Mike,

As I recall, during the SDK Beta Program we were advised against trying to manually load a newer version of D3 via the include tag in the contribution.xml file to avoid causing conflicts with the standard D3 library included in DS.  Technically, I suppose you could load your own version of D3 if you could guarantee that no other components based on the DS standard D3 version were going to be used in the application.

Perhaps the DS Team can confirm if the above position still applies.

Mustafa.

mike_howles4
Active Contributor
0 Kudos

Hey Mustafa, always good to hear from you!  Your comments are in line with my suspicions and while if confirmed, is unfortunate, I'm hoping to get SAP's official stance of yay or nay   Perhaps will pop in with some insight?