<commit_before>var scale_state = 0;
var orgWidth = 0, orgHeight = 0;
var scale_margin = 160;
var resized_msg = document.createElement("div");
resized_msg.appendChild(document.createTextNode("Image rescaled"));
resized_msg.appendChild(document.createElement("br"));
resized_msg.appendChild(document.createTextNode("click to see full size"));

function resize()
{
	var img = document.getElementById("main-image");
	var resized_div = document.getElementById("rescaled-msg");
	if (!img || !resized_div) return 0;
	if (scale_state == 0) {
		orgWidth = img.width;
		orgHeight = img.height;
		scale_state = 1;
	}
	if (scale_state == 1) {
		var w = document.body.offsetWidth - scale_margin;
		if (w < 128) w = 128;
		if (w < orgWidth) {
			img.width = w;
			img.height = w * orgHeight / orgWidth;
			scale_state = 2;
			resized_div.appendChild(resized_msg);
			resized_div.style.display = "inline-block";
		}
	} else {
		img.width = orgWidth;
		img.height = orgHeight;
		scale_state = 1;
		resized_div.style.display = "none";
		resized_div.removeChild(resized_msg);
	}
	return 0;
}
<commit_msg>Fix rescaling code style.<commit_after>function resize() {
	var w;
	if (!wp.resize_state) {
		wp.resize_img = document.getElementById("main-image");
		wp.resize_div = document.getElementById("rescaled-msg");
		if (!wp.resize_img || !wp.resize_div) { return false; }
		wp.resized_msg = document.createElement("div");
		wp.resized_msg.appendChild(document.createTextNode("Image rescaled"));
		wp.resized_msg.appendChild(document.createElement("br"));
		wp.resized_msg.appendChild(document.createTextNode("click to see full size"));
		wp.resize_orgWidth = wp.resize_img.width;
		wp.resize_orgHeight = wp.resize_img.height;
		wp.resize_state = 1;
	}
	if (wp.resize_state === 1) {
		w = document.body.offsetWidth - 160;
		if (w < 128) { w = 128; }
		if (w < wp.resize_orgWidth) {
			wp.resize_img.width = w;
			wp.resize_img.height = w * wp.resize_orgHeight / wp.resize_orgWidth;
			wp.resize_state = 2;
			wp.resize_div.appendChild(wp.resized_msg);
			wp.resize_div.style.display = "inline-block";
		}
	} else {
		wp.resize_img.width = wp.resize_orgWidth;
		wp.resize_img.height = wp.resize_orgHeight;
		wp.resize_state = 1;
		wp.resize_div.style.display = "none";
		wp.resize_div.removeChild(wp.resized_msg);
	}
	return false;
}
<|endoftext|>


<commit_before>import React from 'react';
import EventEmitter from 'events';
import d3 from 'd3';
import CursorPane from './CursorPane';
import CanvasPane from './CanvasPane';

const MODE = {
    HAND: {},
    LINE: {}
};

export default class Whiteboard extends React.Component {

    static get propTypes() {
        return {
            width: React.PropTypes.number,
            height: React.PropTypes.number,
            style: React.PropTypes.object,
        };
    }

    static get childContextTypes() {
        return {
            emitter: React.PropTypes.object,
        };
    }

    getChildContext() {
        return {
            emitter: this.emitter,
        };
    }

    constructor(props) {
        super(props);

        this.emitter = new EventEmitter();
        this.state = {
            dataset: [],
            undoStack: [],
            mode: MODE.HAND,
            strokeWidth: 5,
            strokeColor: 'black',
        };
    }

    componentDidMount() {
        this.setupEventHandler();
    }

    setupEventHandler() {
        d3.select('body').on('keydown.body', () => {
            this.emitter.emit('keydown.body', d3.event.keyCode);
        });

        const that = this;
        this.emitter.on('keydown.body', (keyCode) => {
            if (keyCode === 48) { // 0'
                that.toggleMode();
            }
            if (keyCode >= 49 && keyCode <= 57) { // '1' - '9'
                that.changeStrokeWidth(keyCode - 48);
            }
            if (keyCode === 67) { // 'c'
                that.toggleStrokeColor();
            }
        });
        this.emitter.on('mousemove.canvas', (point) => {
            that.pushPoint(point);
        });
        this.emitter.on('click.canvas', (point) => {
            that.toggleMode(point);
        });
        this.emitter.on('undo.pallete', () => {
            that.undoPoint();
        });
        this.emitter.on('redo.pallete', () => {
            that.redoPoint();
        });
    }

    toggleMode(point) {
        if (this.state.mode === MODE.LINE) {
            this.setState({
                mode: MODE.HAND,
            });
        } else {
            const dataset = this.state.dataset;
            dataset.push({
                strokeWidth: this.state.strokeWidth,
                strokeColor: this.state.strokeColor,
                values: point ? [point] : [],
            });
            this.setState({
                mode: MODE.LINE,
                dataset: dataset,
            });
        }
    }

    changeStrokeWidth(width) {
        this.setState({
            strokeWidth: width,
        });
    }

    toggleStrokeColor() {
        if (this.state.strokeColor === 'black') {
            this.setState({
                strokeColor: 'red',
            });
        } else if (this.state.strokeColor === 'red') {
            this.setState({
                strokeColor: 'green',
            });
        } else if (this.state.strokeColor === 'green') {
            this.setState({
                strokeColor: 'blue',
            });
        } else {
            this.setState({
                strokeColor: 'black',
            });
        }
    }

    pushPoint(point) {
        if (this.state.mode === MODE.HAND) {
            return;
        }

        const dataset = this.state.dataset;
        const current = dataset[dataset.length - 1];

        if (current &&
                current.strokeWidth === this.state.strokeWidth &&
                current.strokeColor === this.state.strokeColor) {
            current.values.push(point);
            this.setState({
                dataset: dataset,
                undoStack: [],
            });
        } else {
            dataset.push({
                strokeWidth: this.state.strokeWidth,
                strokeColor: this.state.strokeColor,
                values: [point],
            });
            this.setState({
                dataset: dataset,
                undoStack: [],
            });
        }
    }

    undoPoint() {
        const dataset = this.state.dataset;
        const current = dataset[dataset.length - 1];
        const undoStack = this.state.undoStack;

        if (current && current.values.length > 1) {
            const point = current.values.pop();
            const undoOperation = (newState) => {
                const dataset = this.state.dataset;
                const current = dataset[dataset.length - 1];
                current.values.push(point);
                newState.dataset = dataset;
                this.setState(newState);
            };
            undoStack.push(undoOperation);
            this.setState({
                dataset: dataset,
                undoStack: undoStack,
            });

        } else if (current && current.values.length === 1) {
            dataset.pop();
            const undoOperation = (newState) => {
                const dataset = this.state.dataset;
                dataset.push(current);
                newState.dataset = dataset;
                this.setState(newState);
            };
            undoStack.push(undoOperation);
            this.setState({
                dataset: dataset,
                undoStack: undoStack,
            });
        }
    }

    redoPoint() {
        const undoStack = this.state.undoStack;
        const redoOperation = undoStack.pop();
        if (redoOperation) {
            redoOperation({
                undoStack: undoStack,
            });
        }
    }

    clearPoint() {
        this.setState({
            dataset: [],
            undoStack: [],
        });
    }

    render() {
        const wrapperStyle = {
            position: 'relative',
            width: this.props.width,
            height: this.props.height,
        };

        return (

                <CursorPane {...this.props} {...this.state} />
                <CanvasPane {...this.props} {...this.state} />

        );
    }

}
<commit_msg>Remove event handler to toggle mode<commit_after>import React from 'react';
import EventEmitter from 'events';
import d3 from 'd3';
import CursorPane from './CursorPane';
import CanvasPane from './CanvasPane';

const MODE = {
    HAND: {},
    LINE: {}
};

export default class Whiteboard extends React.Component {

    static get propTypes() {
        return {
            width: React.PropTypes.number,
            height: React.PropTypes.number,
            style: React.PropTypes.object,
        };
    }

    static get childContextTypes() {
        return {
            emitter: React.PropTypes.object,
        };
    }

    getChildContext() {
        return {
            emitter: this.emitter,
        };
    }

    constructor(props) {
        super(props);

        this.emitter = new EventEmitter();
        this.state = {
            dataset: [],
            undoStack: [],
            mode: MODE.HAND,
            strokeWidth: 5,
            strokeColor: 'black',
        };
    }

    componentDidMount() {
        this.setupEventHandler();
    }

    setupEventHandler() {
        d3.select('body').on('keydown.body', () => {
            this.emitter.emit('keydown.body', d3.event.keyCode);
        });

        const that = this;
        this.emitter.on('keydown.body', (keyCode) => {
            if (keyCode >= 49 && keyCode <= 57) { // '1' - '9'
                that.changeStrokeWidth(keyCode - 48);
            }
            if (keyCode === 67) { // 'c'
                that.toggleStrokeColor();
            }
        });
        this.emitter.on('mousemove.canvas', (point) => {
            that.pushPoint(point);
        });
        this.emitter.on('click.canvas', (point) => {
            that.toggleMode(point);
        });
        this.emitter.on('undo.pallete', () => {
            that.undoPoint();
        });
        this.emitter.on('redo.pallete', () => {
            that.redoPoint();
        });
    }

    toggleMode(point) {
        if (this.state.mode === MODE.LINE) {
            this.setState({
                mode: MODE.HAND,
            });
        } else {
            const dataset = this.state.dataset;
            dataset.push({
                strokeWidth: this.state.strokeWidth,
                strokeColor: this.state.strokeColor,
                values: point ? [point] : [],
            });
            this.setState({
                mode: MODE.LINE,
                dataset: dataset,
            });
        }
    }

    changeStrokeWidth(width) {
        this.setState({
            strokeWidth: width,
        });
    }

    toggleStrokeColor() {
        if (this.state.strokeColor === 'black') {
            this.setState({
                strokeColor: 'red',
            });
        } else if (this.state.strokeColor === 'red') {
            this.setState({
                strokeColor: 'green',
            });
        } else if (this.state.strokeColor === 'green') {
            this.setState({
                strokeColor: 'blue',
            });
        } else {
            this.setState({
                strokeColor: 'black',
            });
        }
    }

    pushPoint(point) {
        if (this.state.mode === MODE.HAND) {
            return;
        }

        const dataset = this.state.dataset;
        const current = dataset[dataset.length - 1];

        if (current &&
                current.strokeWidth === this.state.strokeWidth &&
                current.strokeColor === this.state.strokeColor) {
            current.values.push(point);
            this.setState({
                dataset: dataset,
                undoStack: [],
            });
        } else {
            dataset.push({
                strokeWidth: this.state.strokeWidth,
                strokeColor: this.state.strokeColor,
                values: [point],
            });
            this.setState({
                dataset: dataset,
                undoStack: [],
            });
        }
    }

    undoPoint() {
        const dataset = this.state.dataset;
        const current = dataset[dataset.length - 1];
        const undoStack = this.state.undoStack;

        if (current && current.values.length > 1) {
            const point = current.values.pop();
            const undoOperation = (newState) => {
                const dataset = this.state.dataset;
                const current = dataset[dataset.length - 1];
                current.values.push(point);
                newState.dataset = dataset;
                this.setState(newState);
            };
            undoStack.push(undoOperation);
            this.setState({
                dataset: dataset,
                undoStack: undoStack,
            });

        } else if (current && current.values.length === 1) {
            dataset.pop();
            const undoOperation = (newState) => {
                const dataset = this.state.dataset;
                dataset.push(current);
                newState.dataset = dataset;
                this.setState(newState);
            };
            undoStack.push(undoOperation);
            this.setState({
                dataset: dataset,
                undoStack: undoStack,
            });
        }
    }

