Fri Oct 12 2018
Copied to clipboard! Copy reply
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
(function(){


	// **************************************************************************************************
	// RTO
	// **************************************************************************************************

	var rto_destination_url = 'https://www.rosettastone.com/lp/sbsr/example_deal_whatever';


	var rto_styles = document.createElement('style');
	rto_styles.innerHTML = ''
		+ '.rto_container {'
			+ 'position: fixed;'
			+ 'left: 0px;'
			+ 'top: 0px;'
			+ 'width: 100%;'
			+ 'height: 100%;'
			+ 'text-align: center;'
			+ 'font-size: 20px;'
			+ 'overflow: scroll;'
		+ '}'
		+ '.rto_overlay {'
			+ 'background-color: rgba(33, 33, 33, 0.7);'
			+ 'position: fixed;'
			+ 'width: 100%;'
			+ 'height: 100%;'
		+ '}'
		+ '.rto {'
			+ 'margin: 40px auto;'
			+ 'position: relative;'
			+ 'max-width: 600px;'
			+ 'background-color: #353534;'
			+ 'color: #fff;'
			+ 'border-radius: 30px;'
			+ 'overflow: hidden;'
		+ '}'
		+ '.rto_header_section {'
			+ 'background-color: #E9B639;'
			+ 'color: #353534;'
			+ 'padding: 46px 20px 26px;'
		+ '}'
		+ '.rto_header_line_1 {'
			+ 'font-size: 18px;'
		+ '}'
		+ '.rto_header_line_2 {'
			+ 'font-size: 20px;'
			+ 'font-weight: bold;'
		+ '}'
		+ '.rto_content {'
			+ 'padding: 30px 20px;'
		+ '}'
		+ '.rto_message {'
			+ 'padding: 40px 0px 30px;'
			+ 'line-height: 1.3;'
		+ '}'
		+ '.rto_text_large {'
			+ 'font-size: 1.2em;'
			+ 'font-weight: bold;'
		+ '}'
		+ '.rto_cta {'
			+ 'display: inline-block;'
			+ 'text-decoration: none;'
			+ 'background-color: #3BA5D7;'
			+ 'color: #fff;'
			+ 'padding: 15px 20px;'
			+ 'text-transform: uppercase;'
			+ 'border-radius: 30px;'
			+ 'font-size: 22px;'
			+ 'letter-spacing: 0.06em;'
		+ '}'
		+ '.rto_cta:hover {'
			+ 'background-color: #4BB5E7;'
			+ 'color: #fff;'
		+ '}'
		+ '.rto_x_close {'
			+ 'width: 18px;'
			+ 'height: 18px;'
			+ 'position: absolute;'
			+ 'right: 20px;'
			+ 'top: 20px;'
			+ 'cursor: pointer;'
		+ '}'
		+ '.rto_x_close line {'
			+ 'stroke: #fff;'
			+ 'stroke-width: 2;'
			+ 'stroke-linecap: round;'
		+ '}'
		+ '.clock_container {'
			+ 'transform: scale(1.5);'
			+ 'transform-origin: top;'
		+ '}'
	+'';
	document.head.appendChild(rto_styles);


	var rto_container = document.createElement('div');
	rto_container.className = 'rto_container';
	rto_container.innerHTML = ''
		+ '<div class="rto_overlay js_rto_close"></div>'
		+ '<div class="rto">'
			+ '<svg class="rto_x_close js_rto_close" viewBox="0 0 10 10" xmlns="https://www.w3.org/2000/svg">'
				+ '<line x1="1" y1="1" x2="9" y2="9"></line>'
				+ '<line x1="1" y1="9" x2="9" y2="1"></line>'
			+ '</svg>'
			+ '<div class="rto_header_section">'
				+ '<div class="rto_header_line_1">'
					+ 'Who doesn\'t love a little extra?'
				+ '</div>'
				+ '<div class="rto_header_line_2">'
					+ 'You\'ve got 10 minutes.'
				+ '</div>'
			+ '</div>'
			+ '<div class="rto_content">'
				+ '<div class="clock_container">clock</div>'
				+ '<div class="rto_message">'
					+ '<div class="rto_text_standard">Reveal this offer and</div>'
					+ '<div class="rto_text_large">save BIG</div>'
					+ '<div class="rto_text_standard">when you buy now.</div>'
				+ '</div>'
				+ '<a href="'+rto_destination_url+'" class="rto_cta">Reveal the Deal</a>'
			+ '</div>'
		+ '</div>'
	+'';
	document.body.appendChild(rto_container);




	_$('.js_rto_close').on('click', function(){
		_$('.rto_container').hide();
	});















	// **************************************************************************************************
	// CLOCK INSTRUCTIONS:
	//
	//     1) Set the total time on the clock in milliseconds and the clock will take care of itself.
	//     2) Feel free to make whatever style updates you'd like.
	//
	//     Helpful notes:
	//     - If the time is long enough, an EXTRA ARC FOR HOURS WILL BE ADDED AUTOMATICALLY.
	//     - This code supports any number of clock_container divs on the same page.
	//
	// **************************************************************************************************

	var total_time_on_clock_in_ms = 10 * (60*1000); // 10 minutes






	// ****************************
	// Set clock styles here
	// ****************************

	function add_clock_styles(){

		var style_tag = document.createElement('style');
		style_tag.innerHTML = ''
			+ '.clock_arc_svg {'
				+ 'width: 80px;'
				+ 'height: 80px;'
			+ '}'
			+ '.clock_arc {'
				+ 'stroke-width: 0.6;'
				+ 'stroke-linecap: round;'
				+ 'fill: transparent;'
			+ '}'
			+ '.clock_arc_track {'
				+ 'stroke: #1E1E1E;'
			+ '}'
			+ '.clock_arc_fill {'
				+ 'stroke: url(#clock_arc_gradient) #458FCF;'
			+ '}'

			+ '.clock_block {'
				+ 'position: relative;'
				+ 'display: inline-block;'
				+ 'margin: 0px 3px;'
				+ 'line-height: 1;'
			+ '}'

			+ '.clock_time_unit {'
				+ 'text-align: center;'
				+ 'position: absolute;'
				+ 'left: 0px;'
				+ 'top: 20%;'
				+ 'width: 100%;'
			+ '}'
			+ '.clock_time_number {'
				+ 'font-size: 22px;'
			+ '}'
			+ '.clock_time_units {'
				+ 'font-size: 14px;'
			+ '}';
		document.head.appendChild(style_tag);
	}
	add_clock_styles();








	// ********************************
	// From here on, no need to edit
	// ********************************


	function _$(selector){
		var elems = Array.prototype.slice.call(document.querySelectorAll(selector));
		return {
			elems: elems,
			attr: function(attr, value){
				elems.forEach(function(elem){
					var original_attr = elem.getAttribute(attr);
					var final_value = typeof value === 'function' ? value(original_attr) : value;
					elem.setAttribute(attr, final_value);
				});
				return this;
			},
			show: function(display_property){
				elems.forEach(function(elem){
					elem.style.display = display_property || 'block';
				});
				return this;
			},
			hide: function(){
				elems.forEach(function(elem){
					elem.style.display = 'none';
				});
				return this;
			},
			html: function(inner_html){
				elems.forEach(function(elem){
					elem.innerHTML = inner_html;
				});
				return this;
			},
			on: function(event, fn){
				elems.forEach(function(elem){
					elem.addEventListener(event, fn);
				});
				return this;
			}
		};
	}




	function Timer(container_selector, time_remaining_ms){

		this.svg_gradient = ''
			+ '<svg style="width:0;height:0;position:absolute;" aria-hidden="true" focusable="false">'
				+ '<linearGradient id="clock_arc_gradient" x2="1" y2="1">'
					+ '<stop offset="0%" stop-color="#80E4F9" />'
					+ '<stop offset="50%" stop-color="#458FCF" />'
					+ '<stop offset="100%" stop-color="#0E3FA5" />'
				+ '</linearGradient>'
			+ '</svg>';

		this.generate_arc_svg = function(time_units){
			return ''
				+ '<svg class="clock_arc_svg" data-time_units="'+time_units+'" viewBox="0 0 10 10" xmlns="https://www.w3.org/2000/svg">'
					+ '<path class="clock_arc clock_arc_track"></path>'
					+ '<path class="clock_arc clock_arc_fill"></path>'
				+ '</svg>';
		}

		this.generate_time_holder = function(time_units){
			return ''
				+'<div class="clock_block" data-time_units="'+time_units+'">'
					+ this.generate_arc_svg(time_units)
					+ '<div class="clock_time_unit">'
						+ '<div class="clock_time_number">'+
							+ this.getTime(time_units)
						+'</div>'
						+ '<div class="clock_time_units">'
							+ time_units.charAt(0).toUpperCase() + time_units.slice(1)
						+ '</div>'
					+ '</div>'
				+'</div>';
		}

		this.r = 4.55;
		this.arc_degrees_half = 130;
		this.arc_degrees_full = this.arc_degrees_half * 2;

		this.tick_length_ms = 500;
		this.latest_tick_ms;


		this.time_remaining_ms = time_remaining_ms;

		this.getTime = function(time_units){
			var time_in = {
				seconds: (this.time_remaining_ms/1000) % 60,
				minutes: (this.time_remaining_ms/1000/60) % 60,
				hours: this.time_remaining_ms/(1000*60*60)
			};
			return time_in[time_units];
		}

		this.hasHours = Math.floor(this.getTime('hours')) > 0;


		this.init = function(){
			var self = this;
			_$(container_selector).html(
				(self.hasHours ? self.generate_time_holder('hours') : '')
				+ self.generate_time_holder('minutes')
				+ self.generate_time_holder('seconds')
			);
			document.querySelector(container_selector).innerHTML += this.svg_gradient;

			_$('.clock_arc_track').attr(
				'd', describeArc(5, 5, self.r, -self.arc_degrees_half, self.arc_degrees_half)
			);
		};

		this.set_arc_length = function(time_units, percent_full){
			var self = this;
			var start_angle = this.arc_degrees_half - (this.arc_degrees_full * (percent_full/100));

			_$(container_selector + ' .clock_arc_svg[data-time_units='+time_units+'] .clock_arc_fill').attr(
				'd', describeArc(5, 5, self.r, start_angle, self.arc_degrees_half)
			);
		};


		this.time_now_ms = window.performance.now();
		this.total_seconds = this.getTime('seconds') || 60;
		this.total_minutes = this.hasHours ? 60 : this.getTime('minutes');
		this.total_hours = this.getTime('hours');

		this.t = 60;

		this.raf;

		this.update_clock = (function(timestamp){
			this.raf = window.requestAnimationFrame(this.update_clock);
			this.time_remaining_ms -= (timestamp - this.time_now_ms);
			this.time_now_ms = timestamp;

			// make sure time doesn't go negative (it creates weird rendering)
			if(this.time_remaining_ms <= 0){
				this.time_remaining_ms = 0;
			}

			if( (this.time_now_ms - this.latest_tick_ms) >= this.tick_length_ms ){
				this.latest_tick_ms = this.time_now_ms;

				if(this.hasHours){
					this.update_timer_number('hours', Math.floor(this.getTime('hours')) );
				}
				this.update_timer_number('minutes', Math.floor(this.getTime('minutes')) );
				this.update_timer_number('seconds', Math.floor(this.getTime('seconds')) );
			}

			if(this.hasHours){
				this.set_arc_length('hours', (this.getTime('hours') / this.total_hours) * 100);
			}
			this.set_arc_length('minutes', (this.getTime('minutes') / this.total_minutes) * 100);
			this.set_arc_length('seconds', (this.getTime('seconds') / this.total_seconds) * 100);

			if(this.time_remaining_ms <= 0){
				this.stop();
			}
		}).bind(this);

		this.update_timer_number = function(time_units, number){
			_$('.clock_block[data-time_units='+time_units+'] .clock_time_number').html(number);
		}

		this.start = function(){
			this.time_now_ms = window.performance.now();
			this.latest_tick_ms = this.time_now_ms;
			this.update_clock(this.time_now_ms);
		};

		this.stop = function(){
			window.cancelAnimationFrame(this.raf);
		};
	}

	var timer = new Timer('.clock_container', total_time_on_clock_in_ms);
	timer.init();
	timer.start();



	// credit for polarToCartesian and describeArc functions:
	// https://stackoverflow.com/questions/5736398/how-to-calculate-the-svg-path-for-an-arc-of-a-circle
	function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
		var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

		return {
			x: centerX + (radius * Math.cos(angleInRadians)),
			y: centerY + (radius * Math.sin(angleInRadians))
		};
	}
	function describeArc(x, y, radius, startAngle, endAngle){
		var start = polarToCartesian(x, y, radius, endAngle);
		var end = polarToCartesian(x, y, radius, startAngle);

		var arcSweep = endAngle - startAngle <= 180 ? '0' : '1';

		var d = [
				'M', start.x, start.y, 
				'A', radius, radius, 0, arcSweep, 0, end.x, end.y
		].join(' ');

		return d;
	}



})();