فهرست منبع

[search] Better click even for Datamaps

Enrico Berti 11 سال پیش
والد
کامیت
367c8bd592

+ 3 - 1
apps/search/src/search/templates/search2.mako

@@ -908,8 +908,10 @@ ${ commonheader(_('Search'), "search", user, "80px") | n,unicode }
 <script src="/static/ext/js/d3.v3.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/nv.d3.min.js" type="text/javascript" charset="utf-8"></script>
 <script src="/static/ext/js/topojson.v1.min.js" type="text/javascript" charset="utf-8"></script>
-<script src="/static/ext/js/datamaps.all.min.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/topo/world.topo.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/topo/usa.topo.js" type="text/javascript" charset="utf-8"></script>
 
+<script src="/search/static/js/nv.d3.datamaps.js" type="text/javascript" charset="utf-8"></script>
 <script src="/search/static/js/nv.d3.legend.js" type="text/javascript" charset="utf-8"></script>
 <script src="/search/static/js/nv.d3.multiBarWithBrushChart.js" type="text/javascript" charset="utf-8"></script>
 <script src="/search/static/js/nv.d3.lineWithBrushChart.js" type="text/javascript" charset="utf-8"></script>

+ 5 - 6
apps/search/static/js/charts.ko.js

@@ -182,13 +182,12 @@ ko.bindingHandlers.mapChart = {
         fills: fills,
         scope: _scope,
         data: mapData,
+        onClick: function(data) {
+          if (typeof options.onClick != "undefined"){
+            options.onClick(data);
+          }
+        },
         done: function(datamap) {
-          datamap.svg.selectAll('.datamaps-subunit').on('click', function(geography) {
-            if (typeof options.onClick != "undefined"){
-              options.onClick(geography);
-            }
-          });
-
           var _bubbles = [];
           if (options.enableGeocoding) {
             $(nonCountries).each(function(cnt, item){

+ 688 - 0
apps/search/static/js/nv.d3.datamaps.js

@@ -0,0 +1,688 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+(function() {
+  var svg;
+
+  //save off default references
+  var d3 = window.d3, topojson = window.topojson;
+
+  var defaultOptions = {
+    scope: 'world',
+    setProjection: setProjection,
+    projection: 'equirectangular',
+    dataType: 'json',
+    onClick: function() {},
+    done: function() {},
+    fills: {
+      defaultFill: '#ABDDA4'
+    },
+    geographyConfig: {
+        dataUrl: null,
+        hideAntarctica: true,
+        borderWidth: 1,
+        borderColor: '#FDFDFD',
+        popupTemplate: function(geography, data) {
+          return '<div class="hoverinfo"><strong>' + geography.properties.name + '</strong></div>';
+        },
+        popupOnHover: true,
+        highlightOnHover: true,
+        highlightFillColor: '#FC8D59',
+        highlightBorderColor: 'rgba(250, 15, 160, 0.2)',
+        highlightBorderWidth: 2
+    },
+    bubblesConfig: {
+        borderWidth: 2,
+        borderColor: '#FFFFFF',
+        popupOnHover: true,
+        popupTemplate: function(geography, data) {
+          return '<div class="hoverinfo"><strong>' + data.name + '</strong></div>';
+        },
+        fillOpacity: 0.75,
+        animate: true,
+        highlightOnHover: true,
+        highlightFillColor: '#FC8D59',
+        highlightBorderColor: 'rgba(250, 15, 160, 0.2)',
+        highlightBorderWidth: 2,
+        highlightFillOpacity: 0.85,
+        exitDelay: 100
+    },
+    arcConfig: {
+      strokeColor: '#DD1C77',
+      strokeWidth: 1,
+      arcSharpness: 1,
+      animationSpeed: 600
+    }
+  };
+
+  function addContainer( element ) {
+    this.svg = d3.select( element ).append('svg')
+      .attr('width', element.offsetWidth)
+      .attr('class', 'datamap')
+      .attr('height', element.offsetHeight);
+
+    return this.svg;
+  }
+
+  // setProjection takes the svg element and options
+  function setProjection( element, options ) {
+    var projection, path;
+    if ( options && typeof options.scope === 'undefined') {
+      options.scope = 'world';
+    }
+
+    if ( options.scope === 'usa' ) {
+      projection = d3.geo.albersUsa()
+        .scale(element.offsetWidth)
+        .translate([element.offsetWidth / 2, element.offsetHeight / 2]);
+    }
+    else if ( options.scope === 'world' ) {
+      projection = d3.geo[options.projection]()
+        .scale((element.offsetWidth + 1) / 2 / Math.PI)
+        .translate([element.offsetWidth / 2, element.offsetHeight / (options.projection === "mercator" ? 1.45 : 1.8)]);
+    }
+
+    path = d3.geo.path()
+      .projection( projection );
+
+    return {path: path, projection: projection};
+  }
+
+  function addStyleBlock() {
+    if ( d3.select('.datamaps-style-block').empty() ) {
+      d3.select('head').attr('class', 'datamaps-style-block').append('style')
+      .html('.datamap path {stroke: #FFFFFF; stroke-width: 1px;} .datamaps-legend dt, .datamaps-legend dd { float: left; margin: 0 3px 0 0;} .datamaps-legend dd {width: 20px; margin-right: 6px; border-radius: 3px;} .datamaps-legend {padding-bottom: 20px; z-index: 1001; position: absolute; left: 4px; font-size: 12px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;} .datamaps-hoverover {display: none; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; } .hoverinfo {padding: 4px; border-radius: 1px; background-color: #FFF; box-shadow: 1px 1px 5px #CCC; font-size: 12px; border: 1px solid #CCC; } .hoverinfo hr {border:1px dotted #CCC; }');
+    }
+  }
+
+  function drawSubunits( data ) {
+    var fillData = this.options.fills,
+        colorCodeData = this.options.data || {},
+        geoConfig = this.options.geographyConfig,
+        onClick = this.options.onClick;
+
+
+    var subunits = this.svg.select('g.datamaps-subunits');
+    if ( subunits.empty() ) {
+      subunits = this.addLayer('datamaps-subunits', null, true);
+    }
+
+    var geoData = topojson.feature( data, data.objects[ this.options.scope ] ).features;
+    if ( geoConfig.hideAntarctica ) {
+      geoData = geoData.filter(function(feature) {
+        return feature.id !== "ATA";
+      });
+    }
+
+    var geo = subunits.selectAll('path.datamaps-subunit').data( geoData );
+
+    geo.enter()
+      .append('path')
+      .attr('d', this.path)
+      .attr('class', function(d) {
+        return 'datamaps-subunit ' + d.id;
+      })
+      .attr('data-info', function(d) {
+        return JSON.stringify( colorCodeData[d.id]);
+      })
+      .style('fill', function(d) {
+        var fillColor;
+        if ( colorCodeData[d.id] ) {
+          fillColor = fillData[ colorCodeData[d.id].fillKey ];
+        }
+        return fillColor || fillData.defaultFill;
+      })
+      .on('click', function(d) {
+        if ( colorCodeData[d.id] && typeof onClick != "undefined") {
+          onClick(colorCodeData[d.id]);
+        }
+      })
+      .style('stroke-width', geoConfig.borderWidth)
+      .style('stroke', geoConfig.borderColor);
+  }
+
+  function handleGeographyConfig () {
+    var hoverover;
+    var svg = this.svg;
+    var self = this;
+    var options = this.options.geographyConfig;
+
+    if ( options.highlightOnHover || options.popupOnHover ) {
+      svg.selectAll('.datamaps-subunit')
+        .on('mouseover', function(d) {
+          var $this = d3.select(this);
+
+          if ( options.highlightOnHover ) {
+            var previousAttributes = {
+              'fill':  $this.style('fill'),
+              'stroke': $this.style('stroke'),
+              'stroke-width': $this.style('stroke-width'),
+              'fill-opacity': $this.style('fill-opacity')
+            };
+
+            $this
+              .style('fill', options.highlightFillColor)
+              .style('stroke', options.highlightBorderColor)
+              .style('stroke-width', options.highlightBorderWidth)
+              .style('fill-opacity', options.highlightFillOpacity)
+              .attr('data-previousAttributes', JSON.stringify(previousAttributes));
+
+            //as per discussion on https://github.com/markmarkoh/datamaps/issues/19
+            if ( ! /MSIE/.test(navigator.userAgent) ) {
+             moveToFront.call(this);
+            }
+          }
+
+          if ( options.popupOnHover ) {
+            self.updatePopup($this, d, options, svg);
+          }
+        })
+        .on('mouseout', function() {
+          var $this = d3.select(this);
+
+          if (options.highlightOnHover) {
+            //reapply previous attributes
+            var previousAttributes = JSON.parse( $this.attr('data-previousAttributes') );
+            for ( var attr in previousAttributes ) {
+              $this.style(attr, previousAttributes[attr]);
+            }
+          }
+          $this.on('mousemove', null);
+          d3.selectAll('.datamaps-hoverover').style('display', 'none');
+        });
+    }
+
+    function moveToFront() {
+      this.parentNode.appendChild(this);
+    }
+  }
+
+  //plugin to add a simple map legend
+  function addLegend(layer, data, options) {
+    data = data || {};
+    if ( !this.options.fills ) {
+      return;
+    }
+
+    var html = '<dl>';
+    var label = '';
+    if ( data.legendTitle ) {
+      html = '<h2>' + data.legendTitle + '</h2>' + html;
+    }
+    for ( var fillKey in this.options.fills ) {
+
+      if ( fillKey === 'defaultFill') {
+        if (! data.defaultFillName ) {
+          continue;
+        }
+        label = data.defaultFillName;
+      } else {
+        if (data.labels && data.labels[fillKey]) {
+          label = data.labels[fillKey];
+        } else {
+          label= fillKey + ': ';
+        }
+      }
+      html += '<dt>' + label + '</dt>';
+      html += '<dd style="background-color:' +  this.options.fills[fillKey] + '">&nbsp;</dd>';
+    }
+    html += '</dl>';
+
+    var hoverover = d3.select( this.options.element ).append('div')
+      .attr('class', 'datamaps-legend')
+      .html(html);
+  }
+
+  function handleArcs (layer, data, options) {
+    var self = this,
+        svg = this.svg;
+
+    if ( !data || (data && !data.slice) ) {
+      throw "Datamaps Error - arcs must be an array";
+    }
+
+    if ( typeof options === "undefined" ) {
+      options = defaultOptions.arcConfig;
+    }
+
+    var arcs = layer.selectAll('path.datamaps-arc').data( data, JSON.stringify );
+
+    arcs
+      .enter()
+        .append('svg:path')
+        .attr('class', 'datamaps-arc')
+        .style('stroke-linecap', 'round')
+        .style('stroke', function(datum) {
+          if ( datum.options && datum.options.strokeColor) {
+            return datum.options.strokeColor;
+          }
+          return  options.strokeColor
+        })
+        .style('fill', 'none')
+        .style('stroke-width', function(datum) {
+          if ( datum.options && datum.options.strokeWidth) {
+            return datum.options.strokeWidth;
+          }
+          return options.strokeWidth;
+        })
+        .attr('d', function(datum) {
+            var originXY = self.latLngToXY(datum.origin.latitude, datum.origin.longitude);
+            var destXY = self.latLngToXY(datum.destination.latitude, datum.destination.longitude);
+            var midXY = [ (originXY[0] + destXY[0]) / 2, (originXY[1] + destXY[1]) / 2];
+            return "M" + originXY[0] + ',' + originXY[1] + "S" + (midXY[0] + (50 * options.arcSharpness)) + "," + (midXY[1] - (75 * options.arcSharpness)) + "," + destXY[0] + "," + destXY[1];
+        })
+        .transition()
+          .delay(100)
+          .style('fill', function() {
+            /*
+              Thank you Jake Archibald, this is awesome.
+              Source: http://jakearchibald.com/2013/animated-line-drawing-svg/
+            */
+            var length = this.getTotalLength();
+            this.style.transition = this.style.WebkitTransition = 'none';
+            this.style.strokeDasharray = length + ' ' + length;
+            this.style.strokeDashoffset = length;
+            this.getBoundingClientRect();
+            this.style.transition = this.style.WebkitTransition = 'stroke-dashoffset ' + options.animationSpeed + 'ms ease-out';
+            this.style.strokeDashoffset = '0';
+            return 'none';
+          })
+
+    arcs.exit()
+      .transition()
+      .style('opacity', 0)
+      .remove();
+  }
+
+  function handleLabels ( layer, options ) {
+    var self = this;
+    options = options || {};
+    var labelStartCoodinates = this.projection([-67.707617, 42.722131]);
+    this.svg.selectAll(".datamaps-subunit")
+      .attr("data-foo", function(d) {
+        var center = self.path.centroid(d);
+        var xOffset = 7.5, yOffset = 5;
+
+        if ( ["FL", "KY", "MI"].indexOf(d.id) > -1 ) xOffset = -2.5;
+        if ( d.id === "NY" ) xOffset = -1;
+        if ( d.id === "MI" ) yOffset = 18;
+        if ( d.id === "LA" ) xOffset = 13;
+
+        var x,y;
+
+        x = center[0] - xOffset;
+        y = center[1] + yOffset;
+
+        var smallStateIndex = ["VT", "NH", "MA", "RI", "CT", "NJ", "DE", "MD", "DC"].indexOf(d.id);
+        if ( smallStateIndex > -1) {
+          var yStart = labelStartCoodinates[1];
+          x = labelStartCoodinates[0];
+          y = yStart + (smallStateIndex * (2+ (options.fontSize || 12)));
+          layer.append("line")
+            .attr("x1", x - 3)
+            .attr("y1", y - 5)
+            .attr("x2", center[0])
+            .attr("y2", center[1])
+            .style("stroke", options.labelColor || "#000")
+            .style("stroke-width", options.lineWidth || 1)
+        }
+
+        layer.append("text")
+          .attr("x", x)
+          .attr("y", y)
+          .style("font-size", (options.fontSize || 10) + 'px')
+          .style("font-family", options.fontFamily || "Verdana")
+          .style("fill", options.labelColor || "#000")
+          .text( d.id );
+        return "bar";
+      });
+  }
+
+
+  function handleBubbles (layer, data, options ) {
+    var self = this,
+        fillData = this.options.fills,
+        svg = this.svg;
+
+    if ( !data || (data && !data.slice) ) {
+      throw "Datamaps Error - bubbles must be an array";
+    }
+
+    var bubbles = layer.selectAll('circle.datamaps-bubble').data( data, JSON.stringify );
+
+    bubbles
+      .enter()
+        .append('svg:circle')
+        .attr('class', 'datamaps-bubble')
+        .attr('cx', function ( datum ) {
+          var latLng;
+          if ( datumHasCoords(datum) ) {
+            latLng = self.latLngToXY(datum.latitude, datum.longitude);
+          }
+          else if ( datum.centered ) {
+            latLng = self.path.centroid(svg.select('path.' + datum.centered).data()[0]);
+          }
+          if ( latLng ) return latLng[0];
+        })
+        .attr('cy', function ( datum ) {
+          var latLng;
+          if ( datumHasCoords(datum) ) {
+            latLng = self.latLngToXY(datum.latitude, datum.longitude);
+          }
+          else if ( datum.centered ) {
+            latLng = self.path.centroid(svg.select('path.' + datum.centered).data()[0]);
+          }
+          if ( latLng ) return latLng[1];;
+        })
+        .attr('r', 0) //for animation purposes
+        .attr('data-info', function(d) {
+          return JSON.stringify(d);
+        })
+        .style('stroke', options.borderColor)
+        .style('stroke-width', options.borderWidth)
+        .style('fill-opacity', options.fillOpacity)
+        .style('fill', function ( datum ) {
+          var fillColor = fillData[ datum.fillKey ];
+          return fillColor || fillData.defaultFill;
+        })
+        .on('mouseover', function ( datum ) {
+          var $this = d3.select(this);
+
+          if (options.highlightOnHover) {
+            //save all previous attributes for mouseout
+            var previousAttributes = {
+              'fill':  $this.style('fill'),
+              'stroke': $this.style('stroke'),
+              'stroke-width': $this.style('stroke-width'),
+              'fill-opacity': $this.style('fill-opacity')
+            };
+
+            $this
+              .style('fill', options.highlightFillColor)
+              .style('stroke', options.highlightBorderColor)
+              .style('stroke-width', options.highlightBorderWidth)
+              .style('fill-opacity', options.highlightFillOpacity)
+              .attr('data-previousAttributes', JSON.stringify(previousAttributes));
+          }
+
+          if (options.popupOnHover) {
+            self.updatePopup($this, datum, options, svg);
+          }
+        })
+        .on('mouseout', function ( datum ) {
+          var $this = d3.select(this);
+
+          if (options.highlightOnHover) {
+            //reapply previous attributes
+            var previousAttributes = JSON.parse( $this.attr('data-previousAttributes') );
+            for ( var attr in previousAttributes ) {
+              $this.style(attr, previousAttributes[attr]);
+            }
+          }
+
+          d3.selectAll('.datamaps-hoverover').style('display', 'none');
+        })
+        .transition().duration(400)
+          .attr('r', function ( datum ) {
+            return datum.radius;
+          });
+
+    bubbles.exit()
+      .transition()
+        .delay(options.exitDelay)
+        .attr("r", 0)
+        .remove();
+
+    function datumHasCoords (datum) {
+      return typeof datum !== 'undefined' && typeof datum.latitude !== 'undefined' && typeof datum.longitude !== 'undefined';
+    }
+
+  }
+
+  //stolen from underscore.js
+  function defaults(obj) {
+    Array.prototype.slice.call(arguments, 1).forEach(function(source) {
+      if (source) {
+        for (var prop in source) {
+          if (obj[prop] == null) obj[prop] = source[prop];
+        }
+      }
+    });
+    return obj;
+  }
+  /**************************************
+             Public Functions
+  ***************************************/
+
+  function Datamap( options ) {
+
+    if ( typeof d3 === 'undefined' || typeof topojson === 'undefined' ) {
+      throw new Error('Include d3.js (v3.0.3 or greater) and topojson on this page before creating a new map');
+   }
+
+    //set options for global use
+    this.options = defaults(options, defaultOptions);
+    this.options.geographyConfig = defaults(options.geographyConfig, defaultOptions.geographyConfig);
+    this.options.bubblesConfig = defaults(options.bubblesConfig, defaultOptions.bubblesConfig);
+    this.options.arcConfig = defaults(options.arcConfig, defaultOptions.arcConfig);
+
+    //add the SVG container
+    if ( d3.select( this.options.element ).select('svg').length > 0 ) {
+      addContainer.call(this, this.options.element );
+    }
+
+    /* Add core plugins to this instance */
+    this.addPlugin('bubbles', handleBubbles);
+    this.addPlugin('legend', addLegend);
+    this.addPlugin('arc', handleArcs);
+    this.addPlugin('labels', handleLabels);
+
+    //append style block with basic hoverover styles
+    if ( ! this.options.disableDefaultStyles ) {
+      addStyleBlock();
+    }
+
+    return this.draw();
+  }
+
+  // actually draw the features(states & countries)
+  Datamap.prototype.draw = function() {
+    //save off in a closure
+    var self = this;
+    var options = self.options;
+
+    //set projections and paths based on scope
+    var pathAndProjection = options.setProjection.apply(self, [options.element, options] );
+
+    this.path = pathAndProjection.path;
+    this.projection = pathAndProjection.projection;
+
+    //if custom URL for topojson data, retrieve it and render
+    if ( options.geographyConfig.dataUrl ) {
+      d3.json( options.geographyConfig.dataUrl, function(error, results) {
+        if ( error ) throw new Error(error);
+        self.customTopo = results;
+        draw( results );
+      });
+    }
+    else {
+      draw( this[options.scope + 'Topo'] );
+    }
+
+    return this;
+
+      function draw (data) {
+        // if fetching remote data, draw the map first then call `updateChoropleth`
+        if ( self.options.dataUrl ) {
+          //allow for csv or json data types
+          d3[self.options.dataType](self.options.dataUrl, function(data) {
+            //in the case of csv, transform data to object
+            if ( self.options.dataType === 'csv' && (data && data.slice) ) {
+              var tmpData = {};
+              for(var i = 0; i < data.length; i++) {
+                tmpData[data[i].id] = data[i];
+              }
+              data = tmpData;
+            }
+            Datamaps.prototype.updateChoropleth.call(self, data);
+          });
+        }
+        drawSubunits.call(self, data);
+        handleGeographyConfig.call(self);
+
+        if ( self.options.geographyConfig.popupOnHover || self.options.bubblesConfig.popupOnHover) {
+          hoverover = d3.select( self.options.element ).append('div')
+            .attr('class', 'datamaps-hoverover')
+            .style('z-index', 10001)
+            .style('position', 'absolute');
+        }
+
+        //fire off finished callback
+        self.options.done(self);
+      }
+  };
+  /**************************************
+                TopoJSON
+  ***************************************/
+  Datamap.prototype.worldTopo = WORLD_TOPO;
+  Datamap.prototype.usaTopo = USA_TOPO;
+
+  /**************************************
+                Utilities
+  ***************************************/
+
+  //convert lat/lng coords to X / Y coords
+  Datamap.prototype.latLngToXY = function(lat, lng) {
+     return this.projection([lng, lat]);
+  };
+
+  //add <g> layer to root SVG
+  Datamap.prototype.addLayer = function( className, id, first ) {
+    var layer;
+    if ( first ) {
+      layer = this.svg.insert('g', ':first-child')
+    }
+    else {
+      layer = this.svg.append('g')
+    }
+    return layer.attr('id', id || '')
+      .attr('class', className || '');
+  };
+
+  Datamap.prototype.updateChoropleth = function(data) {
+    var svg = this.svg;
+    for ( var subunit in data ) {
+      if ( data.hasOwnProperty(subunit) ) {
+        console.log(data);
+        var color;
+        var subunitData = data[subunit]
+        if ( ! subunit ) {
+          continue;
+        }
+        else if ( typeof subunitData === "string" ) {
+          color = subunitData;
+        }
+        else if ( typeof subunitData.color === "string" ) {
+          color = subunitData.color;
+        }
+        else {
+          color = this.options.fills[ subunitData.fillKey ];
+        }
+        //if it's an object, overriding the previous data
+        if ( subunitData === Object(subunitData) ) {
+          this.options.data[subunit] = defaults(subunitData, this.options.data[subunit] || {});
+          var geo = this.svg.select('.' + subunit).attr('data-info', JSON.stringify(this.options.data[subunit]));
+        }
+        svg
+          .selectAll('.' + subunit)
+          .transition()
+          .style('fill', color);
+      }
+    }
+  };
+
+  Datamap.prototype.updatePopup = function (element, d, options) {
+    var self = this;
+    element.on('mousemove', null);
+    element.on('mousemove', function() {
+      var position = d3.mouse(this);
+      d3.select(self.svg[0][0].parentNode).select('.datamaps-hoverover')
+        .style('top', ( (position[1] + 30)) + "px")
+        .html(function() {
+          var data = JSON.parse(element.attr('data-info'));
+          //if ( !data ) return '';
+          return options.popupTemplate(d, data);
+        })
+        .style('left', ( position[0]) + "px");
+    });
+
+    d3.select(self.svg[0][0].parentNode).select('.datamaps-hoverover').style('display', 'block');
+  };
+
+  Datamap.prototype.addPlugin = function( name, pluginFn ) {
+    var self = this;
+    if ( typeof Datamap.prototype[name] === "undefined" ) {
+      Datamap.prototype[name] = function(data, options, callback, createNewLayer) {
+        var layer;
+        if ( typeof createNewLayer === "undefined" ) {
+          createNewLayer = false;
+        }
+
+        if ( typeof options === 'function' ) {
+          callback = options;
+          options = undefined;
+        }
+
+        options = defaults(options || {}, defaultOptions[name + 'Config']);
+
+        //add a single layer, reuse the old layer
+        if ( !createNewLayer && this.options[name + 'Layer'] ) {
+          layer = this.options[name + 'Layer'];
+          options = options || this.options[name + 'Options'];
+        }
+        else {
+          layer = this.addLayer(name);
+          this.options[name + 'Layer'] = layer;
+          this.options[name + 'Options'] = options;
+        }
+        pluginFn.apply(this, [layer, data, options]);
+        if ( callback ) {
+          callback(layer);
+        }
+      };
+    }
+  };
+
+  // expose library
+  if ( typeof define === "function" && define.amd ) {
+    define( "datamaps", function(require) { d3 = require('d3'); topojson = require('topojson'); return Datamap; } );
+  }
+  else {
+    window.Datamap = window.Datamaps = Datamap;
+  }
+
+  if ( window.jQuery ) {
+    window.jQuery.fn.datamaps = function(options, callback) {
+      options = options || {};
+      options.element = this[0];
+      var datamap = new Datamap(options);
+      if ( typeof callback === "function" ) {
+        callback(datamap, options);
+      }
+      return this;
+    };
+  }
+})();

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
desktop/core/static/ext/js/datamaps.all.min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
desktop/core/static/ext/js/topo/usa.topo.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
desktop/core/static/ext/js/topo/world.topo.js


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است