18

I need to have multiple versions of a javascript library on the same page. How can I accomplish this, short of manually refactoring one version to avoid naming conflicts?

There are many examples of how to do this with Jquery (example). This seems to rely on jQuery goodness, however. How can I do this for an arbitrary script?

More detail: I'm using d3.js, and I'm plugging in visualizations others have made using d3. The issue is, one of the vizzes requires one version of d3, the other requires a newer version. Both of these vizzes are supposed to be available on the same page - the user swaps which viz is displayed by clicking a thumbnail, and then js is used to hide one viz and build the other. So, it seems like swapping the script rather than loading both in a no-conflict style could also be an option.

Community
  • 1
  • 1
mobabo
  • 809
  • 1
  • 9
  • 11

5 Answers5

27

If you take a look at the main d3 source file: https://github.com/mbostock/d3/blob/master/d3.js

you see it begins:

d3 = function() {
  var d3 = {
    version: "3.1.5"
  };
  //.....

So d3 is just an object. I'm not sure if this is the best method, but I think the following would work:

  1. include one version of d3
  2. put the line: d3versionX = d3;
  3. include the next version
  4. same as 2 with different version number.
  5. put d3 = d3versionX where X is your default version for the visualization when the page loads
  6. put an event handler on the thumbnails that trigger the switching of version, and set the d3 variable to the appropriate version number as the first thing that happens.

update with sample code

See this jsbin for a working example. The relevant code:

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>
  <script>
    d3version4 = d3
    window.d3 = null
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
  <script>
    d3version3 = d3
    window.d3 = null
    // test it worked
    console.log('v3', d3version3.version)
    console.log('v4', d3version4.version)
  </script>
Community
  • 1
  • 1
Jonah
  • 15,806
  • 22
  • 87
  • 161
  • 1
    would you be able to post a sample code for how you got this to work? I am running into the exact same issue where I want to use two different versions of D3.js for two different charts on my page. Can this be done? – konrad Sep 19 '16 at 03:21
1

I had a similar problem like yours, some visualization needed d3 v3 while others needed v4. This is how I achieved it.

  1. Included d3 v3 in index.html (since most of my visualizations were on v3)
  2. Include require.js script on index.html //you can use cdn path
  3. Go to JavaScript that needs v4.
  4. write the following code at the top.

    function graphicviz(id) {   
        require.config({
            paths: {
                d3: "https://d3js.org/d3.v4.min"
            }
        });
    
        require(["d3"], function(d3) {
            //... D3 Code Here...
        });
    }
    
    //Call The Function
    graphicviz(id); 
    
TomPlum
  • 135
  • 1
  • 14
0

You need to use this general principle

var x = {
    version: 1,
    alert1: function() {
        alert("1hi1");
    },
    alert2: function() {
        alert("1hi2");
    }
};

var y = x;

var x = {
    version: 2,
    alert1: function() {
        alert("2hi1");
    },
    alert2: function() {
        alert("2hi2");
    }
};

y.alert1();
x.alert1();

on jsfiddle

jquery offers its noconflict method and many libraries offer the same (not necessarily by name) method. But you can do it yourself by referencing my example, depending on the complexity of the script you are loading.

Here is how to inject the 2 different versions and use the above principle to assign them to different variables.

<div id="version1"></div>
<div id="version2"></div>

var script1 = document.createElement("script"),
    script2 = document.createElement("script"),
    oldD3;

function noConflict() {
    oldD3 = d3;
    console.log("loaded old");
    script2.type = 'text/javascript';
    script2.src = "http://d3js.org/d3.v3.min.js";
    script2.addEventListener("load", ready, false);
    document.head.appendChild(script2);
}

function ready() {
    console.log("loaded new");
    console.log(d3, oldD3);
    document.getElementById("version1").textContent = oldD3.version;
    document.getElementById("version2").textContent = d3.version;
}

script1.type = 'text/javascript';
script1.src = "http://d3js.org/d3.v2.min.js";
script1.addEventListener("load", noConflict, false);
document.head.appendChild(script1);

on jsfiddle

Xotic750
  • 22,914
  • 8
  • 57
  • 79
0

From d3 version d3.v4 the header of the script looks a bit different. You can change the identifier global.d3 to global.d3v4, such that it looks like this

(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
    typeof define === 'function' && define.amd ? define(['exports'], factory) :
    (factory((global.d3v4 = global.d3v4 || {})));
}(this, (function (exports) { 'use strict';

var version = "4.8.0";
...

Now you can call d3 functions by d3v4.

chtenb
  • 14,924
  • 14
  • 78
  • 116
0

I've been testing this and while the selected answer may work for most scenarios, the .on function which related to the d3.event object can't seem to be rewritten.

Risharde
  • 1
  • 1
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 28 '22 at 14:27
  • 1
    Please provide code with your answer. – ethry Jul 02 '22 at 21:29