    redoPoint() {
        const undoStack = this.state.undoStack;
        const redoOperation = undoStack.pop();
        if (redoOperation) {
            redoOperation({
                undoStack: undoStack,
            });
        }
    }

    clearPoint() {
        this.setState({
            dataset: [],
            undoStack: [],
        });
    }

    render() {
        const wrapperStyle = {
            position: 'relative',
            width: this.props.width,
            height: this.props.height,
        };

        return (

                <CursorPane {...this.props} {...this.state} />
                <CanvasPane {...this.props} {...this.state} />

        );
    }

}
<|endoftext|>


<commit_before>var minDT = new Date();
minDT.setUTCFullYear(minDT.getUTCFullYear - 3);
var liveChartsFromDT, liveChartsToDT, liveChartConfig;

var updateDatesFromConfig = function(config) {
    var duration = $('#live_chart_duration li[data-live=' + config.live + ']').attr('id');
    var now = new Date();
    liveChartsFromDT.setDateTime(new Date(now.getTime() - (duration * 1000)));
    liveChartsToDT.setDateTime(now);
};

var show_chart_for_instrument = function() {
    var symb, disp_symb;
    $("#instrument_select .deleteme").remove();
    $("#instrument_select option:selected").each(function(){
        symb = $(this).val();
        disp_symb = $(this).text();
    });

    if (symb) {
        liveChartConfig.update({
            symbol: symb,
            update_url: 1
        });
        updateLiveChart(liveChartConfig);
    }
};

var remove_highlight_chart_duration = function () {
    $('#live_chart_duration').find('.live_charts_stream_button').each( function () {
        $(this).find('span').removeClass('current');
    });
};

var build_markets_select = function() {
    var market_select = $("#market_select");
    markets.each(function() {
        if (this.name != 'forex') {
            market_select.append("<option class='ja-hide' id='opt_" + this.name + "' value='" + this.name + "'>" + this.translated_display_name() + "</option>");
        }
        else {
            market_select.append("" + this.translated_display_name() + "");
        }
    });

    $("#market_select").val(liveChartConfig.market.name);
    build_instrument_select();

    $("#market_select").change(build_instrument_select);
};

var build_instrument_select = function() {
    var instrument_select = $("#instrument_select");
    var market = markets.get($('#market_select').val());
    $("#instrument_span").hide();
    if(market) {
        $("#instrument_select option").remove();
        instrument_select.append("<option class='deleteme'></option>");
        market.each(function() {
            this.each(function() {
                instrument_select.append("<option value='" + this.symbol + "'>" + this.translated_display_name() + "</option>");
            });
        });
        $("#instrument_span").show();
        $("#instrument_select").change(show_chart_for_instrument);
        $("#instrument_select").val(liveChartConfig.symbol.symbol);
    }
};

var init_live_chart = function () {
    liveChartsFromDT = new DateTimePicker({
        id: "live_charts_from",
        onChange: function(date) { liveChartsToDT.setMinDateTime(date); }
    });

    liveChartsToDT = new DateTimePicker({
        id: "live_charts_to",
        onChange: function(date) { liveChartsFromDT.setMaxDateTime(date); }
    });

    liveChartConfig = new LiveChartConfig({
        renderTo: 'live_chart_div',
    });

    configure_livechart();
    build_markets_select();

    $(".notice").hide();
    $("#live_chart_extended_options").hide();
    $("#live_charts_show_extended_options").on('click', function(e){
        e.preventDefault();
        $("#live_chart_extended_options").toggle();
    });
    $("#live_charts_high_barrier").change(function(){
        var val = $(this).val();
        if(liveChartConfig.has_indicator('high') || !val) {
            live_chart.remove_indicator('high');
        }

        if (val) {
            var barrier = new LiveChartIndicator.Barrier({ name: "high", value: val, color: 'green'});
            live_chart.add_indicator(barrier);
        }
    });
    $("#live_charts_low_barrier").change(function(){
        var val = $(this).val();
        if(liveChartConfig.has_indicator('low') || !val) {
            live_chart.remove_indicator('low');
        }

        if (val) {
            var barrier = new LiveChartIndicator.Barrier({ name: "low", value: val, color: 'red'});
            live_chart.add_indicator(barrier);
        }
    });

    $('#live_charts_hide_spot').hide();
    $("#live_charts_show_spot").on('click', function(e){
        e.preventDefault();
        var barrier = new LiveChartIndicator.Barrier({ name: "spot", value: "+0"});
        live_chart.add_indicator(barrier);
        $(this).hide();
        $('#live_charts_hide_spot').show();
    });

    $("#live_charts_hide_spot").on('click', function(e){
        e.preventDefault();
        live_chart.remove_indicator('spot');
        $(this).hide();
        $('#live_charts_show_spot').show();
    });

    $("#live_charts_show_interval").on('click', function() {
        liveChartConfig.update({
            interval: {
                from: liveChartsFromDT.getDateTime(),
                to: liveChartsToDT.getDateTime()
            },
            update_url: 1
        });
        updateLiveChart(liveChartConfig);
    });

    $("#live_chart_duration").on('duration_change', function(e) {
        updateDatesFromConfig(e.config);
    });

    show_chart_for_instrument();
    updateDatesFromConfig(liveChartConfig);
};

pjax_config_page('livechart', function() {
    return {
        onLoad: function() {
            init_live_chart();
        },
        onUnload: function() {
            live_chart.close_chart();
            live_chart = null;
        }
    };
});

//The first time some one loads live chart in the session, the script might not have finished loading by the time onLoad.fire() was called.
//So we check if livechart was not configured when we loaded this script then we initialize it manually.
$(function() {
    if(!live_chart && /livechart/.test(window.location.pathname)) {
        init_live_chart();
    }

});
<commit_msg>option<commit_after>var minDT = new Date();
minDT.setUTCFullYear(minDT.getUTCFullYear - 3);
var liveChartsFromDT, liveChartsToDT, liveChartConfig;

var updateDatesFromConfig = function(config) {
    var duration = $('#live_chart_duration li[data-live=' + config.live + ']').attr('id');
    var now = new Date();
    liveChartsFromDT.setDateTime(new Date(now.getTime() - (duration * 1000)));
    liveChartsToDT.setDateTime(now);
};

var show_chart_for_instrument = function() {
    var symb, disp_symb;
    $("#instrument_select .deleteme").remove();
    $("#instrument_select option:selected").each(function(){
        symb = $(this).val();
        disp_symb = $(this).text();
    });

    if (symb) {
        liveChartConfig.update({
            symbol: symb,
            update_url: 1
        });
        updateLiveChart(liveChartConfig);
    }
};

var remove_highlight_chart_duration = function () {
    $('#live_chart_duration').find('.live_charts_stream_button').each( function () {
        $(this).find('span').removeClass('current');
    });
};

var build_markets_select = function() {
    var market_select = $("#market_select");
    markets.each(function() {
        if (this.name != 'forex') {
            market_select.append("<option class='ja-hide' id='opt_" + this.name + "' value='" + this.name + "'>" + this.translated_display_name() + "</option>");
        }
        else {
            market_select.append("<option selected=selected id='opt_" + this.name + "' value='" + this.name + "'>" + this.translated_display_name() + "</option>");
        }
    });

    $("#market_select").val(liveChartConfig.market.name);
    build_instrument_select();

    $("#market_select").change(build_instrument_select);
};

var build_instrument_select = function() {
    var instrument_select = $("#instrument_select");
    var market = markets.get($('#market_select').val());
    $("#instrument_span").hide();
    if(market) {
        $("#instrument_select option").remove();
        instrument_select.append("<option class='deleteme'></option>");
        market.each(function() {
            this.each(function() {
                instrument_select.append("<option value='" + this.symbol + "'>" + this.translated_display_name() + "</option>");
            });
        });
        $("#instrument_span").show();
        $("#instrument_select").change(show_chart_for_instrument);
        $("#instrument_select").val(liveChartConfig.symbol.symbol);
    }
};

var init_live_chart = function () {
    liveChartsFromDT = new DateTimePicker({
        id: "live_charts_from",
        onChange: function(date) { liveChartsToDT.setMinDateTime(date); }
    });

    liveChartsToDT = new DateTimePicker({
        id: "live_charts_to",
        onChange: function(date) { liveChartsFromDT.setMaxDateTime(date); }
    });

    liveChartConfig = new LiveChartConfig({
        renderTo: 'live_chart_div',
    });

    configure_livechart();
    build_markets_select();

    $(".notice").hide();
    $("#live_chart_extended_options").hide();
    $("#live_charts_show_extended_options").on('click', function(e){
        e.preventDefault();
        $("#live_chart_extended_options").toggle();
    });
    $("#live_charts_high_barrier").change(function(){
        var val = $(this).val();
        if(liveChartConfig.has_indicator('high') || !val) {
            live_chart.remove_indicator('high');
        }

        if (val) {
            var barrier = new LiveChartIndicator.Barrier({ name: "high", value: val, color: 'green'});
            live_chart.add_indicator(barrier);
        }
    });
    $("#live_charts_low_barrier").change(function(){
        var val = $(this).val();
        if(liveChartConfig.has_indicator('low') || !val) {
            live_chart.remove_indicator('low');
        }

        if (val) {
            var barrier = new LiveChartIndicator.Barrier({ name: "low", value: val, color: 'red'});
            live_chart.add_indicator(barrier);
        }
    });

    $('#live_charts_hide_spot').hide();
    $("#live_charts_show_spot").on('click', function(e){
        e.preventDefault();
        var barrier = new LiveChartIndicator.Barrier({ name: "spot", value: "+0"});
        live_chart.add_indicator(barrier);
        $(this).hide();
        $('#live_charts_hide_spot').show();
    });

    $("#live_charts_hide_spot").on('click', function(e){
        e.preventDefault();
        live_chart.remove_indicator('spot');
        $(this).hide();
        $('#live_charts_show_spot').show();
    });

    $("#live_charts_show_interval").on('click', function() {
        liveChartConfig.update({
            interval: {
                from: liveChartsFromDT.getDateTime(),
                to: liveChartsToDT.getDateTime()
            },
            update_url: 1
        });
        updateLiveChart(liveChartConfig);
    });

    $("#live_chart_duration").on('duration_change', function(e) {
        updateDatesFromConfig(e.config);
    });

    show_chart_for_instrument();
    updateDatesFromConfig(liveChartConfig);
};

pjax_config_page('livechart', function() {
    return {
        onLoad: function() {
            init_live_chart();
        },
        onUnload: function() {
            live_chart.close_chart();
            live_chart = null;
        }
    };
});

//The first time some one loads live chart in the session, the script might not have finished loading by the time onLoad.fire() was called.
//So we check if livechart was not configured when we loaded this script then we initialize it manually.
$(function() {
    if(!live_chart && /livechart/.test(window.location.pathname)) {
        init_live_chart();
    }

});
<|endoftext|>


<commit_before>// Declarations

var coords, map, markers = new Array(), updater, live;

const fadeTime = 250;

// Functions

function getParameter(name) {
	return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
}

function getSecondsSinceMidnight() {
	return ~~((new Date() - new Date().setHours(0, 0, 0, 0)) / 1000);
}

