├── .gitignore
├── README.md
├── images
├── blue-marble-1280.jpg
├── custom.php
├── gray-1280.png
├── gray-400.png
├── gray-600.png
├── gray-800.png
├── living-1280.jpg
├── map-outlines.psd
├── night-electric-1280.jpg
└── pin.png
├── includes
└── parser.inc
├── index.php
├── json.php
├── lib
├── jquery.maphilight.min.js
├── jquery.timezone-picker.js
└── jquery.timezone-picker.min.js
├── style.css
├── tz_islands.txt
└── tz_world.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | /world
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | timezonepicker
2 | ==============
3 |
4 | A jQuery and ImageMap based timezone picker.
5 |
6 | This library only works with pre-built imagemaps generated from
7 | http://timezonepicker.com.
8 |
9 | Features
10 | --------
11 |
12 | - Simple implementation, lightweight footprint (160KB, 40KB gzipped).
13 | - Includes 440+ clickable areas.
14 | - HTML5 Geolocation to identify timezone.
15 | - Islands include padding to increase ease of selection.
16 | - Country mapping can be used to set timezone and country at the same time.
17 | - Timezone highlighting on rollover (thanks to [jQuery maphilight](http://davidlynch.org/projects/maphilight/docs/))
18 |
19 | Usage
20 | -----
21 |
22 | Basic call using all defaults:
23 | ```javascript
24 | $('#img-with-usemap-attr').timezonePicker();
25 | ```
26 |
27 | A few simple options:
28 | ```javascript
29 | $('#img-with-usemap-attr').timezonePicker({
30 | pin: '.timezone-pin',
31 | fillColor: 'FFCCCC',
32 | });
33 | ```
34 |
35 | Options
36 | -------
37 | As pulled from the set of defaults.
38 |
39 | ```javascript
40 | $.fn.timezonePicker.defaults = {
41 | // Selector for the pin that should be used. This selector only works in the
42 | // immediate parent of the image map img tag.
43 | pin: '.timezone-pin',
44 | // Specify a URL for the pin image instead of using a DOM element.
45 | pinUrl: null,
46 | // Preselect a particular timezone.
47 | timezone: null,
48 | // Pass through options to the jQuery maphilight plugin.
49 | maphilight: true,
50 | // Selector for the select list, textfield, or hidden to update upon click.
51 | target: null,
52 | // Selector for the select list, textfield, or hidden to update upon click
53 | // with the specified country.
54 | countryTarget: null,
55 | // If changing the country should use the first timezone within that country.
56 | countryGuess: true,
57 | // A list of country guess exceptions. These should only be needed if a
58 | // country spans multiple timezones.
59 | countryGuesses: {
60 | 'AU': 'Australia/Sydney',
61 | 'BR': 'America/Sao_Paulo',
62 | 'CA': 'America/Toronto',
63 | 'CN': 'Asia/Shanghai',
64 | 'ES': 'Europe/Madrid',
65 | 'MX': 'America/Mexico_City',
66 | 'RU': 'Europe/Moscow',
67 | 'US': 'America/New_York'
68 | },
69 | // If this map should automatically adjust its size if scaled. Note that
70 | // this can be very expensive computationally and will likely have a delay
71 | // on resize. The maphilight library also is incompatible with this setting
72 | // and will be disabled.
73 | responsive: false,
74 | // A function to be called upon timezone change
75 | // timezoneName, countryName, and offset will be passed as arguments
76 | changeHandler: null,
77 |
78 | // Default options passed along to the maphilight plugin.
79 | fade: false,
80 | stroke: true,
81 | strokeColor: 'FFFFFF',
82 | strokeOpacity: 0.4,
83 | fillColor: 'FFFFFF',
84 | fillOpacity: 0.4,
85 | groupBy: 'data-offset'
86 | };
87 | ```
88 |
89 | Additional methods
90 | ------------------
91 | After creating a timezone picker from an image tag, you can execute additional
92 | commands on the image map with these methods:
93 |
94 | ```javascript
95 | // Query the user's browser for the current location and set timezone from that.
96 | $('#img-with-usemap-attr').timezonePicker('detectTimezone');
97 |
98 | // The detectTimezone method may also provide event callbacks.
99 | $('#img-with-usemap-attr').timezonePicker('detectTimezone', {
100 | success: successCallback,
101 | error: errorCallback,
102 | complete: completeCallback, // Called on both success or failure.
103 | });
104 |
105 | // Set the active timezone to some value programatically.
106 | $('#img-with-usemap-attr').timezonePicker('updateTimezone', 'America/New_York');
107 |
108 | // Resize the image map coordinates to match an adjusted size of the image.
109 | // Note that this option does not work well and is very slow. Not recommended.
110 | $('#img-with-usemap-attr').timezonePicker('resize');
111 | ```
112 |
113 | Building new definition files
114 | -----------------------------
115 |
116 | The definition files are used to determine the polygons and rectangles used to
117 | generate the resulting imagemap. Note this should rarely be necessary for normal
118 | users as the timezone picker project will rebuild the shape files after updates
119 | to the timezone database.
120 |
121 | 1. Download latest shape file "tz_world" from
122 | http://efele.net/maps/tz/world/.
123 |
124 | wget http://efele.net/maps/tz/world/tz_world.zip
125 | unzip tz_world.zip
126 |
127 | 2. Install PostGIS, which provides the shp2pgsql executable.
128 | http://postgis.refractions.net/download/
129 |
130 | For Mac OS X, I installed PostGres, GDAL Complete, and PostGIS binaries from
131 | http://www.kyngchaos.com/software:postgres
132 |
133 | Then add psql and shp2pgsql to your $PATH variable in your shell profile.
134 | export PATH=/usr/local/pgsql-9.1/bin:$PATH
135 |
136 | 3. Convert the tz_world.shp file into SQL:
137 |
138 | ```
139 | cd world
140 | shp2pgsql tz_world.shp timezones > tz_world.sql
141 | ```
142 |
143 | 4. Create a temporary database and import the SQL file.
144 |
145 | ```
146 | psql -U postgres -c "CREATE DATABASE timezones" -d template1
147 | ```
148 |
149 | And import the PostGIS functions into the database.
150 |
151 | ```
152 | psql -U postgres -d timezones -f /usr/local/pgsql-9.1/share/contrib/postgis-2.0/postgis.sql
153 |
154 | psql -U postgres -d timezones < tz_world.sql
155 | ```
156 |
157 | 5. Export the data as text in a simplified format.
158 |
159 | ```
160 | psql -U postgres -d timezones -t -A -c "
161 |
162 | SELECT tzid, ST_AsText(ST_Simplify(ST_SnapToGrid(geom, 0.001), 0.3)) FROM timezones
163 |
164 | WHERE (ST_Area(geom) > 3 OR (gid IN (
165 |
166 | SELECT MAX(gid) FROM timezones WHERE ST_Area(geom) <= 3 AND tzid NOT IN (
167 |
168 | SELECT tzid FROM timezones WHERE ST_Area(geom) > 3
169 |
170 | ) group by tzid ORDER BY MAX(ST_AREA(geom))
171 |
172 | ))) AND tzid != 'uninhabited';
173 |
174 | " > tz_world.txt
175 | ```
176 |
177 | And a special export for Islands that are hard to select otherwise.
178 |
179 | ```
180 | psql -U postgres -d timezones -t -A -c "
181 | SELECT tzid, ST_Expand(ST_Extent(geom), GREATEST(3 - ST_Area(ST_Extent(geom)), 0)) FROM timezones
182 |
183 | WHERE ST_Area(geom) < 3 AND (tzid LIKE 'Pacific/%' OR tzid LIKE 'Indian/%' OR tzid LIKE 'Atlantic/%') GROUP BY tzid ORDER BY tzid;
184 | " > tz_islands.txt
185 | ```
186 |
187 | LICENSE
188 | ---------
189 |
190 | Copyright 2011-2013 Nathan Haug
191 |
192 | Released under the MIT License.
193 |
194 |
--------------------------------------------------------------------------------
/images/blue-marble-1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/blue-marble-1280.jpg
--------------------------------------------------------------------------------
/images/custom.php:
--------------------------------------------------------------------------------
1 | 'png',
5 | 'blue-marble' => 'jpg',
6 | 'living' => 'jpg',
7 | 'night-electric' => 'jpg',
8 | );
9 | $width = isset($_GET['w']) ? min((int) $_GET['w'], 1280) : 600;
10 | $height = round($width / 2);
11 |
12 | if (isset($_GET['base']) && isset($bases[$_GET['base']])) {
13 | $base = $_GET['base'];
14 | $extension = $bases[$_GET['base']];
15 | }
16 | else {
17 | $base = reset(array_keys($bases));
18 | $extension = reset($bases);
19 | }
20 | $source = $base . '-1280.' . $extension;
21 | $open_extension = str_replace('jpg', 'jpeg', $extension);
22 | $open_func = 'imagecreatefrom' . $open_extension;
23 |
24 | $im = $open_func($source);
25 | if (!$im) {
26 | return FALSE;
27 | }
28 |
29 | list($original_width, $original_height) = getimagesize($source);
30 |
31 | $res = imagecreatetruecolor($width, $height);
32 | if ($extension == 'png') {
33 | $transparency = imagecolorallocatealpha($res, 0, 0, 0, 127);
34 | imagealphablending($res, FALSE);
35 | imagefilledrectangle($res, 0, 0, $width, $height, $transparency);
36 | imagealphablending($res, TRUE);
37 | imagesavealpha($res, TRUE);
38 | }
39 | elseif ($extension == 'gif') {
40 | // If we have a specific transparent color.
41 | $transparency_index = imagecolortransparent($im);
42 | if ($transparency_index >= 0) {
43 | // Get the original image's transparent color's RGB values.
44 | $transparent_color = imagecolorsforindex($im, $transparency_index);
45 | // Allocate the same color in the new image resource.
46 | $transparency_index = imagecolorallocate($res, $transparent_color['red'], $transparent_color['green'], $transparent_color['blue']);
47 | // Completely fill the background of the new image with allocated color.
48 | imagefill($res, 0, 0, $transparency_index);
49 | // Set the background color for new image to transparent.
50 | imagecolortransparent($res, $transparency_index);
51 | // Find number of colors in the images palette.
52 | $number_colors = imagecolorstotal($im);
53 | // Convert from true color to palette to fix transparency issues.
54 | imagetruecolortopalette($res, TRUE, $number_colors);
55 | }
56 | }
57 | imagecopyresampled($res, $im, 0, 0, 0, 0, $width, $height, $original_width, $original_height);
58 |
59 | header('Content-Type: image/' . $extension);
60 | header('Cache-Control: public, max-age: 3600');
61 |
62 | $close_function = 'image' . $open_extension;
63 | $close_function($res);
64 |
65 | imagedestroy($res);
66 | imagedestroy($im);
67 |
--------------------------------------------------------------------------------
/images/gray-1280.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/gray-1280.png
--------------------------------------------------------------------------------
/images/gray-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/gray-400.png
--------------------------------------------------------------------------------
/images/gray-600.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/gray-600.png
--------------------------------------------------------------------------------
/images/gray-800.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/gray-800.png
--------------------------------------------------------------------------------
/images/living-1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/living-1280.jpg
--------------------------------------------------------------------------------
/images/map-outlines.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/map-outlines.psd
--------------------------------------------------------------------------------
/images/night-electric-1280.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/night-electric-1280.jpg
--------------------------------------------------------------------------------
/images/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/quicksketch/timezonepicker/884950ae874088cce2ed7003990959658e520b07/images/pin.png
--------------------------------------------------------------------------------
/includes/parser.inc:
--------------------------------------------------------------------------------
1 | 'Gray',
10 | 'blue-marble' => 'Blue marble',
11 | 'night-electric' => 'Night Electric',
12 | 'living' => 'Living Earth',
13 | );
14 |
15 | $base_url = 'http://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['REQUEST_URI']), '/');
16 | if (!empty($_GET['w']) && is_numeric($_GET['w']) && (int) $_GET['w'] < 1280) {
17 | $local_file = 'images/custom.php?w=' . (int) $_GET['w'];
18 | $local_file .= '&base=' . (isset($_GET['base']) && array_key_exists($_GET['base'], $bases) ? $_GET['base'] : reset($bases));
19 | }
20 | else {
21 | $local_file = isset($_GET['src']) && isset($options[$_GET['src']]) ? $_GET['src'] : 'images/gray-600.png';
22 | }
23 |
24 | $remote_file = $base_url . '/' . $local_file;
25 |
26 | // Dimensions must always be exact since the imagemap does not scale.
27 | list($map_width, $map_height) = getimagesize($remote_file);
28 | $timezones = timezone_picker_parse_files($map_width, $map_height, 'tz_world.txt', 'tz_islands.txt');
29 | ?>
30 |
31 |
32 |
33 |
34 | jQuery and Imagemap Timezone Picker
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
76 |
77 |
78 |
79 |
80 |
81 |
82 | $timezone): ?>
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | Select your country and timezone
97 |
98 |
99 | Time zone
100 | - None - Africa/Abidjan Africa/Accra Africa/Addis Ababa Africa/Algiers Africa/Asmara Africa/Bamako Africa/Bangui Africa/Banjul Africa/Bissau Africa/Blantyre Africa/Brazzaville Africa/Bujumbura Africa/Cairo Africa/Casablanca Africa/Ceuta Africa/Conakry Africa/Dakar Africa/Dar es Salaam Africa/Djibouti Africa/Douala Africa/El Aaiun Africa/Freetown Africa/Gaborone Africa/Harare Africa/Johannesburg Africa/Kampala Africa/Khartoum Africa/Kigali Africa/Kinshasa Africa/Lagos Africa/Libreville Africa/Lome Africa/Luanda Africa/Lubumbashi Africa/Lusaka Africa/Malabo Africa/Maputo Africa/Maseru Africa/Mbabane Africa/Mogadishu Africa/Monrovia Africa/Nairobi Africa/Ndjamena Africa/Niamey Africa/Nouakchott Africa/Ouagadougou Africa/Porto-Novo Africa/Sao Tome Africa/Tripoli Africa/Tunis Africa/Windhoek America/Adak America/Anchorage America/Anguilla America/Antigua America/Araguaina America/Argentina/Buenos Aires America/Argentina/Catamarca America/Argentina/Cordoba America/Argentina/Jujuy America/Argentina/La Rioja America/Argentina/Mendoza America/Argentina/Rio Gallegos America/Argentina/Salta America/Argentina/San Juan America/Argentina/San Luis America/Argentina/Tucuman America/Argentina/Ushuaia America/Aruba America/Asuncion America/Atikokan America/Bahia Banderas America/Bahia America/Barbados America/Belem America/Belize America/Blanc-Sablon America/Boa Vista America/Bogota America/Boise America/Cambridge Bay America/Campo Grande America/Cancun America/Caracas America/Cayenne America/Cayman America/Chicago America/Chihuahua America/Costa Rica America/Cuiaba America/Curacao America/Danmarkshavn America/Dawson Creek America/Dawson America/Denver America/Detroit America/Dominica America/Edmonton America/Eirunepe America/El Salvador America/Fortaleza America/Glace Bay America/Godthab America/Goose Bay America/Grand Turk America/Grenada America/Guadeloupe America/Guatemala America/Guayaquil America/Guyana America/Halifax America/Havana America/Hermosillo America/Indiana/Indianapolis America/Indiana/Knox America/Indiana/Marengo America/Indiana/Petersburg America/Indiana/Tell City America/Indiana/Vevay America/Indiana/Vincennes America/Indiana/Winamac America/Inuvik America/Iqaluit America/Jamaica America/Juneau America/Kentucky/Louisville America/Kentucky/Monticello America/La Paz America/Lima America/Los Angeles America/Maceio America/Managua America/Manaus America/Marigot America/Martinique America/Matamoros America/Mazatlan America/Menominee America/Merida America/Metlakatla America/Mexico City America/Miquelon America/Moncton America/Monterrey America/Montevideo America/Montreal America/Montserrat America/Nassau America/New York America/Nipigon America/Nome America/Noronha America/North Dakota/Beulah America/North Dakota/Center America/North Dakota/New Salem America/Ojinaga America/Panama America/Pangnirtung America/Paramaribo America/Phoenix America/Port of Spain America/Port-au-Prince America/Porto Velho America/Puerto Rico America/Rainy River America/Rankin Inlet America/Recife America/Regina America/Resolute America/Rio Branco America/Santa Isabel America/Santarem America/Santiago America/Santo Domingo America/Sao Paulo America/Scoresbysund America/Shiprock America/Sitka America/St Barthelemy America/St Johns America/St Kitts America/St Lucia America/St Thomas America/St Vincent America/Swift Current America/Tegucigalpa America/Thule America/Thunder Bay America/Tijuana America/Toronto America/Tortola America/Vancouver America/Whitehorse America/Winnipeg America/Yakutat America/Yellowknife Antarctica/Casey Antarctica/Davis Antarctica/DumontDUrville Antarctica/Macquarie Antarctica/Mawson Antarctica/McMurdo Antarctica/Palmer Antarctica/Rothera Antarctica/South Pole Antarctica/Syowa Antarctica/Vostok Arctic/Longyearbyen Asia/Aden Asia/Almaty Asia/Amman Asia/Anadyr Asia/Aqtau Asia/Aqtobe Asia/Ashgabat Asia/Baghdad Asia/Bahrain Asia/Baku Asia/Bangkok Asia/Beirut Asia/Bishkek Asia/Brunei Asia/Choibalsan Asia/Chongqing Asia/Colombo Asia/Damascus Asia/Dhaka Asia/Dili Asia/Dubai Asia/Dushanbe Asia/Gaza Asia/Harbin Asia/Ho Chi Minh Asia/Hong Kong Asia/Hovd Asia/Irkutsk Asia/Jakarta Asia/Jayapura Asia/Jerusalem Asia/Kabul Asia/Kamchatka Asia/Karachi Asia/Kashgar Asia/Kathmandu Asia/Kolkata Asia/Krasnoyarsk Asia/Kuala Lumpur Asia/Kuching Asia/Kuwait Asia/Macau Asia/Magadan Asia/Makassar Asia/Manila Asia/Muscat Asia/Nicosia Asia/Novokuznetsk Asia/Novosibirsk Asia/Omsk Asia/Oral Asia/Phnom Penh Asia/Pontianak Asia/Pyongyang Asia/Qatar Asia/Qyzylorda Asia/Rangoon Asia/Riyadh Asia/Sakhalin Asia/Samarkand Asia/Seoul Asia/Shanghai Asia/Singapore Asia/Taipei Asia/Tashkent Asia/Tbilisi Asia/Tehran Asia/Thimphu Asia/Tokyo Asia/Ulaanbaatar Asia/Urumqi Asia/Vientiane Asia/Vladivostok Asia/Yakutsk Asia/Yekaterinburg Asia/Yerevan Atlantic/Azores Atlantic/Bermuda Atlantic/Canary Atlantic/Cape Verde Atlantic/Faroe Atlantic/Madeira Atlantic/Reykjavik Atlantic/South Georgia Atlantic/St Helena Atlantic/Stanley Australia/Adelaide Australia/Brisbane Australia/Broken Hill Australia/Currie Australia/Darwin Australia/Eucla Australia/Hobart Australia/Lindeman Australia/Lord Howe Australia/Melbourne Australia/Perth Australia/Sydney Europe/Amsterdam Europe/Andorra Europe/Athens Europe/Belgrade Europe/Berlin Europe/Bratislava Europe/Brussels Europe/Bucharest Europe/Budapest Europe/Chisinau Europe/Copenhagen Europe/Dublin Europe/Gibraltar Europe/Guernsey Europe/Helsinki Europe/Isle of Man Europe/Istanbul Europe/Jersey Europe/Kaliningrad Europe/Kiev Europe/Lisbon Europe/Ljubljana Europe/London Europe/Luxembourg Europe/Madrid Europe/Malta Europe/Mariehamn Europe/Minsk Europe/Monaco Europe/Moscow Europe/Oslo Europe/Paris Europe/Podgorica Europe/Prague Europe/Riga Europe/Rome Europe/Samara Europe/San Marino Europe/Sarajevo Europe/Simferopol Europe/Skopje Europe/Sofia Europe/Stockholm Europe/Tallinn Europe/Tirane Europe/Uzhgorod Europe/Vaduz Europe/Vatican Europe/Vienna Europe/Vilnius Europe/Volgograd Europe/Warsaw Europe/Zagreb Europe/Zaporozhye Europe/Zurich Indian/Antananarivo Indian/Chagos Indian/Christmas Indian/Cocos Indian/Comoro Indian/Kerguelen Indian/Mahe Indian/Maldives Indian/Mauritius Indian/Mayotte Indian/Reunion Pacific/Apia Pacific/Auckland Pacific/Chatham Pacific/Chuuk Pacific/Easter Pacific/Efate Pacific/Enderbury Pacific/Fakaofo Pacific/Fiji Pacific/Funafuti Pacific/Galapagos Pacific/Gambier Pacific/Guadalcanal Pacific/Guam Pacific/Honolulu Pacific/Johnston Pacific/Kiritimati Pacific/Kosrae Pacific/Kwajalein Pacific/Majuro Pacific/Marquesas Pacific/Midway Pacific/Nauru Pacific/Niue Pacific/Norfolk Pacific/Noumea Pacific/Pago Pago Pacific/Palau Pacific/Pitcairn Pacific/Pohnpei Pacific/Port Moresby Pacific/Rarotonga Pacific/Saipan Pacific/Tahiti Pacific/Tarawa Pacific/Tongatapu Pacific/Wake Pacific/Wallis UTC
101 |
102 |
103 |
104 | Country
105 | - None - Afghanistan Aland Islands Albania Algeria American Samoa Andorra Angola Anguilla Antarctica Antigua and Barbuda Argentina Armenia Aruba Australia Austria Azerbaijan Bahamas Bahrain Bangladesh Barbados Belarus Belgium Belize Benin Bermuda Bhutan Bolivia Bosnia and Herzegovina Botswana Bouvet Island Brazil British Indian Ocean Territory British Virgin Islands Brunei Bulgaria Burkina Faso Burundi Cambodia Cameroon Canada Cape Verde Cayman Islands Central African Republic Chad Chile China Christmas Island Cocos (Keeling) Islands Colombia Comoros Congo (Brazzaville) Congo (Kinshasa) Cook Islands Costa Rica Croatia Cuba Curaçao Cyprus Czech Republic Denmark Djibouti Dominica Dominican Republic Ecuador Egypt El Salvador Equatorial Guinea Eritrea Estonia Ethiopia Falkland Islands Faroe Islands Fiji Finland France French Guiana French Polynesia French Southern Territories Gabon Gambia Georgia Germany Ghana Gibraltar Greece Greenland Grenada Guadeloupe Guam Guatemala Guernsey Guinea Guinea-Bissau Guyana Haiti Heard Island and McDonald Islands Honduras Hong Kong S.A.R., China Hungary Iceland India Indonesia Iran Iraq Ireland Isle of Man Israel Italy Ivory Coast Jamaica Japan Jersey Jordan Kazakhstan Kenya Kiribati Kuwait Kyrgyzstan Laos Latvia Lebanon Lesotho Liberia Libya Liechtenstein Lithuania Luxembourg Macao S.A.R., China Macedonia Madagascar Malawi Malaysia Maldives Mali Malta Marshall Islands Martinique Mauritania Mauritius Mayotte Mexico Micronesia Moldova Monaco Mongolia Montenegro Montserrat Morocco Mozambique Myanmar Namibia Nauru Nepal Netherlands Netherlands Antilles New Caledonia New Zealand Nicaragua Niger Nigeria Niue Norfolk Island Northern Mariana Islands North Korea Norway Oman Pakistan Palau Palestinian Territory Panama Papua New Guinea Paraguay Peru Philippines Pitcairn Poland Portugal Puerto Rico Qatar Reunion Romania Russia Rwanda Saint Barthélemy Saint Helena Saint Kitts and Nevis Saint Lucia Saint Martin (French part) Saint Pierre and Miquelon Saint Vincent and the Grenadines Samoa San Marino Sao Tome and Principe Saudi Arabia Senegal Serbia Seychelles Sierra Leone Singapore Slovakia Slovenia Solomon Islands Somalia South Africa South Georgia and the South Sandwich Islands South Korea Spain Sri Lanka Sudan Suriname Svalbard and Jan Mayen Swaziland Sweden Switzerland Syria Taiwan Tajikistan Tanzania Thailand Timor-Leste Togo Tokelau Tonga Trinidad and Tobago Tunisia Turkey Turkmenistan Turks and Caicos Islands Tuvalu U.S. Virgin Islands Uganda Ukraine United Arab Emirates United Kingdom United States United States Minor Outlying Islands Uruguay Uzbekistan Vanuatu Vatican Venezuela Vietnam Wallis and Futuna Western Sahara Yemen Zambia Zimbabwe
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
Timezone Picker jQuery and Imagemap Library
114 |
115 |
116 | Timezone Picker is intended to be a free use combination library of a jQuery
117 | library (jquery.timezone-picker.js )
118 | and an ImageMap format (as demonstrated here).
119 |
120 | To generate your ImageMap, simply choose an image width from above. All images
121 | are half-height of the width, in the standard
122 |
123 | Equirectangular projection . You should be able to use any variety of
124 | images in this standard format.
125 |
126 |
127 |
Features
128 |
129 | 400+ individual clickable areas
130 | Expanded island regions for easy selection
131 | Lightweight implementation (140KB)
132 | Completely standalone; no internet connection or APIs required
133 | Universally compatible (IE6+, Firefox, Chrome, Safari, Opera, mobile browsers)
134 | Geolocation when available (IE9+, and all the above)
135 | Mobile and Touch event friendly
136 | Automatic select list updating, both country and timezone
137 | Timezone pin locations
138 |
139 |
140 |
Recommended Use
141 |
142 | Generation of the ImageMap files can be rather computationally expensive,
143 | especially from the raw data files. It's therefor recommended that you simply
144 | copy/paste the entire ImageMap from the source code, rather than
145 | generating the ImageMap code on your own. However, please do not attempt
146 | to hotlink images or files from TimezonePicker.com. Just copy/paste the
147 | pieces, it's all meant to work independently of an external internet
148 | connections, making it perfect for offline, intranet, or secure websites.
149 |
150 |
151 |
152 | Alternatively, you may also use this data feed in JSON format to generate your
153 | own ImageMap data. Adjust the ?w= query string parameter as needed for your
154 | desired map dimensions.
155 |
156 |
159 |
160 |
161 |
On Mobile
162 |
163 | ImageMaps are not very friendy to adaptive/responsive designs. Because the
164 | coordinates are coded to a particular image width and height, they do not
165 | resize easily (though the library does support this, but it's slow). However,
166 | it's not recommended to decrease the size of the map for the mobile version
167 | anyway, because selection becomes more difficult on mobile due to the
168 | "touch behavior" required. Your finger is a lot less accurate than a mouse.
169 | Therefor it's recommended to use an "overflow: auto;" on the containing DIV,
170 | which adds a horizontal scrollbar to the map. This can keep the map the same
171 | size, while making it easier for mobile users to select the timezone. Of
172 | course they could also just use the "Detect" button. :)
173 |
174 |
175 |
Credits
176 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
--------------------------------------------------------------------------------
/json.php:
--------------------------------------------------------------------------------
1 | 1280 ? 600 : (int) $_GET['w'];
8 | $map_height = round($map_width/2);
9 | $timezones = timezone_picker_parse_files($map_width, $map_height, 'tz_world.txt', 'tz_islands.txt');
10 |
11 | header('Content-Type: application/json');
12 | header('Cache-Control: public, max-age: 3600');
13 |
14 | print json_encode($timezones, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
15 |
--------------------------------------------------------------------------------
/lib/jquery.maphilight.min.js:
--------------------------------------------------------------------------------
1 | (function(G){var B,J,C,K,N,M,I,E,H,A,L;B=document.namespaces;J=!!document.createElement("canvas").getContext;if(!(J||B)){G.fn.maphilight=function(){return this};return }if(J){E=function(O){return Math.max(0,Math.min(parseInt(O,16),255))};H=function(O,P){return"rgba("+E(O.substr(0,2))+","+E(O.substr(2,2))+","+E(O.substr(4,2))+","+P+")"};C=function(O){var P=G(' ').get(0);P.getContext("2d").clearRect(0,0,P.width,P.height);return P};var F=function(Q,O,R,P,S){P=P||0;S=S||0;Q.beginPath();if(O=="rect"){Q.rect(R[0]+P,R[1]+S,R[2]-R[0],R[3]-R[1])}else{if(O=="poly"){Q.moveTo(R[0]+P,R[1]+S);for(i=2;i').get(0)};K=function(P,S,T,W,O){var U,V,Q,R;U=' ';V=(W.stroke?'strokeweight="'+W.strokeWidth+'" stroked="t" strokecolor="#'+W.strokeColor+'"':'stroked="f"');Q=' ';if(S=="rect"){R=G(' ')}else{if(S=="poly"){R=G(' ')}else{if(S=="circ"){R=G(' ')}}}R.get(0).innerHTML=U+Q;G(P).append(R)};N=function(O){G(O).find("[name=highlighted]").remove()}}M=function(P){var O,Q=P.getAttribute("coords").split(",");for(O=0;O0)){return }if(W.hasClass("maphilighted")){var R=W.parent();W.insertBefore(R);R.remove();G(S).unbind(".maphilight").find("area[coords]").unbind(".maphilight")}T=G("
").css({display:"block",background:'url("'+this.src+'")',position:"relative",padding:0,width:this.width,height:this.height});if(a.wrapClass){if(a.wrapClass===true){T.addClass(G(this).attr("class"))}else{T.addClass(a.wrapClass)}}W.before(T).css("opacity",0).css(I).remove();if(G.browser.msie){W.css("filter","Alpha(opacity=0)")}T.append(W);V=C(this);G(V).css(I);V.height=this.height;V.width=this.width;Z=function(f){var c,d;d=L(this,a);if(!d.neverOn&&!d.alwaysOn){c=M(this);K(V,c[0],c[1],d,"highlighted");if(d.groupBy){var b;if(/^[a-zA-Z][\-a-zA-Z]+$/.test(d.groupBy)){b=S.find("area["+d.groupBy+'="'+G(this).attr(d.groupBy)+'"]')}else{b=S.find(d.groupBy)}var g=this;b.each(function(){if(this!=g){var h=L(this,a);if(!h.neverOn&&!h.alwaysOn){var e=M(this);K(V,e[0],e[1],h,"highlighted")}}})}if(!J){G(V).append(" ")}}};G(S).bind("alwaysOn.maphilight",function(){if(X){N(X)}if(!J){G(V).empty()}G(S).find("area[coords]").each(function(){var b,c;c=L(this,a);if(c.alwaysOn){if(!X&&J){X=C(W[0]);G(X).css(I);X.width=W[0].width;X.height=W[0].height;W.before(X)}c.fade=c.alwaysOnFade;b=M(this);if(J){K(X,b[0],b[1],c,"")}else{K(V,b[0],b[1],c,"")}}})});G(S).trigger("alwaysOn.maphilight").find("area[coords]").bind("mouseover.maphilight",Z).bind("mouseout.maphilight",function(b){N(V)});W.before(V);W.addClass("maphilighted")})};G.fn.maphilight.defaults={fill:true,fillColor:"000000",fillOpacity:0.2,stroke:true,strokeColor:"ff0000",strokeOpacity:1,strokeWidth:1,fade:true,alwaysOn:false,neverOn:false,groupBy:false,wrapClass:true,shadow:false,shadowX:0,shadowY:0,shadowRadius:6,shadowColor:"000000",shadowOpacity:0.8,shadowPosition:"outside",shadowFrom:false}})(jQuery);
--------------------------------------------------------------------------------
/lib/jquery.timezone-picker.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 |
3 | // We only support a single instance per call, so these variables are available
4 | // for all subsequent calls.
5 | var methods = {};
6 | var opts = {};
7 | var selectedTimezone = null;
8 | var imgElement = null;
9 | var mapElement = null;
10 | var $pin = null;
11 |
12 | // Gets called upon timezone change.
13 | // The expected method signature is changeHandler(timezoneName, countryName, offset).
14 | var changeHandler = null;
15 |
16 | methods.init = function(initOpts) {
17 | var $origCall = this;
18 |
19 | // Set the instance options.
20 | opts = $.extend({}, $.fn.timezonePicker.defaults, initOpts);
21 | selectedTimezone = opts.timezone;
22 |
23 | changeHandler = opts.changeHandler;
24 |
25 | return $origCall.each(function(index, item) {
26 | imgElement = item;
27 | mapElement = document.getElementsByName(imgElement.useMap.replace(/^#/, ''))[0];
28 |
29 | // Wrap the img tag in a relatively positioned DIV for the pin.
30 | $(imgElement).wrap('
').parent().css({
31 | position: 'relative',
32 | width: $(imgElement).width() + 'px'
33 | });
34 |
35 | // Add the pin.
36 | if (opts.pinUrl) {
37 | $pin = $(' ').appendTo(imgElement.parentNode).css('display', 'none');
38 | }
39 | else if (opts.pin) {
40 | $pin = $(imgElement).parent().parent().find(opts.pin).appendTo(imgElement.parentNode).css('display', 'none');
41 | }
42 |
43 | // Main event handler when a timezone is clicked.
44 | $(mapElement).find('area').click(function() {
45 | var areaElement = this;
46 | // Enable the pin adjustment.
47 | if ($pin) {
48 | $pin.css('display', 'block');
49 | var pinCoords = $(areaElement).attr('data-pin').split(',');
50 | var pinWidth = parseInt($pin.width() / 2);
51 | var pinHeight = $pin.height();
52 |
53 | $pin.css({
54 | position: 'absolute',
55 | left: (pinCoords[0] - pinWidth) + 'px',
56 | top: (pinCoords[1] - pinHeight) + 'px'
57 | });
58 | }
59 |
60 | var timezoneName = $(areaElement).attr('data-timezone');
61 | var countryName = $(areaElement).attr('data-country');
62 | var offset = $(areaElement).attr('data-offset');
63 |
64 | // Call the change handler
65 | if (typeof changeHandler === 'function') {
66 | changeHandler(timezoneName, countryName, offset);
67 | }
68 |
69 | // Update the target select list.
70 | if (opts.target) {
71 | if (timezoneName) $(opts.target).val(timezoneName);
72 | }
73 | if (opts.countryTarget) {
74 | if (countryName) $(opts.countryTarget).val(countryName);
75 | }
76 |
77 | return false;
78 | });
79 |
80 | // Adjust the timezone if the target changes.
81 | if (opts.target) {
82 | $(opts.target).bind('change', function() {
83 | $origCall.timezonePicker('updateTimezone', $(this).val());
84 | });
85 | }
86 |
87 | // Adjust the timezone if the countryTarget changes.
88 | if (opts.countryTarget && opts.countryGuess) {
89 | $(opts.countryTarget).bind('change', function() {
90 | var countryCode = $(this).val();
91 | if (opts.countryGuesses[countryCode]) {
92 | $(mapElement).find('area[data-timezone="' + opts.countryGuesses[countryCode] + '"]').click()
93 | }
94 | else {
95 | $(mapElement).find('area[data-country=' + countryCode + ']:first').click();
96 | }
97 | });
98 | }
99 |
100 | // This is very expensive, so only run if enabled.
101 | if (opts.responsive) {
102 | var resizeTimeout = null;
103 | $(window).resize(function() {
104 | if (resizeTimeout) {
105 | clearTimeout(resizeTimeout);
106 | }
107 | resizeTimeout = setTimeout(function() {
108 | $origCall.timezonePicker('resize');
109 | }, 200);
110 | });
111 | }
112 |
113 | // Give the page a slight time to load before selecting the default
114 | // timezone on the map.
115 | setTimeout(function() {
116 | if (opts.responsive && parseInt(imgElement.width) !== parseInt(imgElement.getAttribute('width'))) {
117 | $origCall.timezonePicker('resize');
118 | }
119 | else if (opts.maphilight && $.fn.maphilight) {
120 | $(imgElement).maphilight(opts);
121 | }
122 | if (opts.target) {
123 | $(opts.target).triggerHandler('change');
124 | }
125 | }, 500);
126 |
127 | });
128 | };
129 |
130 | /**
131 | * Update the currently selected timezone and update the pin location.
132 | */
133 | methods.updateTimezone = function(newTimezone) {
134 | selectedTimezone = newTimezone;
135 | $pin.css('display', 'none');
136 | $(mapElement).find('area').each(function(m, areaElement) {
137 | if (areaElement.getAttribute('data-timezone') === selectedTimezone) {
138 | $(areaElement).triggerHandler('click');
139 | return false;
140 | }
141 | });
142 |
143 | return this;
144 | };
145 |
146 | /**
147 | * Use browser geolocation to update the currently selected timezone and update the pin location.
148 | */
149 | methods.detectLocation = function(detectOpts) {
150 | var detectDefaults = {
151 | success: undefined,
152 | error: undefined,
153 | complete: undefined
154 | };
155 | detectOpts = $.extend(detectDefaults, detectOpts);
156 |
157 | if (navigator.geolocation) {
158 | navigator.geolocation.getCurrentPosition(showPosition, handleErrors);
159 | }
160 |
161 | function showPosition(position) {
162 | var $imgElement = $(imgElement);
163 | var imageXY = convertXY(position.coords.latitude, position.coords.longitude, $imgElement.width(), $imgElement.height());
164 |
165 | $(mapElement).find('area').each(function(m, areaElement) {
166 | var coords = areaElement.getAttribute('coords').split(',');
167 | var shape = areaElement.getAttribute('shape');
168 | var poly = [];
169 | for (var n = 0; n < coords.length/2; n++) {
170 | poly[n] = [ coords[n * 2], coords[n * 2 + 1] ];
171 | }
172 |
173 | if ((shape === 'poly' && isPointInPoly(poly, imageXY[0], imageXY[1])) ||
174 | (shape === 'rect' && isPointInRect(coords, imageXY[0], imageXY[1]))
175 | ) {
176 | $(areaElement).triggerHandler('click', detectOpts['success']);
177 | return false;
178 | }
179 | });
180 | if (detectOpts['complete']) {
181 | detectOpts['complete'](position);
182 | }
183 | }
184 |
185 | function handleErrors(error) {
186 | if (detectOpts['error']) {
187 | detectOpts['error'](error);
188 | }
189 | if (detectOpts['complete']) {
190 | detectOpts['complete'](error);
191 | }
192 | }
193 |
194 | // Converts lat and long into X,Y coodinates on a Equirectangular map.
195 | function convertXY(latitude, longitude, map_width, map_height) {
196 | var x = Math.round((longitude + 180) * (map_width / 360));
197 | var y = Math.round(((latitude * -1) + 90) * (map_height / 180));
198 | return [x, y];
199 | }
200 |
201 | // Do a dual-check here to ensure accuracy. Ray-tracing algorithm gives us the
202 | // basic idea of if we're in a polygon, but may be inaccurate if the ray goes
203 | // through a single point exactly at its vertex. We double check positives
204 | // against a bounding box, ensuring the item is actually in that area.
205 | function isPointInPoly(poly, x, y){
206 | var inside = false;
207 | var bbox = [1000000,1000000,-1000000,-1000000];
208 | for (var i = 0, j = poly.length - 1; i < poly.length; j = i++) {
209 | var xi = poly[i][0], yi = poly[i][1];
210 | var xj = poly[j][0], yj = poly[j][1];
211 | bbox[0] = Math.min(bbox[0], xi);
212 | bbox[1] = Math.min(bbox[1], yi);
213 | bbox[2] = Math.max(bbox[2], xi);
214 | bbox[3] = Math.max(bbox[3], yi);
215 |
216 | var intersect = ((yi > y) != (yj > y))
217 | && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
218 | if (intersect) inside = !inside;
219 | }
220 |
221 | return inside && isPointInRect(bbox, x, y);
222 | }
223 |
224 | // Simple check if a point is in between two X/Y coordinates. Input may be
225 | // any two points, with a box made between them.
226 | function isPointInRect(rect, x, y) {
227 | // Adjust so we're always going top-left to lower-right.
228 | rect = [
229 | Math.min(rect[0], rect[2]),
230 | Math.min(rect[1], rect[3]),
231 | Math.max(rect[0], rect[2]),
232 | Math.max(rect[1], rect[3])
233 | ];
234 | return (x >= rect[0] && x <= rect[2] && y >= rect[1] && y <= rect[2]);
235 | }
236 |
237 | return this;
238 | };
239 |
240 | /**
241 | * Experimental method to rewrite the imagemap based on new image dimensions.
242 | *
243 | * This does not resize the image itself, it recalculates the imagemap to match
244 | * the current dimensions of the image.
245 | */
246 | methods.resize = function() {
247 | $(mapElement).find('area').each(function(m, areaElement) {
248 | // Save the original coordinates for further resizing.
249 | if (!areaElement.originalCoords) {
250 | areaElement.originalCoords = {
251 | timezone: areaElement.getAttribute('data-timezone'),
252 | country: areaElement.getAttribute('data-country'),
253 | coords: areaElement.getAttribute('coords'),
254 | pin: areaElement.getAttribute('data-pin')
255 | };
256 | }
257 | var rescale = imgElement.width/imgElement.getAttribute('width');
258 |
259 | // Adjust the image size.
260 | $(imgElement).parent().css({
261 | width: $(imgElement).width() + 'px'
262 | });
263 |
264 | // Adjust the coords attribute.
265 | var originalCoords = areaElement.originalCoords.coords.split(',');
266 | var newCoords = new Array();
267 | for (var j = 0; j < originalCoords.length; j++) {
268 | newCoords[j] = Math.round(parseInt(originalCoords[j]) * rescale);
269 | }
270 | areaElement.setAttribute('coords', newCoords.join(','));
271 |
272 | // Adjust the pin coordinates.
273 | var pinCoords = areaElement.originalCoords.pin.split(',');
274 | pinCoords[0] = Math.round(parseInt(pinCoords[0]) * rescale);
275 | pinCoords[1] = Math.round(parseInt(pinCoords[1]) * rescale);
276 | areaElement.setAttribute('data-pin', pinCoords.join(','));
277 |
278 | // Fire the change handler on the target.
279 | if (opts.target) {
280 | $(opts.target).triggerHandler('change');
281 | }
282 |
283 | });
284 |
285 | return this;
286 | };
287 |
288 | $.fn.timezonePicker = function(method) {
289 | // Method calling logic.
290 | if (methods[method]) {
291 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
292 | }
293 | else if (typeof method === 'object' || !method) {
294 | return methods.init.apply(this, arguments);
295 | }
296 | else {
297 | $.error('Method ' + method + ' does not exist on jQuery.timezonePicker');
298 | }
299 | };
300 |
301 | $.fn.timezonePicker.defaults = {
302 | // Selector for the pin that should be used. This selector only works in the
303 | // immediate parent of the image map img tag.
304 | pin: '.timezone-pin',
305 | // Specify a URL for the pin image instead of using a DOM element.
306 | pinUrl: null,
307 | // Preselect a particular timezone.
308 | timezone: null,
309 | // Pass through options to the jQuery maphilight plugin.
310 | maphilight: true,
311 | // Selector for the select list, textfield, or hidden to update upon click.
312 | target: null,
313 | // Selector for the select list, textfield, or hidden to update upon click
314 | // with the specified country.
315 | countryTarget: null,
316 | // If changing the country should use the first timezone within that country.
317 | countryGuess: true,
318 | // A list of country guess exceptions. These should only be needed if a
319 | // country spans multiple timezones.
320 | countryGuesses: {
321 | 'AU': 'Australia/Sydney',
322 | 'BR': 'America/Sao_Paulo',
323 | 'CA': 'America/Toronto',
324 | 'CN': 'Asia/Shanghai',
325 | 'ES': 'Europe/Madrid',
326 | 'MX': 'America/Mexico_City',
327 | 'RU': 'Europe/Moscow',
328 | 'US': 'America/New_York'
329 | },
330 | // If this map should automatically adjust its size if scaled. Note that
331 | // this can be very expensive computationally and will likely have a delay
332 | // on resize. The maphilight library also is incompatible with this setting
333 | // and will be disabled.
334 | responsive: false,
335 |
336 | // Default options passed along to the maphilight plugin.
337 | fade: false,
338 | stroke: true,
339 | strokeColor: 'FFFFFF',
340 | strokeOpacity: 0.4,
341 | fillColor: 'FFFFFF',
342 | fillOpacity: 0.4,
343 | groupBy: 'data-offset'
344 | };
345 |
346 | })(jQuery);
347 |
--------------------------------------------------------------------------------
/lib/jquery.timezone-picker.min.js:
--------------------------------------------------------------------------------
1 | (function($){var methods={};var opts={};var selectedTimzone=null;var imgElement=null;var mapElement=null;var $pin=null;var changeHandler=null;methods.init=function(initOpts){var $origCall=this;opts=$.extend({},$.fn.timezonePicker.defaults,initOpts);selectedTimzone=opts.timezone;changeHandler=opts.changeHandler;return $origCall.each(function(index,item){imgElement=item;mapElement=document.getElementsByName(imgElement.useMap.replace(/^#/,""))[0];$(imgElement).wrap('
').parent().css({position:"relative",width:$(imgElement).width()+"px"});if(opts.pinUrl){$pin=$(' ').appendTo(imgElement.parentNode).css("display","none")}else if(opts.pin){$pin=$(imgElement).parent().parent().find(opts.pin).appendTo(imgElement.parentNode).css("display","none")}$(mapElement).find("area").click(function(){var areaElement=this;if($pin){$pin.css("display","block");var pinCoords=$(areaElement).attr("data-pin").split(",");var pinWidth=parseInt($pin.width()/2);var pinHeight=$pin.height();$pin.css({position:"absolute",left:pinCoords[0]-pinWidth+"px",top:pinCoords[1]-pinHeight+"px"})}var timezoneName=$(areaElement).attr("data-timezone");var countryName=$(areaElement).attr("data-country");var offset=$(areaElement).attr("data-offset");if(typeof changeHandler==="function"){changeHandler(timezoneName,countryName,offset)}if(opts.target){if(timezoneName)$(opts.target).val(timezoneName)}if(opts.countryTarget){if(countryName)$(opts.countryTarget).val(countryName)}return false});if(opts.target){$(opts.target).bind("change",function(){$origCall.timezonePicker("updateTimezone",$(this).val())})}if(opts.countryTarget&&opts.countryGuess){$(opts.countryTarget).bind("change",function(){var countryCode=$(this).val();if(opts.countryGuesses[countryCode]){$(mapElement).find('area[data-timezone="'+opts.countryGuesses[countryCode]+'"]').click()}else{$(mapElement).find("area[data-country="+countryCode+"]:first").click()}})}if(opts.responsive){var resizeTimeout=null;$(window).resize(function(){if(resizeTimeout){clearTimeout(resizeTimeout)}resizeTimeout=setTimeout(function(){$origCall.timezonePicker("resize")},200)})}setTimeout(function(){if(opts.responsive&&parseInt(imgElement.width)!==parseInt(imgElement.getAttribute("width"))){$origCall.timezonePicker("resize")}else if(opts.maphilight&&$.fn.maphilight){$(imgElement).maphilight(opts)}if(opts.target){$(opts.target).triggerHandler("change")}},500)})};methods.updateTimezone=function(newTimezone){selectedTimzone=newTimezone;$pin.css("display","none");$(mapElement).find("area").each(function(m,areaElement){if(areaElement.getAttribute("data-timezone")===selectedTimzone){$(areaElement).triggerHandler("click");return false}});return this};methods.detectLocation=function(detectOpts){var detectDefaults={success:undefined,error:undefined,complete:undefined};detectOpts=$.extend(detectDefaults,detectOpts);if(navigator.geolocation){navigator.geolocation.getCurrentPosition(showPosition,handleErrors)}function showPosition(position){var $imgElement=$(imgElement);var imageXY=convertXY(position.coords.latitude,position.coords.longitude,$imgElement.width(),$imgElement.height());$(mapElement).find("area").each(function(m,areaElement){var coords=areaElement.getAttribute("coords").split(",");var shape=areaElement.getAttribute("shape");var poly=[];for(var n=0;ny!=yj>y&&x<(xj-xi)*(y-yi)/(yj-yi)+xi;if(intersect)inside=!inside}return inside&&isPointInRect(bbox,x,y)}function isPointInRect(rect,x,y){rect=[Math.min(rect[0],rect[2]),Math.min(rect[1],rect[3]),Math.max(rect[0],rect[2]),Math.max(rect[1],rect[3])];return x>=rect[0]&&x<=rect[2]&&y>=rect[1]&&y<=rect[2]}return this};methods.resize=function(){$(mapElement).find("area").each(function(m,areaElement){if(!areaElement.originalCoords){areaElement.originalCoords={timezone:areaElement.getAttribute("data-timezone"),country:areaElement.getAttribute("data-country"),coords:areaElement.getAttribute("coords"),pin:areaElement.getAttribute("data-pin")}}var rescale=imgElement.width/imgElement.getAttribute("width");$(imgElement).parent().css({width:$(imgElement).width()+"px"});var originalCoords=areaElement.originalCoords.coords.split(",");var newCoords=new Array;for(var j=0;j