JavaScript TypeScript / ES6 ...
<style >
#chartdiv {
width : 100% ;
height : 600px ;
max-width : 100% ;
}
</style >
<script src ="https://cdn.amcharts.com/lib/4/core.js" > </script >
<script src ="https://cdn.amcharts.com/lib/4/maps.js" > </script >
<script src ="https://cdn.amcharts.com/lib/4/themes/animated.js" > </script >
<script >
am4core.ready (function ( ) {
am4core.useTheme (am4themes_animated);
var availableCountries = ["US" , "SS" , "NZ" , "LT" , "LU" , "MK" , "MG" , "MW" , "MY" , "ML" , "MR" , "MX" , "MD" , "MN" , "ME" , "MA" , "MZ" , "NA" , "NP" , "NL" , "KW" , "KG" , "LA" , "LV" , "LB" , "LS" , "LR" , "LY" , "KR" , "JO" , "KZ" , "KE" , "KP" , "JP" , "IT" , "JM" , "IL" , "IR" , "IQ" , "IE" , "ID" , "IN" , "HN" , "HU" , "IS" , "HT" , "ER" , "EE" , "ET" , "FI" , "FR" , "GA" , "GM" , "GE" , "DE" , "GH" , "GR" , "GL" , "GQ" , "EC" , "EG" , "SV" , "DJ" , "DK" , "CZ" , "CY" , "CU" , "HR" , "CI" , "CR" , "CG" , "CD" , "CO" , "CN" , "CL" , "TD" , "CF" , "CA" , "KH" , "CM" , "BI" , "MM" , "BF" , "BG" , "BR" , "BW" , "BA" , "BO" , "BT" , "BJ" , "BZ" , "BE" , "BY" , "AM" , "AZ" , "BD" , "AT" , "AU" , "AR" , "AO" , "DZ" , "AL" , "GT" , "GN" , "GW" , "GY" , "NI" , "NE" , "NG" , "NO" , "OM" , "PK" , "PA" , "PG" , "PY" , "PE" , "PH" , "PL" , "PT" , "PR" , "RO" , "RU" , "RW" , "SA" , "SN" , "RS" , "SL" , "SK" , "SI" , "SO" , "ZA" , "ES" , "LK" , "SD" , "SR" , "SZ" , "SE" , "CH" , "SY" , "TW" , "TJ" , "TZ" , "TH" , "TN" , "TR" , "TM" , "UG" , "UA" , "AE" , "GB" , "UY" , "UZ" , "VE" , "VN" , "YE" , "ZM" , "ZW" ];
var selectedPolygon;
var userCountryId;
var mapChart;
var continentsSeries;
var countriesSeries;
var nextButton;
var slider;
var mainContainer;
var flagContainer;
var colorSet = new am4core.ColorSet ();
var heartAnimation;
var flag;
var countryName;
var ds = new am4core.DataSource ();
ds.url = "https://services.amcharts.com/ip/?v=xz6Z" ;
ds.events .on ("ended" , function (ev ) {
if (ev.target .data ) {
userCountryId = ev.target .data .country_code ;
}
});
ds.load ();
ds.events .on ("ended" , init);
function init ( ) {
mainContainer = am4core.create ("chartdiv" , am4core.Container );
mainContainer.background .fillOpacity = 1 ;
mainContainer.background .fill = am4core.color ("#313950" );
mainContainer.width = am4core.percent (100 );
mainContainer.height = am4core.percent (100 );
mainContainer.preloader .disabled = true ;
slider = mainContainer.createChild (am4core.Slider );
slider.isMeasured = false ;
slider.background .fillOpacity = 0.15 ;
slider.x = am4core.percent (50 );
slider.y = am4core.percent (90 );
slider.start = 0 ;
slider.horizontalCenter = "middle" ;
slider.verticalCenter = "middle" ;
slider.width = 300 ;
slider.zIndex = 100 ;
slider.background .fillOpacity = 0.15 ;
slider.startGrip .background .fillOpacity = 0.8 ;
slider.startGrip .background .fill = am4core.color ("#0975da" );
slider.startGrip .background .stroke = am4core.color ("#0975da" );
slider.startGrip .background .states .getKey ("hover" ).properties .fill = am4core.color ("#0975da" );
var downState = slider.startGrip .background .states .getKey ("down" );
downState .properties .fill = am4core.color ("#0996f2" );
slider.events .on ("rangechanged" , handleSlider);
var triangle = new am4core.Triangle ();
triangle.width = 8 ;
triangle.height = 10 ;
triangle.fill = am4core.color ("#ffffff" );
triangle.direction = "right" ;
triangle.valign = "middle" ;
triangle.align = "center" ;
triangle.dx = 1 ;
nextButton = mainContainer.createChild (am4core.Button );
nextButton.horizontalCenter = "middle" ;
nextButton.verticalCenter = "middle" ;
nextButton.padding (0 , 0 , 0 , 0 );
nextButton.background .cornerRadius (25 , 25 , 25 , 25 );
nextButton.x = am4core.percent (80 );
nextButton.y = am4core.percent (90 );
nextButton.width = 40 ;
nextButton.height = 40 ;
nextButton.zIndex = 101 ;
nextButton.icon = triangle;
nextButton.background .fillOpacity = 0 ;
nextButton.background .states .getKey ("hover" ).properties .fill = am4core.color ("#0975da" );
nextButton.background .stroke = am4core.color ("#0975da" );
nextButton.background .states .getKey ("down" ).properties .fill = am4core.color ("#0975da" );
var label = mainContainer.createChild (am4core.Label )
label.text = "next" ;
label.x = am4core.percent (80 );
label.y = am4core.percent (90 );
label.verticalCenter = "middle" ;
label.horizontalCenter = "right" ;
label.dx = -25 ;
label.dy = -2 ;
label.fill = am4core.color ("#ffffff" );
label.events .on ("over" , function ( ) {
nextButton.isHover = true ;
});
label.events .on ("out" , function ( ) {
nextButton.isHover = false ;
});
nextButton.events .on ("hit" , handleNext);
label.events .on ("hit" , handleNext);
flagContainer = mainContainer.createChild (am4core.Container );
flagContainer.horizontalCenter = "middle" ;
flagContainer.hiddenState .properties .dy = -180 ;
flagContainer.x = am4core.percent (50 );
flagContainer.y = 30 ;
flagContainer.layout = "horizontal" ;
flag = flagContainer.createChild (am4core.Image );
flag.width = 50 ;
flag.height = 50 ;
countryName = flagContainer.createChild (am4core.Label );
countryName.marginLeft = 15 ;
countryName.fontSize = 25 ;
countryName.x = 100 ;
countryName.valign = "middle" ;
countryName.fill = am4core.color ("#ffffff" );
createMap ();
}
function createMap ( ) {
mapChart = mainContainer.createChild (am4maps.MapChart );
mapChart.zIndex = -1 ;
mapChart.maxZoomLevel = 2000 ;
mapChart.projection = new am4maps.projections .Mercator ();
mapChart.seriesContainer .events .disableType ("doublehit" );
mapChart.chartContainer .background .events .disableType ("doublehit" );
mapChart.deltaLongitude = -11 ;
mapChart.seriesContainer .draggable = false ;
mapChart.geodataSource .url = "//www.amcharts.com/lib/4/geodata/json/continentsHigh.json" ;
mapChart.seriesContainer .resizable = false ;
mapChart.mouseWheelBehavior = "none" ;
continentsSeries = mapChart.series .push (new am4maps.MapPolygonSeries ());
continentsSeries.useGeodata = true ;
continentsSeries.exclude = ["antarctica" ];
continentsSeries.mapPolygons .template .fill = am4core.color ("#283047" );
continentsSeries.mapPolygons .template .strokeOpacity = 0 ;
continentsSeries.toBack ();
countriesSeries = mapChart.series .push (new am4maps.MapPolygonSeries ());
countriesSeries.useGeodata = true ;
countriesSeries.exclude = ["AQ" ];
countriesSeries.mapPolygons .template .visible = false ;
countriesSeries.mapPolygons .template .hiddenState .properties .opacity = 0 ;
countriesSeries.geodataSource .url = "//www.amcharts.com/wp-content/uploads/assets/maps/worldCustomHigh.json" ;
countriesSeries.mapPolygons .template .fill = am4core.color ("#0975da" );
countriesSeries.mapPolygons .template .strokeOpacity = 0 ;
countriesSeries.geodataSource .events .on ("ended" , function ( ) {
setTimeout (function ( ) {
handleNext (userCountryId);
}, 500 )
});
}
function handleNext (countryId ) {
flagContainer.hide (1000 );
if (availableCountries.indexOf (countryId) == -1 ) {
userCountryId = availableCountries[Math .floor (Math .random () * availableCountries.length )];
}
if (slider.start > 0 ) {
var animation = slider.animate ({ property : "start" , to : 0 }, 500 );
animation.events .on ("animationended" , function ( ) {
setTimeout (function ( ) {
zoomToSelectedPolygon ()
}, 100 );
});
}
else {
zoomToSelectedPolygon ();
}
}
function zoomToSelectedPolygon ( ) {
if (selectedPolygon) {
selectedPolygon.hide ();
}
selectedPolygon = countriesSeries.getPolygonById (userCountryId);
selectedPolygon.hide (0 );
selectedPolygon.opacity = 0 ;
selectedPolygon.defaultState .properties .opacity = 1 ;
selectedPolygon.toFront ();
var showAnimation = selectedPolygon.show (1000 );
showAnimation.events .on ("animationended" , function ( ) {
flag.href = "//www.amcharts.com/wp-content/uploads/assets/flags/" + userCountryId.toLowerCase () + ".svg" ;
countryName.text = selectedPolygon.dataItem .dataContext .name ;
setTimeout (function ( ) {
flagContainer.show ();
}, 1000 )
selectedPolygon.polygon .validate ();
var w = selectedPolygon.polygon .bbox .width ;
var h = selectedPolygon.polygon .bbox .height ;
var x = selectedPolygon.polygon .bbox .x + w / 2 ;
var y = selectedPolygon.polygon .bbox .y + h / 2 ;
w = Math .max (w, h);
var path = am4core.path .moveTo ({ x : x, y : y + w / 3 });
path += am4core.path .cubicCurveTo ({ x : x, y : y - w / 4 }, { x : x - w / 2 - w / 4 , y : y - w / 3 }, { x : x - w / 8 , y : y - w / 2 });
path += am4core.path .cubicCurveTo ({ x : x, y : y + w / 3 }, { x : x + w / 8 , y : y - w / 2 }, { x : x + w / 2 + w / 4 , y : y - w / 3 });
var points = am4core.path .pathToPoints (path, 300 );
var middleLatitude = mapChart.zoomGeoPoint .latitude + (selectedPolygon.latitude - mapChart.zoomGeoPoint .latitude ) / 2 ;
var middleLongitude = mapChart.zoomGeoPoint .longitude + (selectedPolygon.longitude - mapChart.zoomGeoPoint .longitude ) / 2 ;
mapChart.zoomEasing = am4core.ease .sinOut ;
var zoomOutAnimation = mapChart.zoomToGeoPoint ({ latitude : middleLatitude, longitude : middleLongitude }, 2 , true );
zoomOutAnimation.events .on ("animationended" , function ( ) {
mapChart.zoomEasing = am4core.ease .cubicInOut ;
mapChart.zoomToMapObject (selectedPolygon, 400 / Math .max (w, h) * mapChart.scaleRatio , true , 1500 );
selectedPolygon.polygon .points ;
selectedPolygon.polygon .morpher .morphToSingle = true ;
var animation;
if (points) {
animation = selectedPolygon.polygon .morpher .morphToPolygon ([[points]]);
}
else {
animation = selectedPolygon.polygon .morpher .morphToCircle ();
}
animation.stop ();
})
})
}
function handleSlider ( ) {
if (selectedPolygon) {
selectedPolygon.polygon .morpher .morphProgress = slider.start ;
if (slider.start >= 0.999 ) {
if (!heartAnimation) {
heartBeet (mapChart.zoomLevel / 1000 );
}
}
else {
if (heartAnimation) {
heartAnimation.kill ();
heartAnimation = undefined ;
}
}
}
}
function heartBeet (scale ) {
heartAnimation = mapChart.animate ({ property : "scale" , to : 1 + scale / 7 }, 200 );
heartAnimation.events .on ("animationended" , function ( ) {
heartAnimation = mapChart.animate ([{ property : "scale" , to : 1 }], 100 );
heartAnimation.events .on ("animationended" , function ( ) {
setTimeout (function ( ) { heartBeet (scale) }, 500 )
})
})
}
});
</script >
<div id ="chartdiv" > </div >
import * as am4core from "@amcharts/amcharts4/core" ;
import * as am4maps from "@amcharts/amcharts4/maps" ;
import am4themes_animated from "@amcharts/amcharts4/themes/animated" ;
am4core.useTheme (am4themes_animated);
let availableCountries = ["US" , "SS" , "NZ" , "LT" , "LU" , "MK" , "MG" , "MW" , "MY" , "ML" , "MR" , "MX" , "MD" , "MN" , "ME" , "MA" , "MZ" , "NA" , "NP" , "NL" , "KW" , "KG" , "LA" , "LV" , "LB" , "LS" , "LR" , "LY" , "KR" , "JO" , "KZ" , "KE" , "KP" , "JP" , "IT" , "JM" , "IL" , "IR" , "IQ" , "IE" , "ID" , "IN" , "HN" , "HU" , "IS" , "HT" , "ER" , "EE" , "ET" , "FI" , "FR" , "GA" , "GM" , "GE" , "DE" , "GH" , "GR" , "GL" , "GQ" , "EC" , "EG" , "SV" , "DJ" , "DK" , "CZ" , "CY" , "CU" , "HR" , "CI" , "CR" , "CG" , "CD" , "CO" , "CN" , "CL" , "TD" , "CF" , "CA" , "KH" , "CM" , "BI" , "MM" , "BF" , "BG" , "BR" , "BW" , "BA" , "BO" , "BT" , "BJ" , "BZ" , "BE" , "BY" , "AM" , "AZ" , "BD" , "AT" , "AU" , "AR" , "AO" , "DZ" , "AL" , "GT" , "GN" , "GW" , "GY" , "NI" , "NE" , "NG" , "NO" , "OM" , "PK" , "PA" , "PG" , "PY" , "PE" , "PH" , "PL" , "PT" , "PR" , "RO" , "RU" , "RW" , "SA" , "SN" , "RS" , "SL" , "SK" , "SI" , "SO" , "ZA" , "ES" , "LK" , "SD" , "SR" , "SZ" , "SE" , "CH" , "SY" , "TW" , "TJ" , "TZ" , "TH" , "TN" , "TR" , "TM" , "UG" , "UA" , "AE" , "GB" , "UY" , "UZ" , "VE" , "VN" , "YE" , "ZM" , "ZW" ];
let selectedPolygon;
let userCountryId;
let mapChart;
let continentsSeries;
let countriesSeries;
let nextButton;
let slider;
let mainContainer;
let flagContainer;
let colorSet = new am4core.ColorSet ();
let heartAnimation;
let flag;
let countryName;
let ds = new am4core.DataSource ();
ds.url = "https://services.amcharts.com/ip/?v=xz6Z" ;
ds.events .on ("ended" , function (ev ) {
if (ev.target .data ) {
userCountryId = ev.target .data .country_code ;
}
});
ds.load ();
ds.events .on ("ended" , init);
function init ( ) {
mainContainer = am4core.create ("chartdiv" , am4core.Container );
mainContainer.background .fillOpacity = 1 ;
mainContainer.background .fill = am4core.color ("#313950" );
mainContainer.width = am4core.percent (100 );
mainContainer.height = am4core.percent (100 );
mainContainer.preloader .disabled = true ;
slider = mainContainer.createChild (am4core.Slider );
slider.isMeasured = false ;
slider.background .fillOpacity = 0.15 ;
slider.x = am4core.percent (50 );
slider.y = am4core.percent (90 );
slider.start = 0 ;
slider.horizontalCenter = "middle" ;
slider.verticalCenter = "middle" ;
slider.width = 300 ;
slider.zIndex = 100 ;
slider.background .fillOpacity = 0.15 ;
slider.startGrip .background .fillOpacity = 0.8 ;
slider.startGrip .background .fill = am4core.color ("#0975da" );
slider.startGrip .background .stroke = am4core.color ("#0975da" );
slider.startGrip .background .states .getKey ("hover" ).properties .fill = am4core.color ("#0975da" );
let downState = slider.startGrip .background .states .getKey ("down" );
downState .properties .fill = am4core.color ("#0996f2" );
slider.events .on ("rangechanged" , handleSlider);
let triangle = new am4core.Triangle ();
triangle.width = 8 ;
triangle.height = 10 ;
triangle.fill = am4core.color ("#ffffff" );
triangle.direction = "right" ;
triangle.valign = "middle" ;
triangle.align = "center" ;
triangle.dx = 1 ;
nextButton = mainContainer.createChild (am4core.Button );
nextButton.horizontalCenter = "middle" ;
nextButton.verticalCenter = "middle" ;
nextButton.padding (0 , 0 , 0 , 0 );
nextButton.background .cornerRadius (25 , 25 , 25 , 25 );
nextButton.x = am4core.percent (80 );
nextButton.y = am4core.percent (90 );
nextButton.width = 40 ;
nextButton.height = 40 ;
nextButton.zIndex = 101 ;
nextButton.icon = triangle;
nextButton.background .fillOpacity = 0 ;
nextButton.background .states .getKey ("hover" ).properties .fill = am4core.color ("#0975da" );
nextButton.background .stroke = am4core.color ("#0975da" );
nextButton.background .states .getKey ("down" ).properties .fill = am4core.color ("#0975da" );
let label = mainContainer.createChild (am4core.Label )
label.text = "next" ;
label.x = am4core.percent (80 );
label.y = am4core.percent (90 );
label.verticalCenter = "middle" ;
label.horizontalCenter = "right" ;
label.dx = -25 ;
label.dy = -2 ;
label.fill = am4core.color ("#ffffff" );
label.events .on ("over" , function ( ) {
nextButton.isHover = true ;
});
label.events .on ("out" , function ( ) {
nextButton.isHover = false ;
});
nextButton.events .on ("hit" , handleNext);
label.events .on ("hit" , handleNext);
flagContainer = mainContainer.createChild (am4core.Container );
flagContainer.horizontalCenter = "middle" ;
flagContainer.hiddenState .properties .dy = -180 ;
flagContainer.x = am4core.percent (50 );
flagContainer.y = 30 ;
flagContainer.layout = "horizontal" ;
flag = flagContainer.createChild (am4core.Image );
flag.width = 50 ;
flag.height = 50 ;
countryName = flagContainer.createChild (am4core.Label );
countryName.marginLeft = 15 ;
countryName.fontSize = 25 ;
countryName.x = 100 ;
countryName.valign = "middle" ;
countryName.fill = am4core.color ("#ffffff" );
createMap ();
}
function createMap ( ) {
mapChart = mainContainer.createChild (am4maps.MapChart );
mapChart.zIndex = -1 ;
mapChart.maxZoomLevel = 2000 ;
mapChart.projection = new am4maps.projections .Mercator ();
mapChart.seriesContainer .events .disableType ("doublehit" );
mapChart.chartContainer .background .events .disableType ("doublehit" );
mapChart.deltaLongitude = -11 ;
mapChart.seriesContainer .draggable = false ;
mapChart.geodataSource .url = "//www.amcharts.com/lib/4/geodata/json/continentsHigh.json" ;
mapChart.seriesContainer .resizable = false ;
mapChart.mouseWheelBehavior = "none" ;
continentsSeries = mapChart.series .push (new am4maps.MapPolygonSeries ());
continentsSeries.useGeodata = true ;
continentsSeries.exclude = ["antarctica" ];
continentsSeries.mapPolygons .template .fill = am4core.color ("#283047" );
continentsSeries.mapPolygons .template .strokeOpacity = 0 ;
continentsSeries.toBack ();
countriesSeries = mapChart.series .push (new am4maps.MapPolygonSeries ());
countriesSeries.useGeodata = true ;
countriesSeries.exclude = ["AQ" ];
countriesSeries.mapPolygons .template .visible = false ;
countriesSeries.mapPolygons .template .hiddenState .properties .opacity = 0 ;
countriesSeries.geodataSource .url = "//www.amcharts.com/wp-content/uploads/assets/maps/worldCustomHigh.json" ;
countriesSeries.mapPolygons .template .fill = am4core.color ("#0975da" );
countriesSeries.mapPolygons .template .strokeOpacity = 0 ;
countriesSeries.geodataSource .events .on ("ended" , function ( ) {
setTimeout (function ( ) {
handleNext (userCountryId);
}, 500 )
});
}
function handleNext (countryId ) {
flagContainer.hide (1000 );
if (availableCountries.indexOf (countryId) == -1 ) {
userCountryId = availableCountries[Math .floor (Math .random () * availableCountries.length )];
}
if (slider.start > 0 ) {
let animation = slider.animate ({ property : "start" , to : 0 }, 500 );
animation.events .on ("animationended" , function ( ) {
setTimeout (function ( ) {
zoomToSelectedPolygon ()
}, 100 );
});
}
else {
zoomToSelectedPolygon ();
}
}
function zoomToSelectedPolygon ( ) {
if (selectedPolygon) {
selectedPolygon.hide ();
}
selectedPolygon = countriesSeries.getPolygonById (userCountryId);
selectedPolygon.hide (0 );
selectedPolygon.opacity = 0 ;
selectedPolygon.defaultState .properties .opacity = 1 ;
selectedPolygon.toFront ();
let showAnimation = selectedPolygon.show (1000 );
showAnimation.events .on ("animationended" , function ( ) {
flag.href = "//www.amcharts.com/wp-content/uploads/assets/flags/" + userCountryId.toLowerCase () + ".svg" ;
countryName.text = selectedPolygon.dataItem .dataContext .name ;
setTimeout (function ( ) {
flagContainer.show ();
}, 1000 )
selectedPolygon.polygon .validate ();
let w = selectedPolygon.polygon .bbox .width ;
let h = selectedPolygon.polygon .bbox .height ;
let x = selectedPolygon.polygon .bbox .x + w / 2 ;
let y = selectedPolygon.polygon .bbox .y + h / 2 ;
w = Math .max (w, h);
let path = am4core.path .moveTo ({ x : x, y : y + w / 3 });
path += am4core.path .cubicCurveTo ({ x : x, y : y - w / 4 }, { x : x - w / 2 - w / 4 , y : y - w / 3 }, { x : x - w / 8 , y : y - w / 2 });
path += am4core.path .cubicCurveTo ({ x : x, y : y + w / 3 }, { x : x + w / 8 , y : y - w / 2 }, { x : x + w / 2 + w / 4 , y : y - w / 3 });
let points = am4core.path .pathToPoints (path, 300 );
let middleLatitude = mapChart.zoomGeoPoint .latitude + (selectedPolygon.latitude - mapChart.zoomGeoPoint .latitude ) / 2 ;
let middleLongitude = mapChart.zoomGeoPoint .longitude + (selectedPolygon.longitude - mapChart.zoomGeoPoint .longitude ) / 2 ;
mapChart.zoomEasing = am4core.ease .sinOut ;
let zoomOutAnimation = mapChart.zoomToGeoPoint ({ latitude : middleLatitude, longitude : middleLongitude }, 2 , true );
zoomOutAnimation.events .on ("animationended" , function ( ) {
mapChart.zoomEasing = am4core.ease .cubicInOut ;
mapChart.zoomToMapObject (selectedPolygon, 400 / Math .max (w, h) * mapChart.scaleRatio , true , 1500 );
selectedPolygon.polygon .points ;
selectedPolygon.polygon .morpher .morphToSingle = true ;
let animation;
if (points) {
animation = selectedPolygon.polygon .morpher .morphToPolygon ([[points]]);
}
else {
animation = selectedPolygon.polygon .morpher .morphToCircle ();
}
animation.stop ();
})
})
}
function handleSlider ( ) {
if (selectedPolygon) {
selectedPolygon.polygon .morpher .morphProgress = slider.start ;
if (slider.start >= 0.999 ) {
if (!heartAnimation) {
heartBeet (mapChart.zoomLevel / 1000 );
}
}
else {
if (heartAnimation) {
heartAnimation.kill ();
heartAnimation = undefined ;
}
}
}
}
function heartBeet (scale ) {
heartAnimation = mapChart.animate ({ property : "scale" , to : 1 + scale / 7 }, 200 );
heartAnimation.events .on ("animationended" , function ( ) {
heartAnimation = mapChart.animate ([{ property : "scale" , to : 1 }], 100 );
heartAnimation.events .on ("animationended" , function ( ) {
setTimeout (function ( ) { heartBeet (scale) }, 500 )
})
})
}