function toHMS(seconds) {
	var hours   = Math.floor(seconds / 3600),
		minutes = Math.floor((seconds % 3600) / 60);
	seconds = seconds - (minutes * 60) - (hours * 3600);
	return {
		h: ('0' + hours).slice(-2),
		m: ('0' + minutes).slice(-2),
		s: ('0' + seconds).slice(-2)
	};
}

function toCountdown(seconds, showHours) {
	seconds = seconds - getSecondsSinceMidnight();
	var time = toHMS(Math.abs(seconds));
	return (seconds < 0 ? '-' : '') + (showHours ? time.h + 'h ': '') + time.m + 'm ' + (showHours ? '' : time.s + 's');
}

function toTime(seconds) {
	var time = toHMS(seconds);
	return time.h + ':' + time.m;
}

function showStop(id, settings) {
	if (updater && !live) {

		$('.trip-scheduled').each(function() {
			$(this).text(toCountdown($(this).attr('data-time'), true));

			if ($(this).attr('data-time') > getSecondsSinceMidnight()) return;

			$(this).parent().animate({left: window.innerWidth + 'px'}, 1000, function() {
				$(this).remove();

				$('.trip').each(function() {
					$(this).animate({top: (parseInt($(this).css('top')) - 80) + 'px'}, 500);
				});

			});

		});

		return;
	}

	$.get('//' + location.host + '/getstop?id=' + id).done(function(data) {
		let trips   = data.trips,
			content = '';

		live = data.live;

		for (let i = 0; i < trips.length; i++) {
			let trip = trips[i];

			if (live) {
				content += '

' + trip.number + '

' + toCountdown(trip.scheduled, false) + '

' + toCountdown(trip.expected, false) + '

';
			} else {
				content += '

' + trip.number + '

' + toCountdown(trip.time, true) + '

' + toTime(trip.time) + '

';
			}

		}
		$('#stop-trips').html(content);

		if (settings.panMap) map.panTo({
			lat: data.lat,
			lng: data.lng
		});

		if (!settings.fadeIn) return;

		$('#stop-name').text(data.name);
		$('#stop-desc').text(data.desc);

		document.title = 'Bussiaeg - ' + data.name + (data.desc ? ' - ' + data.desc : '');
		history.pushState(null, document.title, '/?stop=' + data.id);

		$('#stop').fadeIn(fadeTime);
	});

}

// Initialization

function init() {

	map = new google.maps.Map(document.getElementById('map'), {
		center: {
			lat: parseFloat(getParameter('lat')) || 59.388,
			lng: parseFloat(getParameter('lng')) || 24.684
		},
		zoom: 17,
		minZoom: 10,
		maxZoom: 20,
		disableDoubleClickZoom: true,
		disableDefaultUI: true,
		clickableIcons: false,
		styles: [{
			featureType: 'transit.station',
			elementType: 'all',
			stylers: [{
				visibility: 'off'
			}]
		}]
	});

	google.maps.event.addListener(map, 'idle', function(e) {
		let bounds = map.getBounds();

		if (map.getZoom() <= 15) {

			for (let i = 0; i < markers.length; i++) {
				markers[i].setMap(null);
			}

			return;
		}

		$.get('//' + location.host + '/getstops?lat_min=' + bounds.f.b + '&lng_min=' + bounds.b.f + '&lat_max=' + bounds.f.f + '&lng_max=' + bounds.b.b, function(stops) {

			for (let i = 0; i < stops.length; i++) {
				let stop = stops[i];

				let marker = new google.maps.Marker({
					position: {
						lat: stop.lat,
						lng: stop.lng
					},
					icon: new google.maps.MarkerImage('assets/stop.png', new google.maps.Size(24, 24), null, null),
					map: map
				});

				marker.addListener('click', function() {
					if (updater) return;

					showStop(stop.id, {panMap: false, fadeIn: true});
					updater = setInterval(function() {
						showStop(stop.id, {panMap: false, fadeIn: false});
					}, 1000);

				});

				markers.push(marker);
			}

		});

	});

	navigator.geolocation.watchPosition(function(pos) {
		coords = pos.coords;
	});

}

const share = parseInt(getParameter('stop'));
if (share) if (!isNaN(share)) if (!updater) {

	showStop(share, {panMap: true, fadeIn: true});
	updater = setInterval(function() {
		showStop(share, {panMap: false, fadeIn: false});
	}, 1000);

}

// User Interface

$('#stop-top').click(function() {
	clearInterval(updater); updater = null;

	$(this).parent().fadeOut(fadeTime, function() {
		$('#stop-name').text('...');
		$('#stop-desc').text('...');
		$('#stop-trips').html('');
	});

});

$('#map').mousedown(function() {
	$('#bookmarks').animate({left: '-240px'}, fadeTime);
});

$('#btn-bookmarks').click(function() {
	$(this).addClass('bounce');

	$('#bookmarks').animate({left: '0px'}, fadeTime);
});

$('#bookmarks-add').click(function() {
	var bookmarks = localStorage.getItem('bookmarks') || [],
		name = swal({
			type: 'input',
			title: 'Anna asukohale nimi',
			confirmButtonColor: 'deepskyblue',
			showCancelButton: true,
			inputPlaceholder: 'Minu kodu'
		});

	localStorage.setItem('bookmarks', bookmarks);
});

$('#btn-help').click(function() {
	$(this).addClass('bounce');

	$('#help').fadeIn(fadeTime, function() {
		$('#btn-help').removeClass('bounce');
	});

});

$('#help').click(function() {
	$(this).fadeOut(fadeTime);
});

$('#btn-locate').click(function() {
	$(this).addClass('bounce');

	map.panTo({
		lat: coords.latitude,
		lng: coords.longitude
	});

});

$('#btn-locate').on('animationend', function() {
	$(this).removeClass('bounce');
});<commit_msg>Change to leaflet map engine<commit_after>// Declarations

var coords, map, updater, live;

const fadeTime = 250;

// Functions

function getParameter(name) {
	return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
}

function getSecondsSinceMidnight() {
	return ~~((new Date() - new Date().setHours(0, 0, 0, 0)) / 1000);
}

function toHMS(seconds) {
	var hours   = Math.floor(seconds / 3600),
		minutes = Math.floor((seconds % 3600) / 60);
	seconds = seconds - (minutes * 60) - (hours * 3600);
	return {
		h: ('0' + hours).slice(-2),
		m: ('0' + minutes).slice(-2),
		s: ('0' + seconds).slice(-2)
	};
}

function toCountdown(seconds, showHours) {
	seconds = seconds - getSecondsSinceMidnight();
	var time = toHMS(Math.abs(seconds));
	return (seconds < 0 ? '-' : '') + (showHours ? time.h + 'h ': '') + time.m + 'm ' + (showHours ? '' : time.s + 's');
}

function toTime(seconds) {
	var time = toHMS(seconds);
	return time.h + ':' + time.m;
}

function showStop(id, settings) {
	if (updater && !live) {

		$('.trip-scheduled').each(function() {
			$(this).text(toCountdown($(this).attr('data-time'), true));

			if ($(this).attr('data-time') > getSecondsSinceMidnight()) return;

			$(this).parent().animate({left: window.innerWidth + 'px'}, 1000, function() {
				$(this).remove();

				$('.trip').each(function() {
					$(this).animate({top: (parseInt($(this).css('top')) - 80) + 'px'}, 500);
				});

			});

		});

		return;
	}

	$.get('//' + location.host + '/getstop?id=' + id).done(function(data) {
		let trips   = data.trips,
			content = '';

		live = data.live;

		for (let i = 0; i < trips.length; i++) {
			let trip = trips[i];

			if (live) {
				content += '

' + trip.number + '

' + toCountdown(trip.scheduled, false) + '

' + toCountdown(trip.expected, false) + '

';
			} else {
				content += '

' + trip.number + '

' + toCountdown(trip.time, true) + '

' + toTime(trip.time) + '

';
			}

		}
		$('#stop-trips').html(content);

		if (settings.panMap) map.panTo({
			lat: data.lat,
			lng: data.lng
		});

		if (!settings.fadeIn) return;

		$('#stop-name').text(data.name);
		$('#stop-desc').text(data.desc);

		document.title = 'Bussiaeg - ' + data.name + (data.desc ? ' - ' + data.desc : '');
		history.pushState(null, document.title, '/?stop=' + data.id);

		$('#stop').fadeIn(fadeTime);
	});

}

function showStops() {

	if (map.getZoom() <= 15) return map.eachLayer(function(layer) {
		if (layer._icon !== undefined) map.removeLayer(layer);
	});

	const bounds = map.getBounds();
	$.get('//' + location.host + '/getstops?lat_min=' + bounds._northEast.lat + '&lng_min=' + bounds._northEast.lng + '&lat_max=' + bounds._southWest.lat + '&lng_max=' + bounds._southWest.lng, function(stops) {

		for (let i = 0; i < stops.length; i++) {
			let stop = stops[i];

			L.marker([stop.lat, stop.lng], {
				icon: L.icon({
					iconUrl: 'assets/stop.png',
					iconSize: [24, 24],
					draggable: true
				}),
				type: 'stop'
			}).addTo(map).on('click', function() {
				if (updater) return;

				showStop(stop.id, {panMap: false, fadeIn: true});
				updater = setInterval(function() {
					showStop(stop.id, {panMap: false, fadeIn: false});
				}, 1000);

			});

		}

	});

}

// Initialization

var map = L.map('map', {
	center: [
		parseFloat(getParameter('lat')) || 59.388,
		parseFloat(getParameter('lng')) || 24.684
	],
	zoom: 17,
	minZoom: 10,
	maxZoom: 18,
	maxBounds: [[59.874204, 21.396935], [57.290822, 28.838625]],
	attributionControl: false,
	bounceAtZoomLimits: false,
	doubleClickZoom: false,
	zoomControl: false,
	keyboard: false,
	boxZoom: false
});

L.tileLayer('//{s}.google.com/vt/lyrs=phl=en&x={x}&y={y}&z={z}&pbhttps://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i372053562!3m14!2sen-US!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2zcy50OjY2fHAudjpvZmY!4e0', {
    subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
}).addTo(map);

L.control.attribution({
	position: 'bottomleft',
	prefix: 'Bussiaeg.ee | Sõiduplaanid | Peatus | Google | Leaflet'
}).addTo(map);

showStops()
map.on('moveend', function() {
	showStops()
});

map.locate({
	enableHighAccuracy: true,
	setView: true
});

map.on('locationfound', function() {
	console.log('asd');
});

navigator.geolocation.getCurrentPosition(function(pos) {
	map.panTo([pos.coords.latitude, pos.coords.longitude]);
});

navigator.geolocation.watchPosition(function(pos) {
	coords = pos;
});

const share = parseInt(getParameter('stop'));
if (share) if (!isNaN(share)) if (!updater) {

	showStop(share, {panMap: true, fadeIn: true});
	updater = setInterval(function() {
		showStop(share, {panMap: false, fadeIn: false});
	}, 1000);

}

// User Interface

$('#stop-top').click(function() {
	clearInterval(updater); updater = null;

	$(this).parent().fadeOut(fadeTime, function() {
		$('#stop-name').text('...');
		$('#stop-desc').text('...');
		$('#stop-trips').html('');
	});

});

map.on('click', function() {
	$('#bookmarks').animate({left: '-240px'}, fadeTime);
});

$('#btn-bookmarks').click(function() {
	$(this).addClass('bounce');

	$('#bookmarks').animate({left: '0px'}, fadeTime);
});

