├── README.md ├── index.html ├── jquery-jvectormap-2.0.1.css ├── LICENSE └── jquery-jvectormap-2.0.1.min.js /README.md: -------------------------------------------------------------------------------- 1 | jVectorMap-Turkey 2 | ================= 3 | 4 | jVectorMap Türkiye Haritası Eklentisi / jVectorMap Turkey Map Plugin 5 | #Javascript, #jQuery 6 | 7 | jVectorMap Sayfası: 8 | http://jvectormap.com 9 | 10 | İlk Esin Kaynağı: 11 | http://avpar.blogspot.com.tr/2014/03/jvector-map-turkiye.html 12 | 13 | 14 | ```javascript 15 | $('#world-map').vectorMap( 16 | { 17 | map: 'turkey_1_mill_en' 18 | }); 19 | ``` 20 | 21 | Diğer alternatifleri; 22 | https://github.com/aytacsunar/turkey-map-jquery-with-jqvmap 23 | 24 | Canbey Bilgili 25 | http://www.emanova.com 26 | http://www.xanbei.com 27 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |true legend will be rendered as vertical.
1447 | * @param {String} params.title Legend title.
1448 | * @param {Function} params.labelRender Method to convert series values to legend labels.
1449 | */
1450 | jvm.Legend = function(params) {
1451 | this.params = params || {};
1452 | this.map = this.params.map;
1453 | this.series = this.params.series;
1454 | this.body = jvm.$('');
1455 | this.body.addClass('jvectormap-legend');
1456 | if (this.params.cssClass) {
1457 | this.body.addClass(this.params.cssClass);
1458 | }
1459 |
1460 | if (params.vertical) {
1461 | this.map.legendCntVertical.append( this.body );
1462 | } else {
1463 | this.map.legendCntHorizontal.append( this.body );
1464 | }
1465 |
1466 | this.render();
1467 | }
1468 |
1469 | jvm.Legend.prototype.render = function(){
1470 | var ticks = this.series.scale.getTicks(),
1471 | i,
1472 | inner = jvm.$('').addClass('jvectormap-legend-inner'),
1473 | tick,
1474 | sample,
1475 | label;
1476 |
1477 | this.body.html('');
1478 | if (this.params.title) {
1479 | this.body.append(
1480 | jvm.$('').addClass('jvectormap-legend-title').html(this.params.title)
1481 | );
1482 | }
1483 | this.body.append(inner);
1484 |
1485 | for (i = 0; i < ticks.length; i++) {
1486 | tick = jvm.$('').addClass('jvectormap-legend-tick');
1487 | sample = jvm.$('').addClass('jvectormap-legend-tick-sample');
1488 |
1489 | switch (this.series.params.attribute) {
1490 | case 'fill':
1491 | if (jvm.isImageUrl(ticks[i].value)) {
1492 | sample.css('background', 'url('+ticks[i].value+')');
1493 | } else {
1494 | sample.css('background', ticks[i].value);
1495 | }
1496 | break;
1497 | case 'stroke':
1498 | sample.css('background', ticks[i].value);
1499 | break;
1500 | case 'image':
1501 | sample.css('background', 'url('+ticks[i].value+') no-repeat center center');
1502 | break;
1503 | case 'r':
1504 | jvm.$('').css({
1505 | 'border-radius': ticks[i].value,
1506 | border: this.map.params.markerStyle.initial['stroke-width']+'px '+
1507 | this.map.params.markerStyle.initial['stroke']+' solid',
1508 | width: ticks[i].value * 2 + 'px',
1509 | height: ticks[i].value * 2 + 'px',
1510 | background: this.map.params.markerStyle.initial['fill']
1511 | }).appendTo(sample);
1512 | break;
1513 | }
1514 | tick.append( sample );
1515 | label = ticks[i].label;
1516 | if (this.params.labelRender) {
1517 | label = this.params.labelRender(label);
1518 | }
1519 | tick.append( jvm.$('fill, stroke, fill-opacity, stroke-opacity for markers and regions and r (radius) for markers only.
1529 | * @param {Array} params.scale Values used to map a dimension of data to a visual representation. The first value sets visualization for minimum value from the data set and the last value sets visualization for the maximum value. There also could be intermidiate values. Default value is ['#C8EEFF', '#0071A4']
1530 | * @param {Function|String} params.normalizeFunction The function used to map input values to the provided scale. This parameter could be provided as function or one of the strings: 'linear' or 'polynomial', while 'linear' is used by default. The function provided takes value from the data set as an input and returns corresponding value from the scale.
1531 | * @param {Number} params.min Minimum value of the data set. Could be calculated automatically if not provided.
1532 | * @param {Number} params.min Maximum value of the data set. Could be calculated automatically if not provided.
1533 | */
1534 | jvm.DataSeries = function(params, elements, map) {
1535 | var scaleConstructor;
1536 |
1537 | params = params || {};
1538 | params.attribute = params.attribute || 'fill';
1539 |
1540 | this.elements = elements;
1541 | this.params = params;
1542 | this.map = map;
1543 |
1544 | if (params.attributes) {
1545 | this.setAttributes(params.attributes);
1546 | }
1547 |
1548 | if (jvm.$.isArray(params.scale)) {
1549 | scaleConstructor = (params.attribute === 'fill' || params.attribute === 'stroke') ? jvm.ColorScale : jvm.NumericScale;
1550 | this.scale = new scaleConstructor(params.scale, params.normalizeFunction, params.min, params.max);
1551 | } else if (params.scale) {
1552 | this.scale = new jvm.OrdinalScale(params.scale);
1553 | } else {
1554 | this.scale = new jvm.SimpleScale(params.scale);
1555 | }
1556 |
1557 | this.values = params.values || {};
1558 | this.setValues(this.values);
1559 |
1560 | if (this.params.legend) {
1561 | this.legend = new jvm.Legend($.extend({
1562 | map: this.map,
1563 | series: this
1564 | }, this.params.legend))
1565 | }
1566 | };
1567 |
1568 | jvm.DataSeries.prototype = {
1569 | setAttributes: function(key, attr){
1570 | var attrs = key,
1571 | code;
1572 |
1573 | if (typeof key == 'string') {
1574 | if (this.elements[key]) {
1575 | this.elements[key].setStyle(this.params.attribute, attr);
1576 | }
1577 | } else {
1578 | for (code in attrs) {
1579 | if (this.elements[code]) {
1580 | this.elements[code].element.setStyle(this.params.attribute, attrs[code]);
1581 | }
1582 | }
1583 | }
1584 | },
1585 |
1586 | /**
1587 | * Set values for the data set.
1588 | * @param {Object} values Object which maps codes of regions or markers to values.
1589 | */
1590 | setValues: function(values) {
1591 | var max = -Number.MAX_VALUE,
1592 | min = Number.MAX_VALUE,
1593 | val,
1594 | cc,
1595 | attrs = {};
1596 |
1597 | if (!(this.scale instanceof jvm.OrdinalScale) && !(this.scale instanceof jvm.SimpleScale)) {
1598 | // we have a color scale as an array
1599 | if (typeof this.params.min === 'undefined' || typeof this.params.max === 'undefined') {
1600 | // min and/or max are not defined, so calculate them
1601 | for (cc in values) {
1602 | val = parseFloat(values[cc]);
1603 | if (val > max) max = val;
1604 | if (val < min) min = val;
1605 | }
1606 | }
1607 |
1608 | if (typeof this.params.min === 'undefined') {
1609 | this.scale.setMin(min);
1610 | this.params.min = min;
1611 | } else {
1612 | this.scale.setMin(this.params.min);
1613 | }
1614 |
1615 | if (typeof this.params.max === 'undefined') {
1616 | this.scale.setMax(max);
1617 | this.params.max = max;
1618 | } else {
1619 | this.scale.setMax(this.params.max);
1620 | }
1621 |
1622 | for (cc in values) {
1623 | if (cc != 'indexOf') {
1624 | val = parseFloat(values[cc]);
1625 | if (!isNaN(val)) {
1626 | attrs[cc] = this.scale.getValue(val);
1627 | } else {
1628 | attrs[cc] = this.elements[cc].element.style.initial[this.params.attribute];
1629 | }
1630 | }
1631 | }
1632 | } else {
1633 | for (cc in values) {
1634 | if (values[cc]) {
1635 | attrs[cc] = this.scale.getValue(values[cc]);
1636 | } else {
1637 | attrs[cc] = this.elements[cc].element.style.initial[this.params.attribute];
1638 | }
1639 | }
1640 | }
1641 |
1642 | this.setAttributes(attrs);
1643 | jvm.$.extend(this.values, values);
1644 | },
1645 |
1646 | clear: function(){
1647 | var key,
1648 | attrs = {};
1649 |
1650 | for (key in this.values) {
1651 | if (this.elements[key]) {
1652 | attrs[key] = this.elements[key].element.shape.style.initial[this.params.attribute];
1653 | }
1654 | }
1655 | this.setAttributes(attrs);
1656 | this.values = {};
1657 | },
1658 |
1659 | /**
1660 | * Set scale of the data series.
1661 | * @param {Array} scale Values representing scale.
1662 | */
1663 | setScale: function(scale) {
1664 | this.scale.setScale(scale);
1665 | if (this.values) {
1666 | this.setValues(this.values);
1667 | }
1668 | },
1669 |
1670 | /**
1671 | * Set normalize function of the data series.
1672 | * @param {Function|String} normilizeFunction.
1673 | */
1674 | setNormalizeFunction: function(f) {
1675 | this.scale.setNormalizeFunction(f);
1676 | if (this.values) {
1677 | this.setValues(this.values);
1678 | }
1679 | }
1680 | };
1681 | /**
1682 | * Contains methods for transforming point on sphere to
1683 | * Cartesian coordinates using various projections.
1684 | * @class
1685 | */
1686 | jvm.Proj = {
1687 | degRad: 180 / Math.PI,
1688 | radDeg: Math.PI / 180,
1689 | radius: 6381372,
1690 |
1691 | sgn: function(n){
1692 | if (n > 0) {
1693 | return 1;
1694 | } else if (n < 0) {
1695 | return -1;
1696 | } else {
1697 | return n;
1698 | }
1699 | },
1700 |
1701 | /**
1702 | * Converts point on sphere to the Cartesian coordinates using Miller projection
1703 | * @param {Number} lat Latitude in degrees
1704 | * @param {Number} lng Longitude in degrees
1705 | * @param {Number} c Central meridian in degrees
1706 | */
1707 | mill: function(lat, lng, c){
1708 | return {
1709 | x: this.radius * (lng - c) * this.radDeg,
1710 | y: - this.radius * Math.log(Math.tan((45 + 0.4 * lat) * this.radDeg)) / 0.8
1711 | };
1712 | },
1713 |
1714 | /**
1715 | * Inverse function of mill()
1716 | * Converts Cartesian coordinates to point on sphere using Miller projection
1717 | * @param {Number} x X of point in Cartesian system as integer
1718 | * @param {Number} y Y of point in Cartesian system as integer
1719 | * @param {Number} c Central meridian in degrees
1720 | */
1721 | mill_inv: function(x, y, c){
1722 | return {
1723 | lat: (2.5 * Math.atan(Math.exp(0.8 * y / this.radius)) - 5 * Math.PI / 8) * this.degRad,
1724 | lng: (c * this.radDeg + x / this.radius) * this.degRad
1725 | };
1726 | },
1727 |
1728 | /**
1729 | * Converts point on sphere to the Cartesian coordinates using Mercator projection
1730 | * @param {Number} lat Latitude in degrees
1731 | * @param {Number} lng Longitude in degrees
1732 | * @param {Number} c Central meridian in degrees
1733 | */
1734 | merc: function(lat, lng, c){
1735 | return {
1736 | x: this.radius * (lng - c) * this.radDeg,
1737 | y: - this.radius * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360))
1738 | };
1739 | },
1740 |
1741 | /**
1742 | * Inverse function of merc()
1743 | * Converts Cartesian coordinates to point on sphere using Mercator projection
1744 | * @param {Number} x X of point in Cartesian system as integer
1745 | * @param {Number} y Y of point in Cartesian system as integer
1746 | * @param {Number} c Central meridian in degrees
1747 | */
1748 | merc_inv: function(x, y, c){
1749 | return {
1750 | lat: (2 * Math.atan(Math.exp(y / this.radius)) - Math.PI / 2) * this.degRad,
1751 | lng: (c * this.radDeg + x / this.radius) * this.degRad
1752 | };
1753 | },
1754 |
1755 | /**
1756 | * Converts point on sphere to the Cartesian coordinates using Albers Equal-Area Conic
1757 | * projection
1758 | * @see Albers Equal-Area Conic projection
1759 | * @param {Number} lat Latitude in degrees
1760 | * @param {Number} lng Longitude in degrees
1761 | * @param {Number} c Central meridian in degrees
1762 | */
1763 | aea: function(lat, lng, c){
1764 | var fi0 = 0,
1765 | lambda0 = c * this.radDeg,
1766 | fi1 = 29.5 * this.radDeg,
1767 | fi2 = 45.5 * this.radDeg,
1768 | fi = lat * this.radDeg,
1769 | lambda = lng * this.radDeg,
1770 | n = (Math.sin(fi1)+Math.sin(fi2)) / 2,
1771 | C = Math.cos(fi1)*Math.cos(fi1)+2*n*Math.sin(fi1),
1772 | theta = n*(lambda-lambda0),
1773 | ro = Math.sqrt(C-2*n*Math.sin(fi))/n,
1774 | ro0 = Math.sqrt(C-2*n*Math.sin(fi0))/n;
1775 |
1776 | return {
1777 | x: ro * Math.sin(theta) * this.radius,
1778 | y: - (ro0 - ro * Math.cos(theta)) * this.radius
1779 | };
1780 | },
1781 |
1782 | /**
1783 | * Converts Cartesian coordinates to the point on sphere using Albers Equal-Area Conic
1784 | * projection
1785 | * @see Albers Equal-Area Conic projection
1786 | * @param {Number} x X of point in Cartesian system as integer
1787 | * @param {Number} y Y of point in Cartesian system as integer
1788 | * @param {Number} c Central meridian in degrees
1789 | */
1790 | aea_inv: function(xCoord, yCoord, c){
1791 | var x = xCoord / this.radius,
1792 | y = yCoord / this.radius,
1793 | fi0 = 0,
1794 | lambda0 = c * this.radDeg,
1795 | fi1 = 29.5 * this.radDeg,
1796 | fi2 = 45.5 * this.radDeg,
1797 | n = (Math.sin(fi1)+Math.sin(fi2)) / 2,
1798 | C = Math.cos(fi1)*Math.cos(fi1)+2*n*Math.sin(fi1),
1799 | ro0 = Math.sqrt(C-2*n*Math.sin(fi0))/n,
1800 | ro = Math.sqrt(x*x+(ro0-y)*(ro0-y)),
1801 | theta = Math.atan( x / (ro0 - y) );
1802 |
1803 | return {
1804 | lat: (Math.asin((C - ro * ro * n * n) / (2 * n))) * this.degRad,
1805 | lng: (lambda0 + theta / n) * this.degRad
1806 | };
1807 | },
1808 |
1809 | /**
1810 | * Converts point on sphere to the Cartesian coordinates using Lambert conformal
1811 | * conic projection
1812 | * @see Lambert Conformal Conic Projection
1813 | * @param {Number} lat Latitude in degrees
1814 | * @param {Number} lng Longitude in degrees
1815 | * @param {Number} c Central meridian in degrees
1816 | */
1817 | lcc: function(lat, lng, c){
1818 | var fi0 = 0,
1819 | lambda0 = c * this.radDeg,
1820 | lambda = lng * this.radDeg,
1821 | fi1 = 33 * this.radDeg,
1822 | fi2 = 45 * this.radDeg,
1823 | fi = lat * this.radDeg,
1824 | n = Math.log( Math.cos(fi1) * (1 / Math.cos(fi2)) ) / Math.log( Math.tan( Math.PI / 4 + fi2 / 2) * (1 / Math.tan( Math.PI / 4 + fi1 / 2) ) ),
1825 | F = ( Math.cos(fi1) * Math.pow( Math.tan( Math.PI / 4 + fi1 / 2 ), n ) ) / n,
1826 | ro = F * Math.pow( 1 / Math.tan( Math.PI / 4 + fi / 2 ), n ),
1827 | ro0 = F * Math.pow( 1 / Math.tan( Math.PI / 4 + fi0 / 2 ), n );
1828 |
1829 | return {
1830 | x: ro * Math.sin( n * (lambda - lambda0) ) * this.radius,
1831 | y: - (ro0 - ro * Math.cos( n * (lambda - lambda0) ) ) * this.radius
1832 | };
1833 | },
1834 |
1835 | /**
1836 | * Converts Cartesian coordinates to the point on sphere using Lambert conformal conic
1837 | * projection
1838 | * @see Lambert Conformal Conic Projection
1839 | * @param {Number} x X of point in Cartesian system as integer
1840 | * @param {Number} y Y of point in Cartesian system as integer
1841 | * @param {Number} c Central meridian in degrees
1842 | */
1843 | lcc_inv: function(xCoord, yCoord, c){
1844 | var x = xCoord / this.radius,
1845 | y = yCoord / this.radius,
1846 | fi0 = 0,
1847 | lambda0 = c * this.radDeg,
1848 | fi1 = 33 * this.radDeg,
1849 | fi2 = 45 * this.radDeg,
1850 | n = Math.log( Math.cos(fi1) * (1 / Math.cos(fi2)) ) / Math.log( Math.tan( Math.PI / 4 + fi2 / 2) * (1 / Math.tan( Math.PI / 4 + fi1 / 2) ) ),
1851 | F = ( Math.cos(fi1) * Math.pow( Math.tan( Math.PI / 4 + fi1 / 2 ), n ) ) / n,
1852 | ro0 = F * Math.pow( 1 / Math.tan( Math.PI / 4 + fi0 / 2 ), n ),
1853 | ro = this.sgn(n) * Math.sqrt(x*x+(ro0-y)*(ro0-y)),
1854 | theta = Math.atan( x / (ro0 - y) );
1855 |
1856 | return {
1857 | lat: (2 * Math.atan(Math.pow(F/ro, 1/n)) - Math.PI / 2) * this.degRad,
1858 | lng: (lambda0 + theta / n) * this.degRad
1859 | };
1860 | }
1861 | };jvm.MapObject = function(config){};
1862 |
1863 | jvm.MapObject.prototype.getLabelText = function(key){
1864 | var text;
1865 |
1866 | if (this.config.label) {
1867 | if (typeof this.config.label.render === 'function') {
1868 | text = this.config.label.render(key);
1869 | } else {
1870 | text = key;
1871 | }
1872 | } else {
1873 | text = null;
1874 | }
1875 | return text;
1876 | }
1877 |
1878 | jvm.MapObject.prototype.getLabelOffsets = function(key){
1879 | var offsets;
1880 |
1881 | if (this.config.label) {
1882 | if (typeof this.config.label.offsets === 'function') {
1883 | offsets = this.config.label.offsets(key);
1884 | } else if (typeof this.config.label.offsets === 'object') {
1885 | offsets = this.config.label.offsets[key];
1886 | }
1887 | }
1888 | return offsets || [0, 0];
1889 | }
1890 |
1891 | /**
1892 | * Set hovered state to the element. Hovered state means mouse cursor is over element. Styles will be updates respectively.
1893 | * @param {Boolean} isHovered true to make element hovered, false otherwise.
1894 | */
1895 | jvm.MapObject.prototype.setHovered = function(isHovered){
1896 | if (this.isHovered !== isHovered) {
1897 | this.isHovered = isHovered;
1898 | this.shape.isHovered = isHovered;
1899 | this.shape.updateStyle();
1900 | if (this.label) {
1901 | this.label.isHovered = isHovered;
1902 | this.label.updateStyle();
1903 | }
1904 | }
1905 | };
1906 |
1907 | /**
1908 | * Set selected state to the element. Styles will be updates respectively.
1909 | * @param {Boolean} isSelected true to make element selected, false otherwise.
1910 | */
1911 | jvm.MapObject.prototype.setSelected = function(isSelected){
1912 | if (this.isSelected !== isSelected) {
1913 | this.isSelected = isSelected;
1914 | this.shape.isSelected = isSelected;
1915 | this.shape.updateStyle();
1916 | if (this.label) {
1917 | this.label.isSelected = isSelected;
1918 | this.label.updateStyle();
1919 | }
1920 | jvm.$(this.shape).trigger('selected', [isSelected]);
1921 | }
1922 | };
1923 |
1924 | jvm.MapObject.prototype.setStyle = function(){
1925 | this.shape.setStyle.apply(this.shape, arguments);
1926 | };
1927 |
1928 | jvm.MapObject.prototype.remove = function(){
1929 | this.shape.remove();
1930 | if (this.label) {
1931 | this.label.remove();
1932 | }
1933 | };jvm.Region = function(config){
1934 | var bbox,
1935 | text,
1936 | offsets,
1937 | labelDx,
1938 | labelDy;
1939 |
1940 | this.config = config;
1941 | this.map = this.config.map;
1942 |
1943 | this.shape = config.canvas.addPath({
1944 | d: config.path,
1945 | 'data-code': config.code
1946 | }, config.style, config.canvas.rootElement);
1947 | this.shape.addClass('jvectormap-region jvectormap-element');
1948 |
1949 | bbox = this.shape.getBBox();
1950 |
1951 | text = this.getLabelText(config.code);
1952 | if (this.config.label && text) {
1953 | offsets = this.getLabelOffsets(config.code);
1954 | this.labelX = bbox.x + bbox.width / 2 + offsets[0];
1955 | this.labelY = bbox.y + bbox.height / 2 + offsets[1];
1956 | this.label = config.canvas.addText({
1957 | text: text,
1958 | 'text-anchor': 'middle',
1959 | 'alignment-baseline': 'central',
1960 | x: this.labelX,
1961 | y: this.labelY,
1962 | 'data-code': config.code
1963 | }, config.labelStyle, config.labelsGroup);
1964 | this.label.addClass('jvectormap-region jvectormap-element');
1965 | }
1966 | };
1967 |
1968 | jvm.inherits(jvm.Region, jvm.MapObject);
1969 |
1970 | jvm.Region.prototype.updateLabelPosition = function(){
1971 | if (this.label) {
1972 | this.label.set({
1973 | x: this.labelX * this.map.scale + this.map.transX * this.map.scale,
1974 | y: this.labelY * this.map.scale + this.map.transY * this.map.scale
1975 | });
1976 | }
1977 | };jvm.Marker = function(config){
1978 | var text,
1979 | offsets;
1980 |
1981 | this.config = config;
1982 | this.map = this.config.map;
1983 |
1984 | this.isImage = !!this.config.style.initial.image;
1985 | this.createShape();
1986 |
1987 | text = this.getLabelText(config.index);
1988 | if (this.config.label && text) {
1989 | this.offsets = this.getLabelOffsets(config.index);
1990 | this.labelX = config.cx / this.map.scale - this.map.transX;
1991 | this.labelY = config.cy / this.map.scale - this.map.transY;
1992 | this.label = config.canvas.addText({
1993 | text: text,
1994 | 'data-index': config.index,
1995 | dy: "0.6ex",
1996 | x: this.labelX,
1997 | y: this.labelY
1998 | }, config.labelStyle, config.labelsGroup);
1999 |
2000 | this.label.addClass('jvectormap-marker jvectormap-element');
2001 | }
2002 | };
2003 |
2004 | jvm.inherits(jvm.Marker, jvm.MapObject);
2005 |
2006 | jvm.Marker.prototype.createShape = function(){
2007 | var that = this;
2008 |
2009 | if (this.shape) {
2010 | this.shape.remove();
2011 | }
2012 | this.shape = this.config.canvas[this.isImage ? 'addImage' : 'addCircle']({
2013 | "data-index": this.config.index,
2014 | cx: this.config.cx,
2015 | cy: this.config.cy
2016 | }, this.config.style, this.config.group);
2017 |
2018 | this.shape.addClass('jvectormap-marker jvectormap-element');
2019 |
2020 | if (this.isImage) {
2021 | jvm.$(this.shape.node).on('imageloaded', function(){
2022 | that.updateLabelPosition();
2023 | });
2024 | }
2025 | };
2026 |
2027 | jvm.Marker.prototype.updateLabelPosition = function(){
2028 | if (this.label) {
2029 | this.label.set({
2030 | x: this.labelX * this.map.scale + this.offsets[0] +
2031 | this.map.transX * this.map.scale + 5 + (this.isImage ? (this.shape.width || 0) / 2 : this.shape.properties.r),
2032 | y: this.labelY * this.map.scale + this.map.transY * this.map.scale + this.offsets[1]
2033 | });
2034 | }
2035 | };
2036 |
2037 | jvm.Marker.prototype.setStyle = function(property, value){
2038 | var isImage;
2039 |
2040 | jvm.Marker.parentClass.prototype.setStyle.apply(this, arguments);
2041 |
2042 | if (property === 'r') {
2043 | this.updateLabelPosition();
2044 | }
2045 |
2046 | isImage = !!this.shape.get('image');
2047 | if (isImage != this.isImage) {
2048 | this.isImage = isImage;
2049 | this.config.style = jvm.$.extend(true, {}, this.shape.style);
2050 | this.createShape();
2051 | }
2052 | };/**
2053 | * Creates map, draws paths, binds events.
2054 | * @constructor
2055 | * @param {Object} params Parameters to initialize map with.
2056 | * @param {String} params.map Name of the map in the format territory_proj_lang where territory is a unique code or name of the territory which the map represents (ISO 3166 standard is used where possible), proj is a name of projection used to generate representation of the map on the plane (projections are named according to the conventions of proj4 utility) and lang is a code of the language, used for the names of regions.
2057 | * @param {String} params.backgroundColor Background color of the map in CSS format.
2058 | * @param {Boolean} params.zoomOnScroll When set to true map could be zoomed using mouse scroll. Default value is true.
2059 | * @param {Boolean} params.panOnDrag When set to true, the map pans when being dragged. Default value is true.
2060 | * @param {Number} params.zoomMax Indicates the maximum zoom ratio which could be reached zooming the map. Default value is 8.
2061 | * @param {Number} params.zoomMin Indicates the minimum zoom ratio which could be reached zooming the map. Default value is 1.
2062 | * @param {Number} params.zoomStep Indicates the multiplier used to zoom map with +/- buttons. Default value is 1.6.
2063 | * @param {Boolean} params.zoomAnimate Indicates whether or not to animate changing of map zoom with zoom buttons.
2064 | * @param {Boolean} params.regionsSelectable When set to true regions of the map could be selected. Default value is false.
2065 | * @param {Boolean} params.regionsSelectableOne Allow only one region to be selected at the moment. Default value is false.
2066 | * @param {Boolean} params.markersSelectable When set to true markers on the map could be selected. Default value is false.
2067 | * @param {Boolean} params.markersSelectableOne Allow only one marker to be selected at the moment. Default value is false.
2068 | * @param {Object} params.regionStyle Set the styles for the map's regions. Each region or marker has four states: initial (default state), hover (when the mouse cursor is over the region or marker), selected (when region or marker is selected), selectedHover (when the mouse cursor is over the region or marker and it's selected simultaneously). Styles could be set for each of this states. Default value for that parameter is:
2069 | {
2070 | initial: {
2071 | fill: 'white',
2072 | "fill-opacity": 1,
2073 | stroke: 'none',
2074 | "stroke-width": 0,
2075 | "stroke-opacity": 1
2076 | },
2077 | hover: {
2078 | "fill-opacity": 0.8,
2079 | cursor: 'pointer'
2080 | },
2081 | selected: {
2082 | fill: 'yellow'
2083 | },
2084 | selectedHover: {
2085 | }
2086 | }
2087 | * @param {Object} params.regionLabelStyle Set the styles for the regions' labels. Each region or marker has four states: initial (default state), hover (when the mouse cursor is over the region or marker), selected (when region or marker is selected), selectedHover (when the mouse cursor is over the region or marker and it's selected simultaneously). Styles could be set for each of this states. Default value for that parameter is:
2088 | {
2089 | initial: {
2090 | 'font-family': 'Verdana',
2091 | 'font-size': '12',
2092 | 'font-weight': 'bold',
2093 | cursor: 'default',
2094 | fill: 'black'
2095 | },
2096 | hover: {
2097 | cursor: 'pointer'
2098 | }
2099 | }
2100 | * @param {Object} params.markerStyle Set the styles for the map's markers. Any parameter suitable for regionStyle could be used as well as numeric parameter r to set the marker's radius. Default value for that parameter is:
2101 | {
2102 | initial: {
2103 | fill: 'grey',
2104 | stroke: '#505050',
2105 | "fill-opacity": 1,
2106 | "stroke-width": 1,
2107 | "stroke-opacity": 1,
2108 | r: 5
2109 | },
2110 | hover: {
2111 | stroke: 'black',
2112 | "stroke-width": 2,
2113 | cursor: 'pointer'
2114 | },
2115 | selected: {
2116 | fill: 'blue'
2117 | },
2118 | selectedHover: {
2119 | }
2120 | }
2121 | * @param {Object} params.markerLabelStyle Set the styles for the markers' labels. Default value for that parameter is:
2122 | {
2123 | initial: {
2124 | 'font-family': 'Verdana',
2125 | 'font-size': '12',
2126 | 'font-weight': 'bold',
2127 | cursor: 'default',
2128 | fill: 'black'
2129 | },
2130 | hover: {
2131 | cursor: 'pointer'
2132 | }
2133 | }
2134 | * @param {Object|Array} params.markers Set of markers to add to the map during initialization. In case of array is provided, codes of markers will be set as string representations of array indexes. Each marker is represented by latLng (array of two numeric values), name (string which will be show on marker's tip) and any marker styles.
2135 | * @param {Object} params.series Object with two keys: markers and regions. Each of which is an array of series configs to be applied to the respective map elements. See DataSeries description for a list of parameters available.
2136 | * @param {Object|String} params.focusOn This parameter sets the initial position and scale of the map viewport. See setFocus docuemntation for possible parameters.
2137 | * @param {Object} params.labels Defines parameters for rendering static labels. Object could contain two keys: regions and markers. Each key value defines configuration object with the following possible options:
2138 | render {Function} - defines method for converting region code or marker index to actual label value.offsets {Object|Function} - provides method or object which could be used to define label offset by region code or marker index.(Event e, Object tip, String code) Will be called right before the region tip is going to be shown.
2146 | * @param {Function} params.onRegionOver (Event e, String code) Will be called on region mouse over event.
2147 | * @param {Function} params.onRegionOut (Event e, String code) Will be called on region mouse out event.
2148 | * @param {Function} params.onRegionClick (Event e, String code) Will be called on region click event.
2149 | * @param {Function} params.onRegionSelected (Event e, String code, Boolean isSelected, Array selectedRegions) Will be called when region is (de)selected. isSelected parameter of the callback indicates whether region is selected or not. selectedRegions contains codes of all currently selected regions.
2150 | * @param {Function} params.onMarkerTipShow (Event e, Object tip, String code) Will be called right before the marker tip is going to be shown.
2151 | * @param {Function} params.onMarkerOver (Event e, String code) Will be called on marker mouse over event.
2152 | * @param {Function} params.onMarkerOut (Event e, String code) Will be called on marker mouse out event.
2153 | * @param {Function} params.onMarkerClick (Event e, String code) Will be called on marker click event.
2154 | * @param {Function} params.onMarkerSelected (Event e, String code, Boolean isSelected, Array selectedMarkers) Will be called when marker is (de)selected. isSelected parameter of the callback indicates whether marker is selected or not. selectedMarkers contains codes of all currently selected markers.
2155 | * @param {Function} params.onViewportChange (Event e, Number scale) Triggered when the map's viewport is changed (map was panned or zoomed).
2156 | */
2157 | jvm.Map = function(params) {
2158 | var map = this,
2159 | e;
2160 |
2161 | this.params = jvm.$.extend(true, {}, jvm.Map.defaultParams, params);
2162 |
2163 | if (!jvm.Map.maps[this.params.map]) {
2164 | throw new Error('Attempt to use map which was not loaded: '+this.params.map);
2165 | }
2166 |
2167 | this.mapData = jvm.Map.maps[this.params.map];
2168 | this.markers = {};
2169 | this.regions = {};
2170 | this.regionsColors = {};
2171 | this.regionsData = {};
2172 |
2173 | this.container = jvm.$('String or Array the region(s) with the corresponding code(s) will be selected. If Object was provided its keys are codes of regions, state of which should be changed. Selected state will be set if value is true, removed otherwise.
2755 | */
2756 | setSelectedRegions: function(keys){
2757 | this.setSelected('regions', keys);
2758 | },
2759 |
2760 | /**
2761 | * Set or remove selected state for the markers.
2762 | * @param {String|Array|Object} keys If String or Array the marker(s) with the corresponding code(s) will be selected. If Object was provided its keys are codes of markers, state of which should be changed. Selected state will be set if value is true, removed otherwise.
2763 | */
2764 | setSelectedMarkers: function(keys){
2765 | this.setSelected('markers', keys);
2766 | },
2767 |
2768 | clearSelected: function(type){
2769 | var select = {},
2770 | selected = this.getSelected(type),
2771 | i;
2772 |
2773 | for (i = 0; i < selected.length; i++) {
2774 | select[selected[i]] = false;
2775 | };
2776 |
2777 | this.setSelected(type, select);
2778 | },
2779 |
2780 | /**
2781 | * Remove the selected state from all the currently selected regions.
2782 | */
2783 | clearSelectedRegions: function(){
2784 | this.clearSelected('regions');
2785 | },
2786 |
2787 | /**
2788 | * Remove the selected state from all the currently selected markers.
2789 | */
2790 | clearSelectedMarkers: function(){
2791 | this.clearSelected('markers');
2792 | },
2793 |
2794 | /**
2795 | * Return the instance of Map. Useful when instantiated as a jQuery plug-in.
2796 | * @returns {Map}
2797 | */
2798 | getMapObject: function(){
2799 | return this;
2800 | },
2801 |
2802 | /**
2803 | * Return the name of the region by region code.
2804 | * @returns {String}
2805 | */
2806 | getRegionName: function(code){
2807 | return this.mapData.paths[code].name;
2808 | },
2809 |
2810 | createRegions: function(){
2811 | var key,
2812 | region,
2813 | map = this;
2814 |
2815 | this.regionLabelsGroup = this.regionLabelsGroup || this.canvas.addGroup();
2816 |
2817 | for (key in this.mapData.paths) {
2818 | region = new jvm.Region({
2819 | map: this,
2820 | path: this.mapData.paths[key].path,
2821 | code: key,
2822 | style: jvm.$.extend(true, {}, this.params.regionStyle),
2823 | labelStyle: jvm.$.extend(true, {}, this.params.regionLabelStyle),
2824 | canvas: this.canvas,
2825 | labelsGroup: this.regionLabelsGroup,
2826 | label: this.canvas.mode != 'vml' ? (this.params.labels && this.params.labels.regions) : null
2827 | });
2828 |
2829 | jvm.$(region.shape).bind('selected', function(e, isSelected){
2830 | map.container.trigger('regionSelected.jvectormap', [jvm.$(this.node).attr('data-code'), isSelected, map.getSelectedRegions()]);
2831 | });
2832 | this.regions[key] = {
2833 | element: region,
2834 | config: this.mapData.paths[key]
2835 | };
2836 | }
2837 | },
2838 |
2839 | createMarkers: function(markers) {
2840 | var i,
2841 | marker,
2842 | point,
2843 | markerConfig,
2844 | markersArray,
2845 | map = this;
2846 |
2847 | this.markersGroup = this.markersGroup || this.canvas.addGroup();
2848 | this.markerLabelsGroup = this.markerLabelsGroup || this.canvas.addGroup();
2849 |
2850 | if (jvm.$.isArray(markers)) {
2851 | markersArray = markers.slice();
2852 | markers = {};
2853 | for (i = 0; i < markersArray.length; i++) {
2854 | markers[i] = markersArray[i];
2855 | }
2856 | }
2857 |
2858 | for (i in markers) {
2859 | markerConfig = markers[i] instanceof Array ? {latLng: markers[i]} : markers[i];
2860 | point = this.getMarkerPosition( markerConfig );
2861 |
2862 | if (point !== false) {
2863 | marker = new jvm.Marker({
2864 | map: this,
2865 | style: jvm.$.extend(true, {}, this.params.markerStyle, {initial: markerConfig.style || {}}),
2866 | labelStyle: jvm.$.extend(true, {}, this.params.markerLabelStyle),
2867 | index: i,
2868 | cx: point.x,
2869 | cy: point.y,
2870 | group: this.markersGroup,
2871 | canvas: this.canvas,
2872 | labelsGroup: this.markerLabelsGroup,
2873 | label: this.canvas.mode != 'vml' ? (this.params.labels && this.params.labels.markers) : null
2874 | });
2875 |
2876 | jvm.$(marker.shape).bind('selected', function(e, isSelected){
2877 | map.container.trigger('markerSelected.jvectormap', [jvm.$(this.node).attr('data-index'), isSelected, map.getSelectedMarkers()]);
2878 | });
2879 | if (this.markers[i]) {
2880 | this.removeMarkers([i]);
2881 | }
2882 | this.markers[i] = {element: marker, config: markerConfig};
2883 | }
2884 | }
2885 | },
2886 |
2887 | repositionMarkers: function() {
2888 | var i,
2889 | point;
2890 |
2891 | for (i in this.markers) {
2892 | point = this.getMarkerPosition( this.markers[i].config );
2893 | if (point !== false) {
2894 | this.markers[i].element.setStyle({cx: point.x, cy: point.y});
2895 | }
2896 | }
2897 | },
2898 |
2899 | repositionLabels: function() {
2900 | var key;
2901 |
2902 | for (key in this.regions) {
2903 | this.regions[key].element.updateLabelPosition();
2904 | }
2905 |
2906 | for (key in this.markers) {
2907 | this.markers[key].element.updateLabelPosition();
2908 | }
2909 | },
2910 |
2911 | getMarkerPosition: function(markerConfig) {
2912 | if (jvm.Map.maps[this.params.map].projection) {
2913 | return this.latLngToPoint.apply(this, markerConfig.latLng || [0, 0]);
2914 | } else {
2915 | return {
2916 | x: markerConfig.coords[0]*this.scale + this.transX*this.scale,
2917 | y: markerConfig.coords[1]*this.scale + this.transY*this.scale
2918 | };
2919 | }
2920 | },
2921 |
2922 | /**
2923 | * Add one marker to the map.
2924 | * @param {String} key Marker unique code.
2925 | * @param {Object} marker Marker configuration parameters.
2926 | * @param {Array} seriesData Values to add to the data series.
2927 | */
2928 | addMarker: function(key, marker, seriesData){
2929 | var markers = {},
2930 | data = [],
2931 | values,
2932 | i,
2933 | seriesData = seriesData || [];
2934 |
2935 | markers[key] = marker;
2936 |
2937 | for (i = 0; i < seriesData.length; i++) {
2938 | values = {};
2939 | if (typeof seriesData[i] !== 'undefined') {
2940 | values[key] = seriesData[i];
2941 | }
2942 | data.push(values);
2943 | }
2944 | this.addMarkers(markers, data);
2945 | },
2946 |
2947 | /**
2948 | * Add set of marker to the map.
2949 | * @param {Object|Array} markers Markers to add to the map. In case of array is provided, codes of markers will be set as string representations of array indexes.
2950 | * @param {Array} seriesData Values to add to the data series.
2951 | */
2952 | addMarkers: function(markers, seriesData){
2953 | var i;
2954 |
2955 | seriesData = seriesData || [];
2956 |
2957 | this.createMarkers(markers);
2958 | for (i = 0; i < seriesData.length; i++) {
2959 | this.series.markers[i].setValues(seriesData[i] || {});
2960 | };
2961 | },
2962 |
2963 | /**
2964 | * Remove some markers from the map.
2965 | * @param {Array} markers Array of marker codes to be removed.
2966 | */
2967 | removeMarkers: function(markers){
2968 | var i;
2969 |
2970 | for (i = 0; i < markers.length; i++) {
2971 | this.markers[ markers[i] ].element.remove();
2972 | delete this.markers[ markers[i] ];
2973 | };
2974 | },
2975 |
2976 | /**
2977 | * Remove all markers from the map.
2978 | */
2979 | removeAllMarkers: function(){
2980 | var i,
2981 | markers = [];
2982 |
2983 | for (i in this.markers) {
2984 | markers.push(i);
2985 | }
2986 | this.removeMarkers(markers)
2987 | },
2988 |
2989 | /**
2990 | * Converts coordinates expressed as latitude and longitude to the coordinates in pixels on the map.
2991 | * @param {Number} lat Latitide of point in degrees.
2992 | * @param {Number} lng Longitude of point in degrees.
2993 | */
2994 | latLngToPoint: function(lat, lng) {
2995 | var point,
2996 | proj = jvm.Map.maps[this.params.map].projection,
2997 | centralMeridian = proj.centralMeridian,
2998 | inset,
2999 | bbox;
3000 |
3001 | if (lng < (-180 + centralMeridian)) {
3002 | lng += 360;
3003 | }
3004 |
3005 | point = jvm.Proj[proj.type](lat, lng, centralMeridian);
3006 |
3007 | inset = this.getInsetForPoint(point.x, point.y);
3008 | if (inset) {
3009 | bbox = inset.bbox;
3010 |
3011 | point.x = (point.x - bbox[0].x) / (bbox[1].x - bbox[0].x) * inset.width * this.scale;
3012 | point.y = (point.y - bbox[0].y) / (bbox[1].y - bbox[0].y) * inset.height * this.scale;
3013 |
3014 | return {
3015 | x: point.x + this.transX*this.scale + inset.left*this.scale,
3016 | y: point.y + this.transY*this.scale + inset.top*this.scale
3017 | };
3018 | } else {
3019 | return false;
3020 | }
3021 | },
3022 |
3023 | /**
3024 | * Converts cartesian coordinates into coordinates expressed as latitude and longitude.
3025 | * @param {Number} x X-axis of point on map in pixels.
3026 | * @param {Number} y Y-axis of point on map in pixels.
3027 | */
3028 | pointToLatLng: function(x, y) {
3029 | var proj = jvm.Map.maps[this.params.map].projection,
3030 | centralMeridian = proj.centralMeridian,
3031 | insets = jvm.Map.maps[this.params.map].insets,
3032 | i,
3033 | inset,
3034 | bbox,
3035 | nx,
3036 | ny;
3037 |
3038 | for (i = 0; i < insets.length; i++) {
3039 | inset = insets[i];
3040 | bbox = inset.bbox;
3041 |
3042 | nx = x - (this.transX*this.scale + inset.left*this.scale);
3043 | ny = y - (this.transY*this.scale + inset.top*this.scale);
3044 |
3045 | nx = (nx / (inset.width * this.scale)) * (bbox[1].x - bbox[0].x) + bbox[0].x;
3046 | ny = (ny / (inset.height * this.scale)) * (bbox[1].y - bbox[0].y) + bbox[0].y;
3047 |
3048 | if (nx > bbox[0].x && nx < bbox[1].x && ny > bbox[0].y && ny < bbox[1].y) {
3049 | return jvm.Proj[proj.type + '_inv'](nx, -ny, centralMeridian);
3050 | }
3051 | }
3052 |
3053 | return false;
3054 | },
3055 |
3056 | getInsetForPoint: function(x, y){
3057 | var insets = jvm.Map.maps[this.params.map].insets,
3058 | i,
3059 | bbox;
3060 |
3061 | for (i = 0; i < insets.length; i++) {
3062 | bbox = insets[i].bbox;
3063 | if (x > bbox[0].x && x < bbox[1].x && y > bbox[0].y && y < bbox[1].y) {
3064 | return insets[i];
3065 | }
3066 | }
3067 | },
3068 |
3069 | createSeries: function(){
3070 | var i,
3071 | key;
3072 |
3073 | this.series = {
3074 | markers: [],
3075 | regions: []
3076 | };
3077 |
3078 | for (key in this.params.series) {
3079 | for (i = 0; i < this.params.series[key].length; i++) {
3080 | this.series[key][i] = new jvm.DataSeries(
3081 | this.params.series[key][i],
3082 | this[key],
3083 | this
3084 | );
3085 | }
3086 | }
3087 | },
3088 |
3089 | /**
3090 | * Gracefully remove the map and and all its accessories, unbind event handlers.
3091 | */
3092 | remove: function(){
3093 | this.tip.remove();
3094 | this.container.remove();
3095 | jvm.$(window).unbind('resize', this.onResize);
3096 | jvm.$('body').unbind('mouseup', this.onContainerMouseUp);
3097 | }
3098 | };
3099 |
3100 | jvm.Map.maps = {};
3101 | jvm.Map.defaultParams = {
3102 | map: 'world_mill_en',
3103 | backgroundColor: '#505050',
3104 | zoomButtons: true,
3105 | zoomOnScroll: true,
3106 | panOnDrag: true,
3107 | zoomMax: 8,
3108 | zoomMin: 1,
3109 | zoomStep: 1.6,
3110 | zoomAnimate: true,
3111 | regionsSelectable: false,
3112 | markersSelectable: false,
3113 | bindTouchEvents: true,
3114 | regionStyle: {
3115 | initial: {
3116 | fill: 'white',
3117 | "fill-opacity": 1,
3118 | stroke: 'none',
3119 | "stroke-width": 0,
3120 | "stroke-opacity": 1
3121 | },
3122 | hover: {
3123 | "fill-opacity": 0.8,
3124 | cursor: 'pointer'
3125 | },
3126 | selected: {
3127 | fill: 'yellow'
3128 | },
3129 | selectedHover: {
3130 | }
3131 | },
3132 | regionLabelStyle: {
3133 | initial: {
3134 | 'font-family': 'Verdana',
3135 | 'font-size': '12',
3136 | 'font-weight': 'bold',
3137 | cursor: 'default',
3138 | fill: 'black'
3139 | },
3140 | hover: {
3141 | cursor: 'pointer'
3142 | }
3143 | },
3144 | markerStyle: {
3145 | initial: {
3146 | fill: 'grey',
3147 | stroke: '#505050',
3148 | "fill-opacity": 1,
3149 | "stroke-width": 1,
3150 | "stroke-opacity": 1,
3151 | r: 5
3152 | },
3153 | hover: {
3154 | stroke: 'black',
3155 | "stroke-width": 2,
3156 | cursor: 'pointer'
3157 | },
3158 | selected: {
3159 | fill: 'blue'
3160 | },
3161 | selectedHover: {
3162 | }
3163 | },
3164 | markerLabelStyle: {
3165 | initial: {
3166 | 'font-family': 'Verdana',
3167 | 'font-size': '12',
3168 | 'font-weight': 'bold',
3169 | cursor: 'default',
3170 | fill: 'black'
3171 | },
3172 | hover: {
3173 | cursor: 'pointer'
3174 | }
3175 | }
3176 | };
3177 | jvm.Map.apiEvents = {
3178 | onRegionTipShow: 'regionTipShow',
3179 | onRegionOver: 'regionOver',
3180 | onRegionOut: 'regionOut',
3181 | onRegionClick: 'regionClick',
3182 | onRegionSelected: 'regionSelected',
3183 | onMarkerTipShow: 'markerTipShow',
3184 | onMarkerOver: 'markerOver',
3185 | onMarkerOut: 'markerOut',
3186 | onMarkerClick: 'markerClick',
3187 | onMarkerSelected: 'markerSelected',
3188 | onViewportChange: 'viewportChange'
3189 | };
3190 | /**
3191 | * Creates map with drill-down functionality.
3192 | * @constructor
3193 | * @param {Object} params Parameters to initialize map with.
3194 | * @param {Number} params.maxLevel Maximum number of levels user can go through
3195 | * @param {Object} params.main Config of the main map. See jvm.Map for more information.
3196 | * @param {Function} params.mapNameByCode Function go generate map name by region code. Default value is:
3197 |
3198 | function(code, multiMap) {
3199 | return code.toLowerCase()+'_'+
3200 | multiMap.defaultProjection+'_en';
3201 | }
3202 |
3203 | * @param {Function} params.mapUrlByCode Function to generate map url by region code. Default value is:
3204 |
3205 | function(code, multiMap){
3206 | return 'jquery-jvectormap-data-'+
3207 | code.toLowerCase()+'-'+
3208 | multiMap.defaultProjection+'-en.js';
3209 | }
3210 |
3211 | */
3212 | jvm.MultiMap = function(params) {
3213 | var that = this;
3214 |
3215 | this.maps = {};
3216 | this.params = jvm.$.extend(true, {}, jvm.MultiMap.defaultParams, params);
3217 | this.params.maxLevel = this.params.maxLevel || Number.MAX_VALUE;
3218 | this.params.main = this.params.main || {};
3219 | this.params.main.multiMapLevel = 0;
3220 | this.history = [ this.addMap(this.params.main.map, this.params.main) ];
3221 | this.defaultProjection = this.history[0].mapData.projection.type;
3222 | this.mapsLoaded = {};
3223 |
3224 | this.params.container.css({position: 'relative'});
3225 | this.backButton = jvm.$('').addClass('jvectormap-goback').text('Back').appendTo(this.params.container);
3226 | this.backButton.hide();
3227 | this.backButton.click(function(){
3228 | that.goBack();
3229 | });
3230 |
3231 | this.spinner = jvm.$('').addClass('jvectormap-spinner').appendTo(this.params.container);
3232 | this.spinner.hide();
3233 | };
3234 |
3235 | jvm.MultiMap.prototype = {
3236 | addMap: function(name, config){
3237 | var cnt = jvm.$('').css({
3238 | width: '100%',
3239 | height: '100%'
3240 | });
3241 |
3242 | this.params.container.append(cnt);
3243 |
3244 | this.maps[name] = new jvm.Map(jvm.$.extend(config, {container: cnt}));
3245 | if (this.params.maxLevel > config.multiMapLevel) {
3246 | this.maps[name].container.on('regionClick.jvectormap', {scope: this}, function(e, code){
3247 | var multimap = e.data.scope,
3248 | mapName = multimap.params.mapNameByCode(code, multimap);
3249 |
3250 | if (!multimap.drillDownPromise || multimap.drillDownPromise.state() !== 'pending') {
3251 | multimap.drillDown(mapName, code);
3252 | }
3253 | });
3254 | }
3255 |
3256 |
3257 | return this.maps[name];
3258 | },
3259 |
3260 | downloadMap: function(code){
3261 | var that = this,
3262 | deferred = jvm.$.Deferred();
3263 |
3264 | if (!this.mapsLoaded[code]) {
3265 | jvm.$.get(this.params.mapUrlByCode(code, this)).then(function(){
3266 | that.mapsLoaded[code] = true;
3267 | deferred.resolve();
3268 | }, function(){
3269 | deferred.reject();
3270 | });
3271 | } else {
3272 | deferred.resolve();
3273 | }
3274 | return deferred;
3275 | },
3276 |
3277 | drillDown: function(name, code){
3278 | var currentMap = this.history[this.history.length - 1],
3279 | that = this,
3280 | focusPromise = currentMap.setFocus({region: code, animate: true}),
3281 | downloadPromise = this.downloadMap(code);
3282 |
3283 | focusPromise.then(function(){
3284 | if (downloadPromise.state() === 'pending') {
3285 | that.spinner.show();
3286 | }
3287 | });
3288 | downloadPromise.always(function(){
3289 | that.spinner.hide();
3290 | });
3291 | this.drillDownPromise = jvm.$.when(downloadPromise, focusPromise);
3292 | this.drillDownPromise.then(function(){
3293 | currentMap.params.container.hide();
3294 | if (!that.maps[name]) {
3295 | that.addMap(name, {map: name, multiMapLevel: currentMap.params.multiMapLevel + 1});
3296 | } else {
3297 | that.maps[name].params.container.show();
3298 | }
3299 | that.history.push( that.maps[name] );
3300 | that.backButton.show();
3301 | });
3302 | },
3303 |
3304 | goBack: function(){
3305 | var currentMap = this.history.pop(),
3306 | prevMap = this.history[this.history.length - 1],
3307 | that = this;
3308 |
3309 | currentMap.setFocus({scale: 1, x: 0.5, y: 0.5, animate: true}).then(function(){
3310 | currentMap.params.container.hide();
3311 | prevMap.params.container.show();
3312 | prevMap.updateSize();
3313 | if (that.history.length === 1) {
3314 | that.backButton.hide();
3315 | }
3316 | prevMap.setFocus({scale: 1, x: 0.5, y: 0.5, animate: true});
3317 | });
3318 | }
3319 | };
3320 |
3321 | jvm.MultiMap.defaultParams = {
3322 | mapNameByCode: function(code, multiMap){
3323 | return code.toLowerCase()+'_'+multiMap.defaultProjection+'_en';
3324 | },
3325 | mapUrlByCode: function(code, multiMap){
3326 | return 'jquery-jvectormap-data-'+code.toLowerCase()+'-'+multiMap.defaultProjection+'-en.js';
3327 | }
3328 | }
3329 |
--------------------------------------------------------------------------------