$('#bookmarks-add').click(function() {
	var bookmarks = localStorage.getItem('bookmarks') || [],
		name = swal({
			type: 'input',
			title: 'Anna asukohale nimi',
			confirmButtonColor: 'deepskyblue',
			showCancelButton: true,
			inputPlaceholder: 'Minu kodu'
		});

	localStorage.setItem('bookmarks', bookmarks);
});

$('#btn-help').click(function() {
	$(this).addClass('bounce');

	$('#help').fadeIn(fadeTime, function() {
		$('#btn-help').removeClass('bounce');
	});

});

$('#help').click(function() {
	$(this).fadeOut(fadeTime);
});

$('#btn-locate').click(function() {
	$(this).addClass('bounce');

	map.panTo([coords.latitude, coords.longitude]);
});

$('#btn-locate').on('animationend', function() {
	$(this).removeClass('bounce');
});<|endoftext|>


<commit_before>export default class XhrPromise {
  constructor(url) {
    this._url = url;
  }

  set data(data) {
    this._data = data;
  }

  post() {
    return new Promise((resolve, reject) => {
      let req = new XMLHttpRequest();

      // req.addEventListener("onreadystatechange", () => { console.log(this); });
      req.addEventListener("load", () => { resolve(); });
      req.addEventListener("error", () => { reject("error"); });
      req.addEventListener("abort", () => { reject("abort"); });
      req.addEventListener("timeout", () => { reject("timeout"); });
      req.open("POST", this._url);
      req.withCredentials = true;
      req.setRequestHeader("Content-type", "application/json");

      if (this._data) {
        req.send(JSON.stringify(this._data));
      } else {
        req.send();
      }
    });
  }

  get() {
    return new Promise((resolve, reject) => {
      let req = new XMLHttpRequest();

      req.addEventListener("load", () => { resolve(); });
      req.addEventListener("error", () => { reject("error"); });
      req.addEventListener("abort", () => { reject("abort"); });
      req.addEventListener("timeout", () => { reject("timeout"); });
      req.open("GET", this._url);
      req.withCredentials = true;
      req.setRequestHeader("Content-type", "application/json");

      if (this._data) {
        req.send(JSON.stringify(this._data));
      }
    });
  }
}
<commit_msg>debugging<commit_after>export default class XhrPromise {
  constructor(url) {
    this._url = url;
  }

  set data(data) {
    this._data = data;
  }

  post() {
    return new Promise((resolve, reject) => {
      let req = new XMLHttpRequest();

      // req.addEventListener("onreadystatechange", () => { console.log(this); });
      req.addEventListener("load", () => { resolve(); });
      req.addEventListener("error", () => { reject("error"); });
      req.addEventListener("abort", () => { reject("abort"); });
      req.addEventListener("timeout", () => { reject("timeout"); });
      req.open("POST", this._url);
      req.withCredentials = true;
      req.setRequestHeader("Content-type", "application/json");

      if (this._data) {
        req.send(JSON.stringify(this._data));
      } else {
        req.send();
      }
    });
  }

  get() {
    return new Promise((resolve, reject) => {
      let req = new XMLHttpRequest();

      req.addEventListener("load", () => { resolve(); });
      req.addEventListener("error", () => { reject("error"); });
      req.addEventListener("abort", () => { reject("abort"); });
      req.addEventListener("timeout", () => { reject("timeout"); });
      req.open("GET", this._url);
      req.withCredentials = true;
      req.setRequestHeader("Content-type", "application/json");

      if (this._data) {
        req.send(JSON.stringify(this._data));
      } else {
        req.send();
      }
    });
  }
}
<|endoftext|>


<commit_before>/**
 * @fileoverview Raphael title renderer.
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var chartConst = require('../const');
var raphaelRenderUtil = require('../plugins/raphaelRenderUtil');

var UNSELECTED_LEGEND_LABEL_OPACITY = 0.5;
var ICON_WIDTH = 10;
var CHECKBOX_WIDTH = 10;
var CHECKBOX_HEIGHT = 10;

var RaphaelLegendComponent = tui.util.defineClass(/** @lends RaphaelLegendComponent.prototype */ {

    /**
     * @param {Array.<object>} legendData Array of legend item data
     * @private
     */
    _renderLegendItems: function(legendData) {
        var self = this;
        var labelPaddingLeft = chartConst.LEGEND_LABEL_LEFT_PADDING;
        var position = tui.util.extend({}, this.basePosition);

        tui.util.forEach(legendData, function(legendDatum, index) {
            var legendIndex = legendDatum.index;
            var legendColor = legendDatum.colorByPoint ? '#aaa' : legendDatum.theme.color;
            var isUnselected = legendDatum.isUnselected;
            var labelHeight = legendDatum.labelHeight;
            var checkboxData = legendDatum.checkbox;
            var predicatedLegendLength = position.left + ICON_WIDTH + self.labelWidths[index]
                + (labelPaddingLeft * 2) + (checkboxData ? CHECKBOX_WIDTH + labelPaddingLeft : 0);
            var isNeedBreakLine = (predicatedLegendLength > self.paper.width);

            if (self.isHorizontal && isNeedBreakLine) {
                position.top += (labelHeight + chartConst.LABEL_PADDING_TOP);
                position.left = self.basePosition.left;
            }

            if (checkboxData) {
                self._renderCheckbox(position, checkboxData, legendIndex, self.legendSet);

                position.left += (CHECKBOX_WIDTH + labelPaddingLeft);
            }

            self._renderIcon(position, {
                legendColor: legendColor,
                iconType: legendDatum.iconType,
                labelHeight: labelHeight,
                isUnselected: isUnselected,
                legendIndex: legendIndex,
                legendSet: self.legendSet
            });

            position.left += ICON_WIDTH + labelPaddingLeft;

            self._renderLabel(position, {
                labelText: legendDatum.label,
                labelHeight: labelHeight,
                isUnselected: isUnselected,
                legendIndex: legendIndex,
                legendSet: self.legendSet
            });

            if (self.isHorizontal) {
                position.left += self.labelWidths[index] + labelPaddingLeft;
            } else {
                position.left = self.basePosition.left;
                position.top += labelHeight + chartConst.LINE_MARGIN_TOP;
            }
        });
    },

    /**
     * @param {Array.<object>} legendData Array of legend item data
     * @param {number} sliceIndex slice index of
     * @returns {Array.<object>}
     * @private
     */
    _getLegendData: function(legendData, sliceIndex) {
        var positionTop = this.basePosition.top;
        var totalHeight = this.dimension.height;
        var chartHeight = this.paper.height;
        var resultLegendData, pageHeight, singleItemHeight, visibleItemCount;

        if (!legendData.length) {
            return null;
        }

        if (totalHeight + (positionTop * 2) > chartHeight) {
            pageHeight = chartHeight - (positionTop * 2);
            singleItemHeight = (legendData[0].labelHeight + chartConst.LINE_MARGIN_TOP);

            visibleItemCount = Math.floor(pageHeight / singleItemHeight);

            resultLegendData = legendData.slice((sliceIndex - 1) * visibleItemCount, sliceIndex * visibleItemCount);
        } else {
            resultLegendData = legendData;
        }

        return resultLegendData;
    },

    /**
     * Render legend
     * @param {object} data rendering data
     *     @param {HTMLElement} data.container legend container
     *     @param {Array.<object>} data.legendData rendering legendData
     *     @param {boolean} data.isHorizontal boolean value of horizontal or not
     *     @param {{height:number, width:number}} data.dimension legend dimension
     *     @param {object} data.labelTheme legend label theme object
     *     @param {number} data.labelWidths label widths
     *     @param {object} data.eventBus event bus
     * @returns {object} paper
     */
    render: function(data) {
        var legendData, legendHeight;

        this.eventBus = data.eventBus;
        this.paper = data.paper;
        this.dimension = data.dimension;
        this.legendSet = this.paper.set();
        this.labelWidths = data.labelWidths;
        this.labelTheme = data.labelTheme;
        this.basePosition = data.position;
        this.isHorizontal = data.isHorizontal;
        this.originalLegendData = data.legendData;
        if (!tui.util.isNumber(this.currentPageCount)) {
            this.currentPageCount = 1;
        }

        legendData = this._getLegendData(data.legendData, this.currentPageCount);

        this._renderLegendItems(legendData);

        if (legendData.length < data.legendData.length) {
            legendHeight = this.paper.height - (this.basePosition.top * 2);

            this.availablePageCount = Math.ceil(data.dimension.height / legendHeight);

            this._renderPaginationArea(this.basePosition, {
                width: data.dimension.width,
                height: legendHeight
            });
        }

        return this.legendSet;
    },

    /**
     * @param {string} direction direction string of paginate 'next' or 'previous'
     * @private
     */
    _paginateLegendAreaTo: function(direction) {
        var pageNumber = this.currentPageCount;

        this._removeLegendItems();

        if (direction === 'next') {
            pageNumber += 1;
        } else {
            pageNumber -= 1;
        }

        this._renderLegendItems(this._getLegendData(this.originalLegendData, pageNumber));
    },

    _removeLegendItems: function() {
        this.legendSet.forEach(function(legendItem) {
            tui.util.forEach(legendItem.events, function(event) {
                event.unbind();
            });
            legendItem.remove();
        });
    },

    /**
     * @param {{top: number, left: number}} position legend area position
     * @param {{height: number, width: number}} dimension legend area dimension
     * @private
     */
    _renderPaginationArea: function(position, dimension) {
        var self = this;
        var BUTTON_WIDTH = 10;
        var BUTTON_PADDING_LEFT = 5;
        var controllerPositionTop = position.top + dimension.height - chartConst.CHART_PADDING;
        var controllerPositionLeft = position.left - chartConst.CHART_PADDING;
        var rightButtonPositionLeft = controllerPositionLeft + dimension.width - BUTTON_WIDTH;
        var leftButtonPositionLeft = rightButtonPositionLeft - (BUTTON_PADDING_LEFT + BUTTON_WIDTH);
        var lowerArrowPath = [
            'M', rightButtonPositionLeft, ',', (controllerPositionTop + 3),
            'L', (rightButtonPositionLeft + 5), ',', (controllerPositionTop + 8),
            'L', (rightButtonPositionLeft + 10), ',', (controllerPositionTop + 3)].join('');
        var upperArrowPath = [
            'M', leftButtonPositionLeft, ',', (controllerPositionTop + 8),
            'L', (leftButtonPositionLeft + 5), ',', (controllerPositionTop + 3),
            'L', (leftButtonPositionLeft + 10), ',', (controllerPositionTop + 8)].join('');

        this.upperButton = raphaelRenderUtil.renderLine(this.paper, upperArrowPath, '#555', 3);
        this.lowerButton = raphaelRenderUtil.renderLine(this.paper, lowerArrowPath, '#555', 3);

        this.upperButton.click(function() {
            if (self.currentPageCount > 1) {
                self._paginateLegendAreaTo('previous');
                self.currentPageCount -= 1;
            }
        });

        this.lowerButton.click(function() {
            if (self.currentPageCount < self.availablePageCount) {
                self._paginateLegendAreaTo('next');
                self.currentPageCount += 1;
            }
        });
    },

    /**
     * Make labels width.
     * @param {Array.<{chartType: ?string, label: string}>} legendData legend data
     * @param {object} theme theme object
     * @returns {Array.<number>} label widths
     */
    makeLabelWidths: function(legendData, theme) {
        return tui.util.map(legendData, function(item) {
            var labelWidth = raphaelRenderUtil.getRenderedTextSize(item.label, theme.fontSize, theme.fontFamily).width;

            return labelWidth + chartConst.LEGEND_AREA_PADDING;
        });
    },

    /**
     * Get rendered label height
     * @param {string} labelText label text
     * @param {object} theme theme object
     * @returns {number}
     */
    getRenderedLabelHeight: function(labelText, theme) {
        return raphaelRenderUtil.getRenderedTextSize(labelText, theme.fontSize, theme.fontFamily).height;
    },

    /**
     * Render label text and attach event
     * @param {object} position left, top
     * @param {object} data rendering data
     *     @param {string} data.labelText label text
     *     @param {number} data.labelHeight label height
     *     @param {boolean} data.isUnselected boolean value for selected or not
     *     @param {number} data.legendIndex legend index
     *     @param {Array.<object>} data.legendSet legend set
     * @private
     */
    _renderLabel: function(position, data) {
        var eventBus = this.eventBus;
        var labelTheme = this.labelTheme;
        var pos = {
            left: position.left,
            top: position.top + (data.labelHeight / 2)
        };
        var attributes = {
            'font-size': labelTheme.fontSize,
            'font-family': labelTheme.fontFamily,
            'font-weight': labelTheme.fontWeight,
            opacity: data.isUnselected ? UNSELECTED_LEGEND_LABEL_OPACITY : 1,
            'text-anchor': 'start'
        };
        var label = raphaelRenderUtil.renderText(this.paper, pos, data.labelText, attributes);

        label.data('index', data.legendIndex);

        label.node.style.userSelect = 'none';
        label.node.style.cursor = 'pointer';

        data.legendSet.push(label);

        label.click(function() {
            eventBus.fire('labelClicked', data.legendIndex);
        });
    },

    /**
     * Render checkbox
     * @param {object} position left, top
     * @param {{checked: boolean}} checkboxData checkbox data
     * @param {number} legendIndex legend index
     * @param {Array.<object>} legendSet legend set
     */
    _renderCheckbox: function(position, checkboxData, legendIndex, legendSet) {
        var self = this;
        var checkboxSet;
        var left = position.left;
        var top = position.top;
        var vPathString = 'M' + ((CHECKBOX_WIDTH * 0.3) + left) + ',' + ((CHECKBOX_HEIGHT * 0.5) + top)
            + 'L' + ((CHECKBOX_WIDTH * 0.5) + left) + ',' + ((CHECKBOX_HEIGHT * 0.7) + top)
            + 'L' + ((CHECKBOX_WIDTH * 0.8) + left) + ',' + ((CHECKBOX_HEIGHT * 0.2) + top);

        if (checkboxData) {
            checkboxSet = this.paper.set();

            checkboxSet.push(this.paper.rect(left, top, CHECKBOX_WIDTH, CHECKBOX_HEIGHT, 2).attr({
                fill: '#fff'
            }));

            if (checkboxData.checked) {
                checkboxSet.push(this.paper.path(vPathString));
            }

            checkboxSet.click(function() {
                self.eventBus.fire('checkboxClicked', legendIndex);
            });

            checkboxSet.forEach(function(checkbox) {
                legendSet.push(checkbox);
            });
        }
    },

    /**
     * Render legend icon and attach event
     * @param {object} position left, top
     * @param {object} data rendering data
     *     @param {string} data.labelText label text
     *     @param {number} data.labelHeight label height
     *     @param {string} data.legendColor legend color hex
     *     @param {boolean} data.isUnselected boolean value for selected or not
     *     @param {number} data.legendIndex legend index
     *     @param {Array.<object>} data.legendSet legend set
     * @private
     */
    _renderIcon: function(position, data) {
        var self = this;
        var icon, pathString;

        this.paper.setStart();

        if (data.iconType === 'line') {
            pathString = 'M' + position.left + ',' + (position.top + (data.labelHeight / 2))
                + 'H' + (position.left + 10);

            icon = raphaelRenderUtil.renderLine(this.paper, pathString, data.legendColor, 3);
        } else {
            icon = raphaelRenderUtil.renderRect(this.paper, {
                left: position.left,
                top: position.top,
                width: 10,
                height: 10
            }, {
                'stroke-width': 0,
                fill: data.legendColor
            });
        }

        icon.click(function() {
            self.eventBus.fire('labelClicked', data.legendIndex);
        });

        data.legendSet.push(icon);
    },
    selectLegend: function(index, legendSet) {
        legendSet.forEach(function(element) {
            var indexData = element.data('index');

            if (tui.util.isNull(indexData) || tui.util.isUndefined(indexData)) {
                element.attr({
                    opacity: 1
                });
            } else if (!tui.util.isUndefined(indexData)) {
                if (tui.util.isNumber(index) && indexData !== index) {
                    element.attr({
                        opacity: UNSELECTED_LEGEND_LABEL_OPACITY
                    });
                } else {
                    element.attr({
                        opacity: 1
                    });
                }
            }
        });
    }
});

module.exports = RaphaelLegendComponent;
<commit_msg>fix: Legend bottom visible issue<commit_after>/**
 * @fileoverview Raphael title renderer.
 * @author NHN Ent.
 *         FE Development Lab <dl_javascript@nhnent.com>
 */

'use strict';

var chartConst = require('../const');
var raphaelRenderUtil = require('../plugins/raphaelRenderUtil');

var UNSELECTED_LEGEND_LABEL_OPACITY = 0.5;
var ICON_WIDTH = 10;
var CHECKBOX_WIDTH = 10;
var CHECKBOX_HEIGHT = 10;

var RaphaelLegendComponent = tui.util.defineClass(/** @lends RaphaelLegendComponent.prototype */ {

    /**
     * @param {Array.<object>} legendData Array of legend item data
     * @private
     */
    _renderLegendItems: function(legendData) {
        var self = this;
        var labelPaddingLeft = chartConst.LEGEND_LABEL_LEFT_PADDING;
        var position = tui.util.extend({}, this.basePosition);

        tui.util.forEach(legendData, function(legendDatum, index) {
            var legendIndex = legendDatum.index;
            var legendColor = legendDatum.colorByPoint ? '#aaa' : legendDatum.theme.color;
            var isUnselected = legendDatum.isUnselected;
            var labelHeight = legendDatum.labelHeight;
            var checkboxData = legendDatum.checkbox;
            var predicatedLegendLength = position.left + ICON_WIDTH + self.labelWidths[index]
                + (labelPaddingLeft * 2) + (checkboxData ? CHECKBOX_WIDTH + labelPaddingLeft : 0);
            var isNeedBreakLine = (predicatedLegendLength > self.paper.width);

            if (self.isHorizontal && isNeedBreakLine) {
                position.top += (labelHeight + chartConst.LABEL_PADDING_TOP);
                position.left = self.basePosition.left;
            }

            if (checkboxData) {
                self._renderCheckbox(position, checkboxData, legendIndex, self.legendSet);

                position.left += (CHECKBOX_WIDTH + labelPaddingLeft);
            }

            self._renderIcon(position, {
                legendColor: legendColor,
                iconType: legendDatum.iconType,
                labelHeight: labelHeight,
                isUnselected: isUnselected,
                legendIndex: legendIndex,
                legendSet: self.legendSet
            });

            position.left += ICON_WIDTH + labelPaddingLeft;

            self._renderLabel(position, {
                labelText: legendDatum.label,
                labelHeight: labelHeight,
                isUnselected: isUnselected,
                legendIndex: legendIndex,
                legendSet: self.legendSet
            });

            if (self.isHorizontal) {
                position.left += self.labelWidths[index] + labelPaddingLeft;
            } else {
                position.left = self.basePosition.left;
                position.top += labelHeight + chartConst.LINE_MARGIN_TOP;
            }
        });
    },

    /**
     * @param {Array.<object>} legendData Array of legend item data
     * @param {number} sliceIndex slice index of
     * @returns {Array.<object>}
     * @private
     */
    _getLegendData: function(legendData, sliceIndex) {
        var positionTop = this.basePosition.top;
        var totalHeight = this.dimension.height;
        var chartHeight = this.paper.height;
        var resultLegendData, pageHeight, singleItemHeight, visibleItemCount;

        if (!legendData.length) {
            return null;
        }

        if (!this.isHorizontal && totalHeight + (positionTop * 2) > chartHeight) {
            pageHeight = chartHeight - (positionTop * 2);
            singleItemHeight = (legendData[0].labelHeight + chartConst.LINE_MARGIN_TOP);

            visibleItemCount = Math.floor(pageHeight / singleItemHeight);

            resultLegendData = legendData.slice((sliceIndex - 1) * visibleItemCount, sliceIndex * visibleItemCount);
        } else {
            resultLegendData = legendData;
        }

        return resultLegendData;
    },

    /**
     * Render legend
     * @param {object} data rendering data
     *     @param {HTMLElement} data.container legend container
     *     @param {Array.<object>} data.legendData rendering legendData
     *     @param {boolean} data.isHorizontal boolean value of horizontal or not
     *     @param {{height:number, width:number}} data.dimension legend dimension
     *     @param {object} data.labelTheme legend label theme object
     *     @param {number} data.labelWidths label widths
     *     @param {object} data.eventBus event bus
     * @returns {object} paper
     */
    render: function(data) {
        var legendData, legendHeight;

        this.eventBus = data.eventBus;
        this.paper = data.paper;
        this.dimension = data.dimension;
        this.legendSet = this.paper.set();
        this.labelWidths = data.labelWidths;
        this.labelTheme = data.labelTheme;
        this.basePosition = data.position;
        this.isHorizontal = data.isHorizontal;
        this.originalLegendData = data.legendData;
        if (!tui.util.isNumber(this.currentPageCount)) {
            this.currentPageCount = 1;
        }

        legendData = this._getLegendData(data.legendData, this.currentPageCount);

        this._renderLegendItems(legendData);

        if (!this.isHorizontal && legendData.length < data.legendData.length) {
            legendHeight = this.paper.height - (this.basePosition.top * 2);

            this.availablePageCount = Math.ceil(data.dimension.height / legendHeight);

            this._renderPaginationArea(this.basePosition, {
                width: data.dimension.width,
                height: legendHeight
            });
        }

        return this.legendSet;
    },

    /**
     * @param {string} direction direction string of paginate 'next' or 'previous'
     * @private
     */
    _paginateLegendAreaTo: function(direction) {
        var pageNumber = this.currentPageCount;

        this._removeLegendItems();

        if (direction === 'next') {
            pageNumber += 1;
        } else {
            pageNumber -= 1;
        }

        this._renderLegendItems(this._getLegendData(this.originalLegendData, pageNumber));
    },

    _removeLegendItems: function() {
        this.legendSet.forEach(function(legendItem) {
            tui.util.forEach(legendItem.events, function(event) {
                event.unbind();
            });
            legendItem.remove();
        });
    },

    /**
     * @param {{top: number, left: number}} position legend area position
     * @param {{height: number, width: number}} dimension legend area dimension
     * @private
     */
    _renderPaginationArea: function(position, dimension) {
        var self = this;
        var BUTTON_WIDTH = 10;
        var BUTTON_PADDING_LEFT = 5;
        var controllerPositionTop = position.top + dimension.height - chartConst.CHART_PADDING;
        var controllerPositionLeft = position.left - chartConst.CHART_PADDING;
        var rightButtonPositionLeft = controllerPositionLeft + dimension.width - BUTTON_WIDTH;
        var leftButtonPositionLeft = rightButtonPositionLeft - (BUTTON_PADDING_LEFT + BUTTON_WIDTH);
        var lowerArrowPath = [
            'M', rightButtonPositionLeft, ',', (controllerPositionTop + 3),
            'L', (rightButtonPositionLeft + 5), ',', (controllerPositionTop + 8),
            'L', (rightButtonPositionLeft + 10), ',', (controllerPositionTop + 3)].join('');
        var upperArrowPath = [
            'M', leftButtonPositionLeft, ',', (controllerPositionTop + 8),
            'L', (leftButtonPositionLeft + 5), ',', (controllerPositionTop + 3),
            'L', (leftButtonPositionLeft + 10), ',', (controllerPositionTop + 8)].join('');

        this.upperButton = raphaelRenderUtil.renderLine(this.paper, upperArrowPath, '#555', 3);
        this.lowerButton = raphaelRenderUtil.renderLine(this.paper, lowerArrowPath, '#555', 3);

        this.upperButton.click(function() {
            if (self.currentPageCount > 1) {
                self._paginateLegendAreaTo('previous');
                self.currentPageCount -= 1;
            }
        });

        this.lowerButton.click(function() {
            if (self.currentPageCount < self.availablePageCount) {
                self._paginateLegendAreaTo('next');
                self.currentPageCount += 1;
            }
        });
    },

    /**
     * Make labels width.
     * @param {Array.<{chartType: ?string, label: string}>} legendData legend data
     * @param {object} theme theme object
     * @returns {Array.<number>} label widths
     */
    makeLabelWidths: function(legendData, theme) {
        return tui.util.map(legendData, function(item) {
            var labelWidth = raphaelRenderUtil.getRenderedTextSize(item.label, theme.fontSize, theme.fontFamily).width;

            return labelWidth + chartConst.LEGEND_AREA_PADDING;
        });
    },

    /**
     * Get rendered label height
     * @param {string} labelText label text
     * @param {object} theme theme object
     * @returns {number}
     */
    getRenderedLabelHeight: function(labelText, theme) {
        return raphaelRenderUtil.getRenderedTextSize(labelText, theme.fontSize, theme.fontFamily).height;
    },

    /**
     * Render label text and attach event
     * @param {object} position left, top
     * @param {object} data rendering data
     *     @param {string} data.labelText label text
     *     @param {number} data.labelHeight label height
     *     @param {boolean} data.isUnselected boolean value for selected or not
     *     @param {number} data.legendIndex legend index
     *     @param {Array.<object>} data.legendSet legend set
     * @private
     */
    _renderLabel: function(position, data) {
        var eventBus = this.eventBus;
        var labelTheme = this.labelTheme;
        var pos = {
            left: position.left,
            top: position.top + (data.labelHeight / 2)
        };
        var attributes = {
            'font-size': labelTheme.fontSize,
            'font-family': labelTheme.fontFamily,
            'font-weight': labelTheme.fontWeight,
            opacity: data.isUnselected ? UNSELECTED_LEGEND_LABEL_OPACITY : 1,
            'text-anchor': 'start'
        };
        var label = raphaelRenderUtil.renderText(this.paper, pos, data.labelText, attributes);

        label.data('index', data.legendIndex);

        label.node.style.userSelect = 'none';
        label.node.style.cursor = 'pointer';

        data.legendSet.push(label);

        label.click(function() {
            eventBus.fire('labelClicked', data.legendIndex);
        });
    },

    /**
     * Render checkbox
     * @param {object} position left, top
     * @param {{checked: boolean}} checkboxData checkbox data
     * @param {number} legendIndex legend index
     * @param {Array.<object>} legendSet legend set
     */
    _renderCheckbox: function(position, checkboxData, legendIndex, legendSet) {
        var self = this;
        var checkboxSet;
        var left = position.left;
        var top = position.top;
        var vPathString = 'M' + ((CHECKBOX_WIDTH * 0.3) + left) + ',' + ((CHECKBOX_HEIGHT * 0.5) + top)
            + 'L' + ((CHECKBOX_WIDTH * 0.5) + left) + ',' + ((CHECKBOX_HEIGHT * 0.7) + top)
            + 'L' + ((CHECKBOX_WIDTH * 0.8) + left) + ',' + ((CHECKBOX_HEIGHT * 0.2) + top);

        if (checkboxData) {
            checkboxSet = this.paper.set();

            checkboxSet.push(this.paper.rect(left, top, CHECKBOX_WIDTH, CHECKBOX_HEIGHT, 2).attr({
                fill: '#fff'
            }));

            if (checkboxData.checked) {
                checkboxSet.push(this.paper.path(vPathString));
            }

            checkboxSet.click(function() {
                self.eventBus.fire('checkboxClicked', legendIndex);
            });

            checkboxSet.forEach(function(checkbox) {
                legendSet.push(checkbox);
            });
        }
    },

    /**
     * Render legend icon and attach event
     * @param {object} position left, top
     * @param {object} data rendering data
     *     @param {string} data.labelText label text
     *     @param {number} data.labelHeight label height
     *     @param {string} data.legendColor legend color hex
     *     @param {boolean} data.isUnselected boolean value for selected or not
     *     @param {number} data.legendIndex legend index
     *     @param {Array.<object>} data.legendSet legend set
     * @private
     */
    _renderIcon: function(position, data) {
        var self = this;
        var icon, pathString;

        this.paper.setStart();

        if (data.iconType === 'line') {
            pathString = 'M' + position.left + ',' + (position.top + (data.labelHeight / 2))
                + 'H' + (position.left + 10);

            icon = raphaelRenderUtil.renderLine(this.paper, pathString, data.legendColor, 3);
        } else {
            icon = raphaelRenderUtil.renderRect(this.paper, {
                left: position.left,
                top: position.top,
                width: 10,
                height: 10
            }, {
                'stroke-width': 0,
                fill: data.legendColor
            });
        }

        icon.click(function() {
            self.eventBus.fire('labelClicked', data.legendIndex);
        });

        data.legendSet.push(icon);
    },
    selectLegend: function(index, legendSet) {
        legendSet.forEach(function(element) {
            var indexData = element.data('index');

            if (tui.util.isNull(indexData) || tui.util.isUndefined(indexData)) {
                element.attr({
                    opacity: 1
                });
            } else if (!tui.util.isUndefined(indexData)) {
                if (tui.util.isNumber(index) && indexData !== index) {
                    element.attr({
                        opacity: UNSELECTED_LEGEND_LABEL_OPACITY
                    });
                } else {
                    element.attr({
                        opacity: 1
                    });
                }
            }
        });
    }
});

module.exports = RaphaelLegendComponent;
<|endoftext|>


<commit_before>// Declarations

var coords, map, updater, live;

const fadeTime = 250,
	  updateTime = 2000;

// Functions (Stops)

function getParameter(name) {
	return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
}

function getSecondsSinceMidnight() {
	return ~~((new Date() - new Date().setHours(0, 0, 0, 0)) / 1000);
}

function toHMS(seconds) {
	var hours   = Math.floor(seconds / 3600),
		minutes = Math.floor((seconds % 3600) / 60);
	seconds = seconds - (minutes * 60) - (hours * 3600);
	return {
		h: ('0' + hours).slice(-2),
		m: ('0' + minutes).slice(-2),
		s: ('0' + seconds).slice(-2)
	};
}

function toCountdown(seconds, showHours) {
	seconds = seconds - getSecondsSinceMidnight();
	var time = toHMS(Math.abs(seconds));
	return (seconds < 0 ? '-' : '') + (showHours ? time.h + 'h ': '') + time.m + 'm ' + (showHours ? '' : time.s + 's');
}

function toTime(seconds) {
	var time = toHMS(seconds);
	return time.h + ':' + time.m;
}

function showStop(id, settings) {
	if (updater && !live) {

		$('.trip-scheduled').each(function() {
			$(this).text(toCountdown($(this).attr('data-time'), true));

			if ($(this).attr('data-time') > getSecondsSinceMidnight()) return;

			$(this).parent().animate({left: window.innerWidth + 'px'}, 1000, function() {
				$(this).remove();

				$('.trip').each(function() {
					$(this).animate({top: (parseInt($(this).css('top')) - 80) + 'px'}, 500);
				});

			});

		});

		return;
	}

	$.get('//' + location.host + '/getstop?id=' + id).done(function(stop) {
		hideBookmarks();

		var trips   = stop.trips,
			content = '';

		live = stop.live;

		for (var i = 0; i < trips.length; i++) {
			var trip = trips[i];

			if (live) {
				content += '

' + trip.number + '

' + toCountdown(trip.scheduled, false) + '

' + toCountdown(trip.expected, false) + '

';
			} else {
				content += '

' + trip.number + '

' + toCountdown(trip.time, true) + '

' + toTime(trip.time) + '

';
			}

		}
		$('#stop-trips').html(content);

		if (settings.panMap) map.panTo({
			lat: stop.lat,
			lng: stop.lng
		});

		if (!settings.fadeIn) return;

		document.title = 'Bussiaeg - ' + stop.name + (stop.desc ? ' - ' + stop.desc : '');
		history.pushState(null, document.title, '/?stop=' + stop.id);

		$('#stop-name').text(stop.name);
		$('#stop-desc').text(stop.desc);

		$('#stop').fadeIn(fadeTime);
	});

}

function showStops() {

	if (map.getZoom() <= 15) return map.eachLayer(function(layer) {
		if (layer._icon !== undefined) map.removeLayer(layer);
	});

	var bounds = map.getBounds();
	$.get('//' + location.host + '/getstops?lat_min=' + bounds._northEast.lat + '&lng_min=' + bounds._northEast.lng + '&lat_max=' + bounds._southWest.lat + '&lng_max=' + bounds._southWest.lng, function(stops) {

		for (var i = 0; i < stops.length; i++) {

			(function() {
				var stop = stops[i];

				L.marker([stop.lat, stop.lng], {
					icon: L.icon({
						iconUrl: 'assets/stop.png',
						iconSize: [24, 24],
						iconAnchor: [0, 0],
					})
				}).addTo(map).on('click', function() {
					if (updater) return;

					showStop(stop.id, {panMap: false, fadeIn: true});
					updater = setInterval(function() {
						showStop(stop.id, {panMap: false, fadeIn: false});
					}, updateTime);

				});

			})();

		}

	});

}

// Functions (Bookmarks)

function addBookmark() {

	swal({
		type: 'input',
		title: 'Sisesta nimi',
		confirmButtonColor: 'deepskyblue',
		confirmButtonText: 'Lisa',
		showCancelButton: true,
		cancelButtonColor: '#fa5858',
		cancelButtonText: 'Tagasi',
		inputPlaceholder: 'Minu kodu',
		animation: 'slide-from-top'
	}, function(input) {
		var bookmarks = JSON.parse(localStorage.getItem('bookmarks')) || [];

		if (input !== false && $.trim(input) != '') bookmarks.push({
			name: input,
			lat:  map.getCenter().lat,
			lng:  map.getCenter().lng,
			zoom: map.getZoom()
		});

		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));

		hideBookmarks();
	});

}

function deleteBookmark(el) {

	swal({
		title: 'Kustuta?',
		text: el.text(),
		confirmButtonText: 'Jah',
		cancelButtonText: 'Ei',
		showCancelButton: true
	}, function(isConfirm) {
		if (!isConfirm) return;

		var bookmarks = JSON.parse(localStorage.getItem('bookmarks'));

		for (var i = 0; i < bookmarks.length; i++) {
			var bookmark = bookmarks[i];

			if (bookmark.lat != el.data('lat') || bookmark.lng != el.data('lng')) continue;

			bookmarks.splice(i, 1);
			el.remove();

			break;
		}

		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
	});

}

function showBookmarks() {
	var bookmarks = JSON.parse(localStorage.getItem('bookmarks')) || [];

	var content = '
Lisa asukoht
';
	for (var i = 0; i < bookmarks.length; i++) {
		var bookmark = bookmarks[i];

		content += '
' + bookmark.name + '
';

	}
	$('#bookmarks').html(content);

	$('.bookmark').each(function() {
		$(this).hammer().on('swiperight', function() {
			deleteBookmark($(this));
		});
	});

	$('#bookmarks').animate({left: '0px'}, fadeTime);
}

function hideBookmarks() {
	$('#bookmarks').animate({left: '-240px'}, fadeTime);
}

// Initialization

const share = parseInt(getParameter('stop'));
if (share) if (!isNaN(share)) if (!updater) {

	showStop(share, {panMap: true, fadeIn: true});
	updater = setInterval(function() {
		showStop(share, {panMap: false, fadeIn: false});
	}, updateTime);

}

var map = L.map('map', {
	center: [
		parseFloat(getParameter('lat')) || 59.388,
		parseFloat(getParameter('lng')) || 24.685
	],
	zoom: 16,
	minZoom: 10,
	maxZoom: 18,
	maxBounds: [[59.874204, 21.396935], [57.290822, 28.838625]],
	attributionControl: false,
	bounceAtZoomLimits: false,
	doubleClickZoom: false,
	zoomControl: false,
	keyboard: false,
	boxZoom: false
});

L.tileLayer('//{s}.google.com/vt/lyrs=phl=en&x={x}&y={y}&z={z}&pbhttps://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i372053562!3m14!2sen-US!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2zcy50OjY2fHAudjpvZmY!4e0', {
    subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
}).addTo(map);

L.control.attribution({
	position: 'bottomleft',
	prefix: 'Bussiaeg.ee | Sõiduplaanid | Peatus | Google | Leaflet'
}).addTo(map);

showStops();
map.on('moveend', function() {
	showStops();
});

navigator.geolocation.getCurrentPosition(function(pos) {
	if (pos.coords.accuracy < 250) map.panTo([pos.coords.latitude, pos.coords.longitude]);
});

navigator.geolocation.watchPosition(function(pos) {
	coords = pos.coords;
});

// User Interface (Stops)

$('#stop-top').click(function() {
	clearInterval(updater); updater = null;

	$(this).parent().fadeOut(fadeTime);

	document.title = 'Bussiaeg';
	history.pushState(null, document.title, '/');

});

// User Interface (Bookmarks)

map.on('click dragstart', function() {
	$(this).addClass('bounce');
	hideBookmarks();
});

$('#bookmarks').hammer().on('swipeleft', function() {
	hideBookmarks();
});

$('#btn-bookmarks').click(function() {
	$(this).addClass('bounce');
	showBookmarks();
});

$('#bookmarks').on('click', '#bookmarks-add', function() {
	addBookmark();
});

$('#bookmarks').on('click', '.bookmark', function() {
	hideBookmarks();

	map.panTo([$(this).data('lat'), $(this).data('lng')]);
	map.setZoom($(this).data('zoom'));

});

// User Interface (Help)

$('#btn-help').click(function() {
	$(this).addClass('bounce');

	hideBookmarks();

	$('#help').fadeIn(fadeTime, function() {
		$('#btn-help').removeClass('bounce');
	});

});

$('#help').click(function() {
	$(this).fadeOut(fadeTime);
});

// User Interface (Locate)

$('#btn-locate').click(function() {
	$(this).addClass('bounce');
	if (coords) map.panTo([coords.latitude, coords.longitude]);
});

$('#btn-locate').on('animationend', function() {
	$(this).removeClass('bounce');
});<commit_msg>Fix time display format<commit_after>// Declarations

var coords, map, updater, live;

const fadeTime = 250,
	  updateTime = 2000;

// Functions (Stops)

function getParameter(name) {
	return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
}

function getSecondsSinceMidnight() {
	return ~~((new Date() - new Date().setHours(0, 0, 0, 0)) / 1000);
}

function toHMS(seconds) {
	var hours   = Math.floor(seconds / 3600),
		minutes = Math.floor((seconds % 3600) / 60);
	seconds = seconds - (minutes * 60) - (hours * 3600);
	return { h: hours, m: minutes, s: seconds };
}

function toCountdown(seconds, showHours) {
	seconds = seconds - getSecondsSinceMidnight();
	var time = toHMS(Math.abs(seconds));
	return (seconds < 0 ? '-' : '') + (showHours && time.h !== 0 ? time.h.toString() + 'h ' : '') + (time.m !== 0 ? time.m.toString() + 'm ' : '') + time.s.toString() + 's';
}

function toTime(seconds) {
	var time = toHMS(seconds);
	return ('0' + time.h).slice(-2) + ':' + ('0' + time.m).slice(-2);
}

function showStop(id, settings) {
	if (updater && !live) {

		$('.trip-scheduled').each(function() {
			$(this).text(toCountdown($(this).attr('data-time'), true));

			if ($(this).attr('data-time') > getSecondsSinceMidnight()) return;

			$(this).parent().animate({left: window.innerWidth + 'px'}, 1000, function() {
				$(this).remove();

				$('.trip').each(function() {
					$(this).animate({top: (parseInt($(this).css('top')) - 80) + 'px'}, 500);
				});

			});

		});

		return;
	}

	$.get('//' + location.host + '/getstop?id=' + id).done(function(stop) {
		hideBookmarks();

		var trips   = stop.trips,
			content = '';

		live = stop.live;

		for (var i = 0; i < trips.length; i++) {
			var trip = trips[i];

			if (live) {
				content += '

' + trip.number + '

' + toCountdown(trip.scheduled, false) + '

' + toCountdown(trip.expected, false) + '

';
			} else {
				content += '

' + trip.number + '

' + toCountdown(trip.time, true) + '

' + toTime(trip.time) + '

';
			}

		}
		$('#stop-trips').html(content);

		if (settings.panMap) map.panTo({
			lat: stop.lat,
			lng: stop.lng
		});

		if (!settings.fadeIn) return;

		document.title = 'Bussiaeg - ' + stop.name + (stop.desc ? ' - ' + stop.desc : '');
		history.pushState(null, document.title, '/?stop=' + stop.id);

		$('#stop-name').text(stop.name);
		$('#stop-desc').text(stop.desc);

		$('#stop').fadeIn(fadeTime);
	});

}

function showStops() {

	if (map.getZoom() <= 15) return map.eachLayer(function(layer) {
		if (layer._icon !== undefined) map.removeLayer(layer);
	});

	var bounds = map.getBounds();
	$.get('//' + location.host + '/getstops?lat_min=' + bounds._northEast.lat + '&lng_min=' + bounds._northEast.lng + '&lat_max=' + bounds._southWest.lat + '&lng_max=' + bounds._southWest.lng, function(stops) {

		for (var i = 0; i < stops.length; i++) {

			(function() {
				var stop = stops[i];

				L.marker([stop.lat, stop.lng], {
					icon: L.icon({
						iconUrl: 'assets/stop.png',
						iconSize: [24, 24],
						iconAnchor: [0, 0],
					})
				}).addTo(map).on('click', function() {
					if (updater) return;

					showStop(stop.id, {panMap: false, fadeIn: true});
					updater = setInterval(function() {
						showStop(stop.id, {panMap: false, fadeIn: false});
					}, updateTime);

				});

			})();

		}

	});

}

// Functions (Bookmarks)

function addBookmark() {

	swal({
		type: 'input',
		title: 'Sisesta nimi',
		confirmButtonColor: 'deepskyblue',
		confirmButtonText: 'Lisa',
		showCancelButton: true,
		cancelButtonColor: '#fa5858',
		cancelButtonText: 'Tagasi',
		inputPlaceholder: 'Minu kodu',
		animation: 'slide-from-top'
	}, function(input) {
		var bookmarks = JSON.parse(localStorage.getItem('bookmarks')) || [];

		if (input !== false && $.trim(input) != '') bookmarks.push({
			name: input,
			lat:  map.getCenter().lat,
			lng:  map.getCenter().lng,
			zoom: map.getZoom()
		});

		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));

		hideBookmarks();
	});

}

function deleteBookmark(el) {

	swal({
		title: 'Kustuta?',
		text: el.text(),
		confirmButtonText: 'Jah',
		cancelButtonText: 'Ei',
		showCancelButton: true
	}, function(isConfirm) {
		if (!isConfirm) return;

		var bookmarks = JSON.parse(localStorage.getItem('bookmarks'));

		for (var i = 0; i < bookmarks.length; i++) {
			var bookmark = bookmarks[i];

			if (bookmark.lat != el.data('lat') || bookmark.lng != el.data('lng')) continue;

			bookmarks.splice(i, 1);
			el.remove();

			break;
		}

		localStorage.setItem('bookmarks', JSON.stringify(bookmarks));
	});

}

function showBookmarks() {
	var bookmarks = JSON.parse(localStorage.getItem('bookmarks')) || [];

	var content = '
Lisa asukoht
';
	for (var i = 0; i < bookmarks.length; i++) {
		var bookmark = bookmarks[i];

		content += '
' + bookmark.name + '
';

	}
	$('#bookmarks').html(content);

	$('.bookmark').each(function() {
		$(this).hammer().on('swiperight', function() {
			deleteBookmark($(this));
		});
	});

	$('#bookmarks').animate({left: '0px'}, fadeTime);
}

function hideBookmarks() {
	$('#bookmarks').animate({left: '-240px'}, fadeTime);
}

// Initialization

const share = parseInt(getParameter('stop'));
if (share) if (!isNaN(share)) if (!updater) {

	showStop(share, {panMap: true, fadeIn: true});
	updater = setInterval(function() {
		showStop(share, {panMap: false, fadeIn: false});
	}, updateTime);

}

var map = L.map('map', {
	center: [
		parseFloat(getParameter('lat')) || 59.388,
		parseFloat(getParameter('lng')) || 24.685
	],
	zoom: 16,
	minZoom: 10,
	maxZoom: 18,
	maxBounds: [[59.874204, 21.396935], [57.290822, 28.838625]],
	attributionControl: false,
	bounceAtZoomLimits: false,
	doubleClickZoom: false,
	zoomControl: false,
	keyboard: false,
	boxZoom: false
});

L.tileLayer('//{s}.google.com/vt/lyrs=phl=en&x={x}&y={y}&z={z}&pbhttps://maps.googleapis.com/maps/vt?pb=!1m5!1m4!1i{z}!2i{x}!3i{y}!4i256!2m3!1e0!2sm!3i372053562!3m14!2sen-US!3sUS!5e18!12m1!1e47!12m3!1e37!2m1!1ssmartmaps!12m4!1e26!2m2!1sstyles!2zcy50OjY2fHAudjpvZmY!4e0', {
    subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
}).addTo(map);

L.control.attribution({
	position: 'bottomleft',
	prefix: 'Bussiaeg.ee | Sõiduplaanid | Peatus | Google | Leaflet'
}).addTo(map);

showStops();
map.on('moveend', function() {
	showStops();
});

navigator.geolocation.getCurrentPosition(function(pos) {
	if (pos.coords.accuracy < 250) map.panTo([pos.coords.latitude, pos.coords.longitude]);
});

navigator.geolocation.watchPosition(function(pos) {
	coords = pos.coords;
});

// User Interface (Stops)

$('#stop-top').click(function() {
	clearInterval(updater); updater = null;

	$(this).parent().fadeOut(fadeTime);

	document.title = 'Bussiaeg';
	history.pushState(null, document.title, '/');

});

// User Interface (Bookmarks)

map.on('click dragstart', function() {
	$(this).addClass('bounce');
	hideBookmarks();
});

$('#bookmarks').hammer().on('swipeleft', function() {
	hideBookmarks();
});

$('#btn-bookmarks').click(function() {
	$(this).addClass('bounce');
	showBookmarks();
});

$('#bookmarks').on('click', '#bookmarks-add', function() {
	addBookmark();
});

$('#bookmarks').on('click', '.bookmark', function() {
	hideBookmarks();

	map.panTo([$(this).data('lat'), $(this).data('lng')]);
	map.setZoom($(this).data('zoom'));

});

// User Interface (Help)

$('#btn-help').click(function() {
	$(this).addClass('bounce');

	hideBookmarks();

	$('#help').fadeIn(fadeTime, function() {
		$('#btn-help').removeClass('bounce');
	});

});

$('#help').click(function() {
	$(this).fadeOut(fadeTime);
});

// User Interface (Locate)

$('#btn-locate').click(function() {
	$(this).addClass('bounce');
	if (coords) map.panTo([coords.latitude, coords.longitude]);
});

$('#btn-locate').on('animationend', function() {
	$(this).removeClass('bounce');
});<|endoftext|>


<commit_before>(function () {
  var ns = $.namespace('pskl.tools.transform');

  ns.TransformUtils = {
    VERTICAL : 'VERTICAL',
    HORIZONTAL : 'HORIZONTAL',
    flip : function (frame, axis) {
      var clone = frame.clone();
      var w = frame.getWidth();
      var h = frame.getHeight();

      clone.forEachPixel(function (color, x, y) {
        if (axis === ns.TransformUtils.VERTICAL) {
          x = w - x - 1;
        } else if (axis === ns.TransformUtils.HORIZONTAL) {
          y = h - y - 1;
        }
        frame.setPixel(x, y, color);
      });
      frame.version++;
      return frame;
    },

    CLOCKWISE : 'clockwise',
    COUNTERCLOCKWISE : 'counterclockwise',
    rotate : function (frame, direction) {
      var clone = frame.clone();
      var w = frame.getWidth();
      var h = frame.getHeight();

      var max =  Math.max(w, h);
      var xDelta = Math.ceil((max - w) / 2);
      var yDelta = Math.ceil((max - h) / 2);

      frame.forEachPixel(function (color, x, y) {
        var _x = x;
        var _y = y;

        // Convert to square coords
        x = x + xDelta;
        y = y + yDelta;

        // Perform the rotation
        var tmpX = x;
        var tmpY = y;
        if (direction === ns.TransformUtils.CLOCKWISE) {
          x = tmpY;
          y = max - 1 - tmpX;
        } else if (direction === ns.TransformUtils.COUNTERCLOCKWISE) {
          y = tmpX;
          x = max - 1 - tmpY;
        }

        // Convert the coordinates back to the rectangular grid
        x = x - xDelta;
        y = y - yDelta;
        if (clone.containsPixel(x, y)) {
          frame.setPixel(_x, _y, clone.getPixel(x, y));
        } else {
          frame.setPixel(_x, _y, Constants.TRANSPARENT_COLOR);
        }
      });

      return frame;
    },

    center : function(frame) {
      // Figure out the boundary
      var minx = frame.width;
      var miny = frame.height;
      var maxx = 0;
      var maxy = 0;
      var transparentColorInt = pskl.utils.colorToInt(Constants.TRANSPARENT_COLOR);
      frame.forEachPixel(function (color, x, y) {
        if (color !== transparentColorInt) {
          minx = Math.min(minx, x);
          maxx = Math.max(maxx, x);
          miny = Math.min(miny, y);
          maxy = Math.max(maxy, y);
        }
      });

      // Calculate how much to move the pixels
      var bw = (maxx - minx + 1) / 2;
      var bh = (maxy - miny + 1) / 2;
      var fw = frame.width / 2;
      var fh = frame.height / 2;

      var dx = Math.floor(fw - bw - minx);
      var dy = Math.floor(fh - bh - miny);

      // Actually move the pixels
      var clone = frame.clone();
      frame.forEachPixel(function(color, x, y) {
        var _x = x;
        var _y = y;

        x -= dx;
        y -= dy;

        if (clone.containsPixel(x, y)) {
          frame.setPixel(_x, _y, clone.getPixel(x, y));
        } else {
          frame.setPixel(_x, _y, Constants.TRANSPARENT_COLOR);
        }
      });

      return frame;
    }
  };
})();
<commit_msg>Remove unneccessary frame version incrementing<commit_after>(function () {
  var ns = $.namespace('pskl.tools.transform');

  ns.TransformUtils = {
    VERTICAL : 'VERTICAL',
    HORIZONTAL : 'HORIZONTAL',
    flip : function (frame, axis) {
      var clone = frame.clone();
      var w = frame.getWidth();
      var h = frame.getHeight();

      clone.forEachPixel(function (color, x, y) {
        if (axis === ns.TransformUtils.VERTICAL) {
          x = w - x - 1;
        } else if (axis === ns.TransformUtils.HORIZONTAL) {
          y = h - y - 1;
        }
        frame.setPixel(x, y, color);
      });

      return frame;
    },

    CLOCKWISE : 'clockwise',
    COUNTERCLOCKWISE : 'counterclockwise',
    rotate : function (frame, direction) {
      var clone = frame.clone();
      var w = frame.getWidth();
      var h = frame.getHeight();

      var max =  Math.max(w, h);
      var xDelta = Math.ceil((max - w) / 2);
      var yDelta = Math.ceil((max - h) / 2);

      frame.forEachPixel(function (color, x, y) {
        var _x = x;
        var _y = y;

        // Convert to square coords
        x = x + xDelta;
        y = y + yDelta;

        // Perform the rotation
        var tmpX = x;
        var tmpY = y;
        if (direction === ns.TransformUtils.CLOCKWISE) {
          x = tmpY;
          y = max - 1 - tmpX;
        } else if (direction === ns.TransformUtils.COUNTERCLOCKWISE) {
          y = tmpX;
          x = max - 1 - tmpY;
        }

        // Convert the coordinates back to the rectangular grid
        x = x - xDelta;
        y = y - yDelta;
        if (clone.containsPixel(x, y)) {
          frame.setPixel(_x, _y, clone.getPixel(x, y));
        } else {
          frame.setPixel(_x, _y, Constants.TRANSPARENT_COLOR);
        }
      });

      return frame;
    },

    center : function(frame) {
      // Figure out the boundary
      var minx = frame.width;
      var miny = frame.height;
      var maxx = 0;
      var maxy = 0;
      var transparentColorInt = pskl.utils.colorToInt(Constants.TRANSPARENT_COLOR);
      frame.forEachPixel(function (color, x, y) {
        if (color !== transparentColorInt) {
          minx = Math.min(minx, x);
          maxx = Math.max(maxx, x);
          miny = Math.min(miny, y);
          maxy = Math.max(maxy, y);
        }
      });

      // Calculate how much to move the pixels
      var bw = (maxx - minx + 1) / 2;
      var bh = (maxy - miny + 1) / 2;
      var fw = frame.width / 2;
      var fh = frame.height / 2;

      var dx = Math.floor(fw - bw - minx);
      var dy = Math.floor(fh - bh - miny);

      // Actually move the pixels
      var clone = frame.clone();
      frame.forEachPixel(function(color, x, y) {
        var _x = x;
        var _y = y;

        x -= dx;
        y -= dy;

        if (clone.containsPixel(x, y)) {
          frame.setPixel(_x, _y, clone.getPixel(x, y));
        } else {
          frame.setPixel(_x, _y, Constants.TRANSPARENT_COLOR);
        }
      });

      return frame;
    }
  };
})();
<|endoftext|>


<commit_before>define(function(require){
	var $ = require('jquery')
		, is_touch_device = require('utils/is_touch');

	/*
	 * takes care of click events
	 *
	 * accepts a listener object to decorate and definitions
	 *
	 * the function accepts either
	 *		a stimulus handle to which to bind the event (definitions.stimHandle)
	 *		or an element to add to the canvas definitions.element (optionaly a jquery css object may be added: definitions.css)
	 *
	 * -- if we want to attach the event to an existing element
	 * definitions = {
	 *		stimHandle: 'firstStim'
	 * }
	 * This attaches to the [data-handle="firstStim"] stimulus.
	 *
	 * -- if we want to create a interface specific element
	 * definitions = {
	 *		element: $('<div>'),
	 *		css: {background:red; 'font-size': 2em'}   // optional
	 * }
	 */

	return function(listener,definitions){
		var eventName = (is_touch_device ? 'touchstart' : 'mousedown') + '.interface';
		var $element = definitions.element ? $(definitions.element) : false;

		listener.on = function(callback){
			function activateCallback(e){ callback(e,eventName); }
			this.activateCallback = activateCallback;

			// If we're binding to an existing element, bind to its appropriate handle
			if (!$element){
				$(document).on(eventName,'[data-handle="'+definitions.stimHandle + '"]', activateCallback);
			} else {
				// the element to attach
				$element
					.css(definitions.css || {})
					.appendTo('#canvas')							// @todo, not great form, we should probably have a variable pointing there...
					.on(eventName,activateCallback);
			}
		};

		listener.off = function(){
			if ($element){
				$element.remove();									// this also removes any attached events
			} else {
				$(document).on(eventName,'[data-handle="'+definitions.stimHandle + '"]', this.activateCallback);
			}
		};
	};
});<commit_msg>fix(input): fixed memory leak where click handlers were not removed<commit_after>define(function(require){
	var $ = require('jquery')
		, is_touch_device = require('utils/is_touch');

	/*
	 * takes care of click events
	 *
	 * accepts a listener object to decorate and definitions
	 *
	 * the function accepts either
	 *		a stimulus handle to which to bind the event (definitions.stimHandle)
	 *		or an element to add to the canvas definitions.element (optionaly a jquery css object may be added: definitions.css)
	 *
	 * -- if we want to attach the event to an existing element
	 * definitions = {
	 *		stimHandle: 'firstStim'
	 * }
	 * This attaches to the [data-handle="firstStim"] stimulus.
	 *
	 * -- if we want to create a interface specific element
	 * definitions = {
	 *		element: $('<div>'),
	 *		css: {background:red; 'font-size': 2em'}   // optional
	 * }
	 */

	return function(listener,definitions){
		var eventName = (is_touch_device ? 'touchstart' : 'mousedown') + '.interface';
		var $element = definitions.element ? $(definitions.element) : false;

		listener.on = function(callback){
			function activateCallback(e){ callback(e,eventName); }
			this.activateCallback = activateCallback;

			// If we're binding to an existing element, bind to its appropriate handle
			if (!$element){
				$(document).on(eventName,'[data-handle="'+definitions.stimHandle + '"]', activateCallback);
			} else {
				// the element to attach
				$element
					.css(definitions.css || {})
					.appendTo('#canvas')							// @todo, not great form, we should probably have a variable pointing there...
					.on(eventName,activateCallback);
			}
		};

		listener.off = function(){
			if ($element){
				$element.remove();									// this also removes any attached events
			} else {
				$(document).off(eventName,'[data-handle="'+definitions.stimHandle + '"]', this.activateCallback);
			}
		};
	};
});<|endoftext|>