<commit_before>/**
 * Created by Administrator on 2015/6/7 0007.
 */

var app = (function(){

    function init(){
        $('body').on('click' , 'a.option' , function(){
            var m = $(this).attr('rel');
            var target = $(this).attr('data-for');
            var pre = '←×';
            var h = "
" + pre + $('#t-'+m).html() + "
";
            if(target.charAt(0) !="#"){
                $(this).parent().nextAll('.' + target).append(h);
            }else
                $( target).append(h);
        })

        $('body').on('click' , 'span.remove' , function(){
            $(this).parent().remove();
        })
        $('body').on('click' , 'span.left' , function(){
            var p = $(this).parent();
            var el = p.prev();
            if(el.length) el.before(p);
            //$(this).parent().remove();
        })

        $('body').on('click' , 'span.right' , function(){
            var p = $(this).parent();
            var el = p.next();
            if(el.length) el.after(p);
            //$(this).parent().remove();
        })
        $('#j-calc').on('click' , function(){
            if($(this).attr('rel') == 'calc') calc();
            if($(this).attr('rel') == 'analyse') analyse();

        })

        $('body').on('click' , '.checkbox a' , function(){
            $(this).toggleClass('select');
        })

    }

    /**
     * 链接查询字串
     * @returns {string}
     */
    function join(con , sp){
        con = con || $('#j-condition li');
        var sql = [];
        for(var i=0;i<con.length ; i++){
            var el = $(con[i]).find('select,input,textarea');
            var seg = "";
            for(var j = 0 ;j<el.length ; j++){
                if(el[j].tagName == 'A')
                    seg += $(el[j]).attr('data-value');
                else
                    seg += $(el[j]).val().replace("\n"," ");
            }
            sql.push(seg);
        }
        sp = sp || " ";
        return sql.join(sp);
    }

    function joinkey(el , fn , args , tonumber){
        if(!fn) fn = "val";
        var arr = [];
        for(var i=0;i<el.length;i++){
            if(el[i].tagName == 'A')
                arr[i] = $(el[i]).attr('data-value');
            else
                arr[i] = $(el[i])[fn]();
            if(tonumber){arr[i] = parseFloat(arr[i]);}
        }
        return arr;
    }

    function calc(){
        var sql = [], bet = [],res = [];

        var el = $("#j-model>li");

        for(var i=0;i<el.length ; i++){
            sql.push( join( $(el[i]).find('.j-condition li') ) );
            bet.push( join( $(el[i]).find('.j-bet') ) );
            res.push(joinkey( $(el[i]).find('.j-bet .checkbox a.select')).join(''));
        }

        console.log(sql);
        console.log(bet);
        console.log(res);
        //return;

        ui.loading();
        $.getJSON('../api/?m=model&a=calc',{
            'where':JSON.stringify(sql),
            'bet':JSON.stringify(bet),
            'result':JSON.stringify(res)
        },function(d){
            d = d.detail;
            console.log(d);
            var ret = 0, ret_all = 0, num = 0;
            var count = d[0].count;
            for(var i in d){
                ret += d[i].r;
                ret_all += d[i].r * count;
            }
            $('#j-return').html(ret);
            $('#j-return-all').html(ret_all);
            $('#j-num').html(d[0].count+"("+ (d[0].p*100).toFixed(2) +"%)");
            ui.loading(null);
        })

    }

    /**
     * 统计 绘制图形
     * @param d：分布数组
     * @param a：类型数字
     */
    function draw(d , a){
        var al = coll(d.data , a);

        $('#j-result').empty();

        for(var i in al){
            //console.log(al[i]);
            var obj = {
                chart: { type: 'area' , zoomType:"x" },
                title: { text: '概率分布' },
                yAxis: {
                    title: { text: '概率分布(%)' }
                },
                //tooltip: { formatter:function(){ return this.y +'% 概率 出现 '+ this.x.toFixed(2);} },
                plotOptions: {
                    area: {
                        /*pointStart: 0,*/pointInterval:0.1,
                        marker: {
                            enabled: false,
                            symbol: 'circle',
                            radius: 1,
                            states: {
                                hover: {
                                    enabled: true
                                }
                            }
                        }
                    }
                },
                series: al[i]
            }
            var a = $('
');
            $('#j-result').append(a);
            a.highcharts(obj);
        }

    }

    /**
     * 原始数据转换
     * @param data
     * @param order
     * @returns {Array}
     */
    function coll(data , order){
        var yas = [], count;
        var l = order.length;
        for(var j =0 ;j<l ; j++){
            var d = data[j];
            var ya = [];
            var ya_h = [];
            var ya_a = [];
            var ya_d = [];
            var count = 0, count_a = 0,count_h = 0,count_d = 0 ;
            for(var i in d){
                var cur = parseInt(d[i].c);
                var cur_h = parseInt(d[i].h);
                var cur_a = parseInt(d[i].a);
                var cur_d = parseInt(d[i].d);

                // 累加所有
                count += cur;

                if(d[i].v != 'null' && d[i].v != null){

                    var v = parseFloat(parseFloat(d[i].v).toFixed(1)) * 10;
                    if(v > 99) v = 99;

                    if(ya[v] === undefined) ya[v] = 0;
                    if(ya_h[v] === undefined) ya_h[v] = 0;
                    if(ya_a[v] === undefined) ya_a[v] = 0;
                    if(ya_d[v] === undefined) ya_d[v] = 0;

                    ya[v] += cur;
                    ya_h[v] += cur_h;
                    ya_a[v] += cur_a;
                    ya_d[v] += cur_d;
                }

            }
            for(var i=0;i<100;i++){
                if(ya[i] === undefined) ya[i] = 0;
                else ya[i] = Math.round((100 * ya[i] / count)*100)/100;

                if(ya_a[i] === undefined) ya_a[i] = 0;
                else ya_a[i] = Math.round((100 * ya_a[i] / count)*100)/100;

                if(ya_h[i] === undefined) ya_h[i] = 0;
                else ya_h[i] = Math.round((100 * ya_h[i] / count)*100)/100;

                if(ya_d[i] === undefined) ya_d[i] = 0;
                else ya_d[i] = Math.round((100 * ya_d[i] / count)*100)/100;
            }
            yas[j] = [
                {"name":order[j] , "data":ya},
                {"name":'胜比' , "data":ya_h},
                {"name":'平比' , "data":ya_d},
                {"name":'负比' , "data":ya_a}
            ];

        }

        return yas;
    }

    function analyse(){
        var sql = join( $('.j-condition li') );
        var order = join( $('#j-order li')).split(" ");

        console.log(JSON.stringify(order))
        ui.loading();
        $.getJSON('../api/?m=model&a=get',{
            'where':sql,
            'order':JSON.stringify(order)
        },function(d){
            //$('#j-result').html( JSON.stringify(d) );
            //console.log(d)
            ui.loading(null);

            if(d.status == 0){
                draw(d.detail , order);
            }
        })
    }

    return {
        'init':init,
        'calc':calc,
        'analyse':analyse
    }
}());<commit_msg>update<commit_after>/**
 * Created by Administrator on 2015/6/7 0007.
 */

var app = (function(){

    function init(){
        $('body').on('click' , 'a.option' , function(){
            var m = $(this).attr('rel');
            var target = $(this).attr('data-for');
            var pre = '←×';
            var h = "
" + pre + $('#t-'+m).html() + "
";
            if(target.charAt(0) !="#"){
                $(this).parent().nextAll('.' + target).append(h);
            }else
                $( target).append(h);
        })

        $('body').on('click' , 'span.remove' , function(){
            $(this).parent().remove();
        })
        $('body').on('click' , 'span.left' , function(){
            var p = $(this).parent();
            var el = p.prev();
            if(el.length) el.before(p);
            //$(this).parent().remove();
        })

        $('body').on('click' , 'span.right' , function(){
            var p = $(this).parent();
            var el = p.next();
            if(el.length) el.after(p);
            //$(this).parent().remove();
        })
        $('#j-calc').on('click' , function(){
            if($(this).attr('rel') == 'calc') calc();
            if($(this).attr('rel') == 'analyse') analyse();

        })

        $('body').on('click' , '.checkbox a' , function(){
            $(this).toggleClass('select');
        })

    }

    /**
     * 链接查询字串
     * @returns {string}
     */
    function join(con , sp){
        con = con || $('#j-condition li');
        var sql = [];
        for(var i=0;i<con.length ; i++){
            var el = $(con[i]).find('select,input,textarea');
            var seg = "";
            for(var j = 0 ;j<el.length ; j++){
                if(el[j].tagName == 'A')
                    seg += $(el[j]).attr('data-value');
                else
                    seg += $(el[j]).val().replace("\n"," ");
            }
            sql.push(seg);
        }
        sp = sp || " ";
        return sql.join(sp);
    }

    function joinkey(el , fn , args , tonumber){
        if(!fn) fn = "val";
        var arr = [];
        for(var i=0;i<el.length;i++){
            if(el[i].tagName == 'A')
                arr[i] = $(el[i]).attr('data-value');
            else
                arr[i] = $(el[i])[fn]();
            if(tonumber){arr[i] = parseFloat(arr[i]);}
        }
        return arr;
    }

    function calc(){
        var sql = [], bet = [],res = [];

        var el = $("#j-model>li");

        for(var i=0;i<el.length ; i++){
            sql.push( join( $(el[i]).find('.j-condition li') ) );
            bet.push( join( $(el[i]).find('.j-bet') ) );
            res.push(joinkey( $(el[i]).find('.j-bet .checkbox a.select')).join(''));
        }

        console.log(sql);
        console.log(bet);
        console.log(res);
        //return;

        ui.loading();
        $.getJSON('../api/?m=model&a=calc',{
            'where':JSON.stringify(sql),
            'bet':JSON.stringify(bet),
            'result':JSON.stringify(res)
        },function(d){
            d = d.detail;
            console.log(d);
            var ret = 0, ret_all = 0, num = 0;
            var count = d[0].count;
            for(var i in d){
                ret += d[i].r;
                ret_all += d[i].r * count;
            }
            $('#j-return').html(ret);
            $('#j-return-all').html(ret_all);
            $('#j-num').html(d[0].count+"("+ (d[0].p*100).toFixed(2) +"%)");
            ui.loading(null);
        })

    }

    /**
     * 统计 绘制图形
     * @param d：分布数组
     * @param a：类型数字
     */
    function draw(d , a){
        var al = coll(d.data , a);

        $('#j-result').empty();

        for(var i in al){
            //console.log(al[i]);
            var obj = {
                chart: { type: 'area' , zoomType:"x" },
                title: { text: '概率分布' },
                yAxis: [{
                            labels: {
                                formatter: function () {
                                    return this.value + '%';
                                }
                            },
                            title: {
                                text: '概率分布(%)'

                            }
                    },
                    { // Primary yAxis
                    labels: {
                        formatter: function () {
                            return this.value + '%';
                        },
                        style: {
                            color: '#89A54E'
                        }
                    },
                    title: {
                        text: '成功率',
                        style: {
                            color: '#89A54E'
                        }
                    },
                    opposite: true
                }
                ],
                //tooltip: { formatter:function(){ return this.y +'% 概率 出现 '+ this.x.toFixed(2);} },
                plotOptions: {
                    area: {
                        /*pointStart: 0,*/pointInterval:0.1,
                        marker: {
                            enabled: false,
                            symbol: 'circle',
                            radius: 1,
                            states: {
                                hover: {
                                    enabled: true
                                }
                            }
                        }
                    },
                    line:{
                        pointInterval:0.1
                    }
                },
                series: al[i]
            }
            var a = $('
');
            $('#j-result').append(a);
            a.highcharts(obj);
        }

    }

    /**
     * 原始数据转换
     * @param data
     * @param order
     * @returns {Array}
     */
    function coll(data , order){
        var yas = [], count;
        var l = order.length;
        for(var j =0 ;j<l ; j++){
            var d = data[j];
            var ya = [];
            var ya_h = [];
            var ya_a = [];
            var ya_d = [];
            var count = 0, count_a = 0,count_h = 0,count_d = 0 ;
            for(var i in d){
                var cur = parseInt(d[i].c);
                var cur_h = parseInt(d[i].h);
                var cur_a = parseInt(d[i].a);
                var cur_d = parseInt(d[i].d);

                // 累加所有
                count += cur;

                if(d[i].v != 'null' && d[i].v != null){

                    var v = parseFloat(parseFloat(d[i].v).toFixed(1)) * 10;
                    if(v > 99) v = 99;

                    if(ya[v] === undefined) ya[v] = 0;
                    if(ya_h[v] === undefined) ya_h[v] = 0;
                    if(ya_a[v] === undefined) ya_a[v] = 0;
                    if(ya_d[v] === undefined) ya_d[v] = 0;

                    ya[v] += cur;
                    ya_h[v] += cur_h;
                    ya_a[v] += cur_a;
                    ya_d[v] += cur_d;
                }

            }
            for(var i=0;i<100;i++){
                if(ya[i] === undefined) ya[i] = 0;
                else ya[i] = Math.round((100 * ya[i] / count)*100)/100;

                if(ya_a[i] === undefined || ya[i] == 0) ya_a[i] = 0;
                else ya_a[i] = Math.round((100 * ya_a[i] / count)*100)/100;

                if(ya_h[i] === undefined || ya[i] == 0) ya_h[i] = 0;
                else ya_h[i] = Math.round((100 * ya_h[i] / count)*100)/100;

                if(ya_d[i] === undefined || ya[i] == 0) ya_d[i] = 0;
                else ya_d[i] = Math.round((100 * ya_d[i] / count)*100)/100;
            }
            yas[j] = [
                {"name":order[j] , "data":ya},
                {"name":'胜比' ,/*yAxis: 0,type: 'line',*/ min:0,"data":ya_h},
                {"name":'平比' ,/*yAxis: 0,type: 'line',min:0,*/ "data":ya_d},
                {"name":'负比' ,/*yAxis: 0,type: 'line', min:0,*/"data":ya_a}
            ];

        }

        return yas;
    }

    function analyse(){
        var sql = join( $('.j-condition li') );
        var order = join( $('#j-order li')).split(" ");

        console.log(JSON.stringify(order))
        ui.loading();
        $.getJSON('../api/?m=model&a=get',{
            'where':sql,
            'order':JSON.stringify(order)
        },function(d){
            //$('#j-result').html( JSON.stringify(d) );
            //console.log(d)
            ui.loading(null);

            if(d.status == 0){
                draw(d.detail , order);
            }
        })
    }

    return {
        'init':init,
        'calc':calc,
        'analyse':analyse
    }
}());<|endoftext|>


<commit_before>/*global Zepto, setTimeout*/
(function ($) {
    /**
     * Cubic Bezier CSS3 transitions emulator
     *
     * See this post for more details
     * http://st-on-it.blogspot.com/2011/05/calculating-cubic-bezier-function.html
     *
     * Copyright (C) 2011 Nikolay Nemshilov
     */
    function bezier(p1, p2, p3, p4) {
        // defining the bezier functions in the polynomial form
        var Cx = 3 * p1,
            Bx = 3 * (p3 - p1) - Cx,
            Ax = 1 - Cx - Bx,
            Cy = 3 * p2,
            By = 3 * (p4 - p2) - Cy,
            Ay = 1 - Cy - By;

        function bezier_x(t) {
            return t * (Cx + t * (Bx + t * Ax));
        }
        function bezier_y(t) {
            return t * (Cy + t * (By + t * Ay));
        }

        // using Newton's method to aproximate the parametric value of x for t
        function bezier_x_der(t) {
            return Cx + t * (2 * Bx + 3 * Ax * t);
        }

        function find_x_for(t) {
            var x = t,
                i = 0, z;

            while (i < 5) { // making 5 iterations max
                z = bezier_x(x) - t;
                if (Math.abs(z) < 1e-3) {
                    break; // if already got close enough
                }
                x = x - z / bezier_x_der(x);
                i += 1;
            }
            return x;
        }

        function ret(t) {
            return bezier_y(find_x_for(t));
        }
        ret.toCSS = function () {
            return "cubic-bezier(" + [p1, p2, p3, p4].join(", ") + ")";
        };
        return ret;
    }

    // Given that the user is moving the slides at a given velocity,
    // what should the bezier curve animation look like?
    //
    // In order for the user not to notice the transition to the bezier,
    // it's important that we don't move the slide; or change its velocity.
    //
    // Luckily CSS enforces the former for us, by setting the initial point
    // of a cubic to (0, 0). The latter is not hard to ensure either, as we
    // know that a bezier curve at the origin is tangent to the line between
    // its first two control points. Thus, we just have to ensure that the
    // control point lies on the line where velocity = v (or x/t = v).
    //
    // The only decision we have with regards to that control point is how
    // far from the origin it should be; this is basically a number we can
    // make up to adjust the user experience, I've called it "i" as it
    // represents how important the user's initial velocity is to the shape
    // of the final curve.
    //
    //    /|       given: x² + t² = i²
    // i / |       given: x / t = v
    //  /  | x     => x = sqrt(i² * v²/(1 + v²))
    // ,___|
    //   t
    //
    // As we want the animation to finish at the end with 0 velocity, we
    // are forced to put the second intermediate control point with an x
    // coordinate of 1 (the final control point is at (1, 1) by definition),
    // so the only other choice we have for the shape of our curve is how
    // far along the t axis to put the second control point.
    //
    // At the moment I'm using 't' for that, because it seems to result in
    // consistently smooth-feeling curves; but it's just an arbitrary choice.
    function bezier_for_velocity(v) {
        var importance = 0.5,
            x = Math.sqrt(importance * importance * (v * v / (1 + v * v))),
            t = x / v,
            sameness = t;

        return bezier(t, x, sameness, 1.0);
    }

    $.fn.ipadSlider = function (options) {
        var x, t, initial_x,
            previous_x, previous_t,
            $this = this,
            initial_t, initial_slide,
            current_offset = 0, initial_offset,
            target_offset = 0,
            animation_start, animation_duration, animation_timing_function,
            slide_width = options.slide_width, last_slide = options.n_slides - 1,
            left_edge = 0,
            right_edge = slide_width * last_slide;

        this.bind('touchstart', function (e) {
            if (e.touches.length !== 1) {
                return;
            }

            // Allow the user to interrupt our animation.
            var t = new Date() - animation_start;
            if (animation_start && t < animation_duration) {
                current_offset += animation_timing_function(t / animation_duration) * (target_offset - current_offset);
            } else {
                current_offset = target_offset;
            }

            $this.css({
                // Remove the delay on animation for instant finger feedback
                '-webkit-transition-duration': '0s',
                '-webkit-transform': 'translate3D(' + (0 - current_offset) + 'px, 0, 0)'
            });

            initial_offset = current_offset;
            initial_slide = Math.floor(target_offset / slide_width);
            initial_x = previous_x = x = e.touches[0].clientX;
            initial_t = previous_t = t = new Date();

        }).on('touchmove', function (e) {

            if (e.touches.length !== 1) {
                return;
            } else {
                e.preventDefault();
            }

            previous_x = x;
            previous_t = t;
            x = e.touches[0].clientX;
            t = new Date();

            current_offset = initial_offset + (initial_x - x);

            // iOS-like halved velocity when dragging beyond the edge
            if (current_offset < left_edge) {
                current_offset = current_offset / 2;
            } else if (current_offset > right_edge) {
                current_offset = right_edge + (current_offset - right_edge) / 2;
            }

            $this.css({
                '-webkit-transform': 'translate3D(' + (0 - current_offset) + 'px, 0, 0)'
            });

        }).on('touchend', function (e) {

            var target_slide, target_distance, velocity;

            // Was the user dragging this thing around speculatively?
            if (t - initial_t > 250) {
                target_slide = Math.round(current_offset / slide_width);

            // If not, which way did they flick?
            // Leave a bit of freedom so a downward flick does nothing.
            } else if (Math.abs(initial_x - x) < 20) {
                target_slide = initial_slide;
            } else if (x > initial_x) {
                target_slide = initial_slide - 1;
            } else {
                target_slide = initial_slide + 1;
            }

            if (target_slide < 0) {
                target_slide = 0;
            } else if (target_slide > last_slide) {
                target_slide = last_slide;
            }

            target_distance = target_slide * slide_width - current_offset;

            // avoid division by zero
            if (Math.abs(x - previous_x) < 1 || Math.abs(t - previous_t) < 1) {
                velocity = 0.1;
            } else {
                velocity = ((x - previous_x) / (t - previous_t));
            }

            $this.trigger('slideTo', {slide: target_slide, bezier: bezier_for_velocity(velocity)});
        }).on('slideTo', function (e, opts) {
            target_offset = opts.slide * slide_width;

            // NOTE: 0.01s > 0s, if we set it to 0 then the transition doesn't happen
            // if the first time the thing is shown is with animate:false.
            animation_duration = (opts.animate === false ? 1 : 500);
            animation_start = new Date();
            animation_timing_function = opts.bezier || bezier_for_velocity(0.1);

            $this.css({
                '-webkit-transition-timing-function': animation_timing_function.toCSS(),
                '-webkit-transition-duration': animation_duration + 'ms',
                '-webkit-transform': 'translate3D(' + (0 - target_offset) + 'px, 0, 0)'
            });

            $this.trigger('slidingTo', opts.slide);
            setTimeout(function () {
                $this.trigger('slidTo', opts.slide);
            }, 500);

        });
        return this;
    };
}(Zepto));
<commit_msg>Make jquery compatible<commit_after>/*global window*/
(function ($) {
    /**
     * Cubic Bezier CSS3 transitions emulator
     *
     * See this post for more details
     * http://st-on-it.blogspot.com/2011/05/calculating-cubic-bezier-function.html
     *
     * Copyright (C) 2011 Nikolay Nemshilov
     */
    function bezier(p1, p2, p3, p4) {
        // defining the bezier functions in the polynomial form
        var Cx = 3 * p1,
            Bx = 3 * (p3 - p1) - Cx,
            Ax = 1 - Cx - Bx,
            Cy = 3 * p2,
            By = 3 * (p4 - p2) - Cy,
            Ay = 1 - Cy - By;

        function bezier_x(t) {
            return t * (Cx + t * (Bx + t * Ax));
        }
        function bezier_y(t) {
            return t * (Cy + t * (By + t * Ay));
        }

        function bezier_x_der(t) {
            return Cx + t * (2 * Bx + 3 * Ax * t);
        }

        // using Newton's method to aproximate the parametric value of x for t
        function find_x_for(t) {
            var x = t,
                i = 0, z;

            while (i < 5) { // making 5 iterations max
                z = bezier_x(x) - t;
                if (Math.abs(z) < 1e-3) {
                    break; // if already got close enough
                }
                x = x - z / bezier_x_der(x);
                i += 1;
            }
            return x;
        }

        function ret(t) {
            return bezier_y(find_x_for(t));
        }
        ret.toCSS = function () {
            return "cubic-bezier(" + [p1, p2, p3, p4].join(", ") + ")";
        };
        return ret;
    }

    // Given that the user is moving the slides at a given velocity,
    // what should the bezier curve animation look like?
    //
    // In order for the user not to notice the transition to the bezier,
    // it's important that we don't move the slide; or change its velocity.
    //
    // Luckily CSS enforces the former for us, by setting the initial point
    // of a cubic to (0, 0). The latter is not hard to ensure either, as we
    // know that a bezier curve at the origin is tangent to the line between
    // its first two control points. Thus, we just have to ensure that the
    // control point lies on the line where velocity = v (or x/t = v).
    //
    // The only decision we have with regards to that control point is how
    // far from the origin it should be; this is basically a number we can
    // make up to adjust the user experience, I've called it "i" as it
    // represents how important the user's initial velocity is to the shape
    // of the final curve.
    //
    //    /|       given: x² + t² = i²
    // i / |       given: x / t = v
    //  /  | x     => x = sqrt(i² * v²/(1 + v²))
    // ,___|
    //   t
    //
    // As we want the animation to finish at the end with 0 velocity, we
    // are forced to put the second intermediate control point with an x
    // coordinate of 1 (the final control point is at (1, 1) by definition),
    // so the only other choice we have for the shape of our curve is how
    // far along the t axis to put the second control point.
    //
    // At the moment I'm using 't' for that, because it seems to result in
    // consistently smooth-feeling curves; but it's just an arbitrary choice.
    function bezier_for_velocity(v) {
        var importance = 0.5,
            x = Math.sqrt(importance * importance * (v * v / (1 + v * v))),
            t = x / v,
            sameness = t;

        return bezier(t, x, sameness, 1.0);
    }

    $.fn.touchSlider = function (options) {
        var x, t, initial_x,
            previous_x, previous_t,
            $this = this,
            initial_t, initial_slide,
            current_offset = 0, initial_offset,
            target_offset = 0,
            animation_start, animation_duration, animation_timing_function,
            slide_width = options.slide_width, last_slide = options.n_slides - 1,
            left_edge = 0,
            right_edge = slide_width * last_slide;

        this.bind('touchstart', function (e) {
            e = e.originalEvent || e;

            if (e.touches.length !== 1) {
                return;
            }

            // Allow the user to interrupt our animation.
            var t = new Date() - animation_start;
            if (animation_start && t < animation_duration) {
                current_offset += animation_timing_function(t / animation_duration) * (target_offset - current_offset);
            } else {
                current_offset = target_offset;
            }

            $this.css({
                // Remove the delay on animation for instant finger feedback
                '-webkit-transition-duration': '0s',
                '-webkit-transform': 'translate3D(' + (0 - current_offset) + 'px, 0, 0)'
            });

            initial_offset = current_offset;
            initial_slide = Math.floor(target_offset / slide_width);
            initial_x = previous_x = x = e.touches[0].clientX;
            initial_t = previous_t = t = new Date();

        }).on('touchmove', function (e) {
            e = e.originalEvent || e;

            if (e.touches.length !== 1) {
                return;
            } else {
                e.preventDefault();
            }

            previous_x = x;
            previous_t = t;
            x = e.touches[0].clientX;
            t = new Date();

            current_offset = initial_offset + (initial_x - x);

            // iOS-like halved velocity when dragging beyond the edge
            if (current_offset < left_edge) {
                current_offset = current_offset / 2;
            } else if (current_offset > right_edge) {
                current_offset = right_edge + (current_offset - right_edge) / 2;
            }

            $this.css({
                '-webkit-transform': 'translate3D(' + (0 - current_offset) + 'px, 0, 0)'
            });

        }).on('touchend', function (e) {
            var target_slide, target_distance, velocity;

            // Was the user dragging this thing around speculatively?
            if (t - initial_t > 250) {
                target_slide = Math.round(current_offset / slide_width);

            // If not, which way did they flick?
            // Leave a bit of freedom so a downward flick does nothing.
            } else if (Math.abs(initial_x - x) < 20) {
                target_slide = initial_slide;
            } else if (x > initial_x) {
                target_slide = initial_slide - 1;
            } else {
                target_slide = initial_slide + 1;
            }

            if (target_slide < 0) {
                target_slide = 0;
            } else if (target_slide > last_slide) {
                target_slide = last_slide;
            }

            target_distance = target_slide * slide_width - current_offset;

            // avoid division by zero
            if (Math.abs(x - previous_x) < 1 || Math.abs(t - previous_t) < 1) {
                velocity = 0.1;
            } else {
                velocity = ((x - previous_x) / (t - previous_t));
            }

            $this.trigger('slideTo', {slide: target_slide, bezier: bezier_for_velocity(velocity)});

        }).on('slideTo', function (e, opts) {
            target_offset = opts.slide * slide_width;

            // NOTE: 0.01s > 0s, if we set it to 0 then the transition doesn't happen
            // if the first time the thing is shown is with animate:false.
            animation_duration = (opts.animate === false ? 1 : 500);
            animation_start = new Date();
            animation_timing_function = opts.bezier || bezier_for_velocity(0.1);

            $this.css({
                '-webkit-transition-timing-function': animation_timing_function.toCSS(),
                '-webkit-transition-duration': animation_duration + 'ms',
                '-webkit-transform': 'translate3D(' + (0 - target_offset) + 'px, 0, 0)'
            });

            $this.trigger('slidingTo', opts.slide);
            window.setTimeout(function () {
                $this.trigger('slidTo', opts.slide);
            }, animation_duration);

        });
        return this;
    };
}(window.jQuery || window.Zepto));
<|endoftext|>


<commit_before>// TODO:
// Record id when creating a new annotation.
// Finish polyline "NewAnnotationItem"
// Load annotation into layer when circle is clicked on.
// Right click menu to "delete, modify (record over), set name.
// Hover over circle to see annotation name.
// Finish remaining annotation items.
// Add camera view as annotation.

(function () {
    "use strict";

    function GirderWidget (layer, itemId) {
        if (itemId) {
            this.ImageItemId  = itemId;
            this.LoadGirderImageItem();
        }
        this.Radius = 7;
        this.AnnotationLayer = layer;

        var idx = 0;
        var y = 70 + (idx*6*this.Radius);
        var self = this;
        this.Plus = $('<img>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .attr('src',"/webgl-viewer/static/"+"bluePlus.png")
            .css({'position':'absolute',
                  'left':(3*this.Radius)+'px',
                  'top': y+'px',
                  'width': (2*this.Radius)+'px',
                  'height': (2*this.Radius)+'px',
                  'opacity':'0.6'})
            .prop('title', "Add Annotation")
            .hover(function(){$(this).css({'opacity':'1'});},
                   function(){$(this).css({'opacity':'0.6'});})
            .click(function () { self.NewAnnotationItem();});

        this.AnnotationObjects = [];
        this.Highlighted = undefined;

        this.MenuAnnotationObject = undefined;
        this.Menu = $('<div>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .hide()
            .mouseleave(function(){$(this).hide();})
            .css({'position'  :'absolute',
                  'background-color': '#FFFFFF',
                  'border'    :'1px solid #666666',
                  'box-sizing': 'border-box',
                  'left'      : '-78px',
                  'width'     : '100px',
                  'padding'   : '0px 2px'})

        $('<button>')
            .appendTo(this.Menu)
            .text("Snap Shot")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .prop('title', "Replace Annotation")
            .click(
                function(){
                    self.SnapShotAnnotation(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
        $('<button>')
            .appendTo(this.Menu)
            .text("Delete")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .click(
                function(){
                    self.DeleteAnnotation(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
        $('<button>')
            .appendTo(this.Menu)
            .text("Properties")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .click(
                function(){
                    // Not implemented yet.
                    //self.ShowAnnotationPropertiesDialog(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
    }

    // Create a new annotation item from the annotation layer.
    // Save it in the database.  Add the annotation as a dot in the GUI.
    GirderWidget.prototype.NewAnnotationItem = function(itemId) {
        var annot = {"elements": []};
        annot.name = "SA-"+this.AnnotationObjects.length;
        annot.elements = this.RecordAnnotation();

        // Make a new annotation in the database.
        var self = this;
        if (window.girder) { // Conditional is for testing in slide atlas.
            girder.restRequest({
                path:  "annotation?itemId="+this.ImageItemId,
                method: 'POST',
                contentType:'application/json',
                data: JSON.stringify(annot),
            }).done(function(retAnnot) {
                // This has the girder id.
                self.Highlight(self.AddAnnotation(retAnnot));
            });
        } else {
            // for debugging without girder.
            self.Highlight(self.AddAnnotation(annot));
        }
    }

    GirderWidget.prototype.LoadGirderImageItem = function(itemId) {
        //var itemId = "564e42fe3f24e538e9a20eb9";
        var data= {"itemId": itemId,
                   "limit": 50,
                   "offset": 0,
                   "sort":"lowerName",
                   "sortdir":1};

        var self = this;
        // This gives an array of {_id:"....",annotation:{name:"...."},itemId:"...."}
        girder.restRequest({
            type: "get",
            url:  "annotation",
            data: JSON.stringify(data)
        }).done(function(data) {
            for (var i = 0; i < data.length; ++i) {
                self.LoadAnnotationItem(data._id);
            }
        });
    }

    GirderWidget.prototype.LoadAnnotationItem = function(annotId) {
        //var annotId = "572be29d3f24e53573aa8e91";
        var self = this;
        girder.restRequest({
            path: 'annotation/' + annotId,
            method: 'GET',
            contentType: 'application/json',
        }).done(function(data) {self.AddAnnotationItem(data);});
    }

    // Converts annotation layer widgets into girder annotation elements.
    // returns an elements array.
    GirderWidget.prototype.RecordAnnotation = function() {
        var returnElements = [];
        for (var i = 0; i < this.AnnotationLayer.GetNumberOfWidgets(); ++i) {
            var widget = this.AnnotationLayer.GetWidget(i).Serialize();
            if (widget.type == "circle") {
                var element = {"type": "circle",
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "center":   widget.origin,
                               "radius":   widget.radius};
                returnElements.push(element);
            }
            if (widget.type == "text") {
                // Will not keep scale feature..
                var points = [widget.position, widget.offset];
                points[1][0] += widget.position[0];
                points[1][1] += widget.position[1];
                var element = {"type": "arrow",
                               "label": widget.string,
                               "lineColor":SAM.ConvertColorToHex(widget.color),
                               'lineWidth': 10,
                               "points": points};
                returnElements.push(element);
            }
            if (widget.type == "grid") {
                var element = {"type": "rectanglegrid",
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "center": widget.origin,
                               "width":  widget.bin_width * widget.dimensions[0],
                               "height":  widget.bin_height * widget.dimensions[1],
                               "rotation": widget.orientation,
                               "normal": [0, 0, 1.0],
                               "widthSubdivisions": widget.dimensions[0],
                               "heightSubdivisions": widget.dimensions[1]};
                returnElements.push(element);
            }
            if (widget.type == "polyline") {
                // add the z coordinate
                for (var j = 0; j < widget.points.length; ++j) {
                    widget.points[j].push(0);
                }
                var element = {"type": "polyline",
                               "closed":widget.closedloop,
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "points": widget.points};
                returnElements.push(element);
            }
            if (widget.type == "lasso") {
                // add the z coordinate
                for (var j = 0; j < widget.points.length; ++j) {
                    widget.points[j].push(0);
                }
                var element = {"type": "polyline",
                               "closed": true,
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "points": widget.points};
                returnElements.push(element);
            }
            // Pencil scheme not exact match.  Need to split up polylines.
            if (widget.type == "pencil") {
                for (var i = 0; i < widget.shapes.length; ++i) {
                    var points = widget.shapes[i];
                    // add the z coordinate
                    for (var j = 0; j < points.length; ++j) {
                        points[j].push(0);
                    }
                    var element = {"type": "polyline",
                                   "closed":false,
                                   "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                                   "lineWidth":widget.linewidth,
                                   "points": points};
                    returnElements.push(element);
                }
            }
        }
        return returnElements;
    }

    // Replace an existing annotation with the current state of the
    // annotation layer.  Saves in the database too.
    // NOTE: We have no safe way for the database save to fail.
    GirderWidget.prototype.SnapShotAnnotation = function(annotObj) {
        this.Highlight(annotObj);
        annotObj.Data.elements = this.RecordAnnotation();
        if (window.girder) {
            // Save in the database
            girder.restRequest({
                path:  "annotation/"+annotObj.Data._id,
                method: 'PUT',
                data: JSON.stringify(annotObj.Data),
                contentType:'application/json'
            });
        }
    }

    // Delete button in menu calls this.
    // Remove the annotation from the gui and database.
    // TODO: animate the circles moving up.
    GirderWidget.prototype.DeleteAnnotation = function(deleteAnnotObj) {
        var found = false;
        var newObjects = [];
        for (var i = 0; i < this.AnnotationObjects.length; ++i) {
            var annotObj = this.AnnotationObjects[i];
            if (found) {
                // Animate the dots up to fill the space.
                var y = 70 + ((i-1)*6*this.Radius);
                annotObj.Circle.animate({'top':y+'px'});
                newObjects.push(annotObj);
            } else if (deleteAnnotObj == annotObj) {
                found = true;
                annotObj.Circle.remove();
                if (window.girder) {
                    // Remove the annotation from the database.
                    girder.restRequest({
                        path:  "annotation/"+annotObj.Data._id,
                        method: 'DELETE',
                        contentType:'application/json'
                    });
                }
            } else {
                newObjects.push(annotObj);
            }
        }
        // Animate the "Add Annotation" button up too.
        var y = 70 + ((i-1)*6*this.Radius);
        this.Plus.animate({'top':y+'px'});
        this.AnnotationObjects = newObjects;
    }

    // Animate the "add annotation" button down to make room for another
    // annotation button.  Make a new annotation and save it in the
    // database. Return the annotationObject which has GUI and data.
    GirderWidget.prototype.AddAnnotation = function(data) {
        var idx = this.AnnotationObjects.length;
        var y = 70 + (idx*6*this.Radius);

        var self = this;
        var circle = $('<div>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .css({'position':'absolute',
                  'left':(3*this.Radius)+'px',
                  'top': y+'px',
                  'width': (2*this.Radius)+'px',
                  'height': (2*this.Radius)+'px',
                  'background-color':'#55BBFF',
                  'opacity':'0.6',
                  'border':'1px solid #666666',
                  'border-radius':this.Radius+'px'})
            .prop('title', "Show Annotation")
            .hide() // hide until animation is finished.
            .hover(function(){$(this).css({'opacity':'1'});},
                   function(){$(this).css({'opacity':'0.6'});});

        var annotObj = {Data:data,
                        Circle:circle};
        this.AnnotationObjects.push(annotObj);

        circle.mousedown(function(e){
            if( e.button == 0 ) {
                self.DisplayAnnotation(annotObj);
                return false;
            }
            if( e.button == 2 ) {
                self.MenuAnnotationObject = annotObj;
                // Position and show the properties menu.
                var pos = $(this).position();
                self.Menu
                    .css({'left':(5 + pos.left + 2*self.Radius)+'px',
                          'top' :(pos.top)+'px'})
                    .show()
                return false;
            }
            return true;
        });

        // Annotate the "add annotation" button down.
        this.Plus.animate({'top':(y+(6*this.Radius))+'px'}, 400,
                          function () { circle.show(); });

        return annotObj;
    }

    // Make the circle button yellow (and turn off the previous.)
    GirderWidget.prototype.Highlight = function(annotObj) {
        // Highlight the circle for this annotaiton.
        if (this.Highlighted) {
            this.Highlighted.Circle.css({'background-color':'#55BBFF'});
        }
        this.Highlighted = annotObj;
        if (annotObj) {
            annotObj.Circle.css({'background-color':'#FFDD00'});
        }
    }

    // Move the annotation info to the layer widgets and draw.
    GirderWidget.prototype.DisplayAnnotation = function(annotObj) {
        this.Highlight(annotObj);

        this.AnnotationLayer.Reset();
        var annot = annotObj.Data;
        for (var i = 0; i < annot.elements.length; ++i) {
            var element = annot.elements[i];
            var obj = {};
            if (element.type == "circle") {
                obj.type = element.type;
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.origin = element.center;
                obj.radius = element.radius;
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "arrow") {
                obj.type = "text";
                obj.string = element.label;
                obj.color = SAM.ConvertColor(element.lineColor);
                obj.position = element.points[0].slice(0);
                obj.offset = element.points[1].slice(0);
                obj.offset[0] -= obj.position[0];
                obj.offset[1] -= obj.position[1];
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "rectanglegrid") {
                obj.type = "grid",
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.origin = element.center;
                obj.bin_width = element.width / element.widthSubdivisions;
                obj.bin_height = element.height / element.heightSubdivisions;
                obj.orientation = element.rotation;
                obj.dimensions = [element.widthSubdivisions, element.heightSubdivisions];
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "polyline") {
                obj.type = element.type;
                obj.closedloop = element.closed;
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.points = element.points;
                this.AnnotationLayer.LoadWidget(obj);
            }
        }
        this.AnnotationLayer.EventuallyDraw();
    }

    SAM.GirderWidget = GirderWidget;

})();
<commit_msg>girder rest api<commit_after>// TODO:
// Record id when creating a new annotation.
// Finish polyline "NewAnnotationItem"
// Load annotation into layer when circle is clicked on.
// Right click menu to "delete, modify (record over), set name.
// Hover over circle to see annotation name.
// Finish remaining annotation items.
// Add camera view as annotation.

(function () {
    "use strict";

    function GirderWidget (layer, itemId) {
        if (itemId) {
            this.ImageItemId  = itemId;
            this.LoadGirderImageItem(itemId);
        }
        this.Radius = 7;
        this.AnnotationLayer = layer;

        var idx = 0;
        var y = 70 + (idx*6*this.Radius);
        var self = this;
        this.Plus = $('<img>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .attr('src',"/webgl-viewer/static/"+"bluePlus.png")
            .css({'position':'absolute',
                  'left':(3*this.Radius)+'px',
                  'top': y+'px',
                  'width': (2*this.Radius)+'px',
                  'height': (2*this.Radius)+'px',
                  'opacity':'0.6'})
            .prop('title', "Add Annotation")
            .hover(function(){$(this).css({'opacity':'1'});},
                   function(){$(this).css({'opacity':'0.6'});})
            .click(function () { self.NewAnnotationItem();});

        this.AnnotationObjects = [];
        this.Highlighted = undefined;

        this.MenuAnnotationObject = undefined;
        this.Menu = $('<div>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .hide()
            .mouseleave(function(){$(this).hide();})
            .css({'position'  :'absolute',
                  'background-color': '#FFFFFF',
                  'border'    :'1px solid #666666',
                  'box-sizing': 'border-box',
                  'left'      : '-78px',
                  'width'     : '100px',
                  'padding'   : '0px 2px'})

        $('<button>')
            .appendTo(this.Menu)
            .text("Snap Shot")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .prop('title', "Replace Annotation")
            .click(
                function(){
                    self.SnapShotAnnotation(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
        $('<button>')
            .appendTo(this.Menu)
            .text("Delete")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .click(
                function(){
                    self.DeleteAnnotation(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
        $('<button>')
            .appendTo(this.Menu)
            .text("Properties")
            .css({'margin': '2px 0px',
                  'width' : '100%'})
            .click(
                function(){
                    // Not implemented yet.
                    //self.ShowAnnotationPropertiesDialog(self.MenuAnnotationObject);
                    self.Menu.hide();
                });
    }

    // Create a new annotation item from the annotation layer.
    // Save it in the database.  Add the annotation as a dot in the GUI.
    GirderWidget.prototype.NewAnnotationItem = function(itemId) {
        var annot = {"elements": []};
        annot.name = "SA-"+this.AnnotationObjects.length;
        annot.elements = this.RecordAnnotation();

        // Make a new annotation in the database.
        var self = this;
        if (window.girder) { // Conditional is for testing in slide atlas.
            girder.restRequest({
                path:  "annotation?itemId="+this.ImageItemId,
                method: 'POST',
                contentType:'application/json',
                data: JSON.stringify(annot),
            }).done(function(retAnnot) {
                // This has the girder id.
                self.Highlight(self.AddAnnotation(retAnnot));
            });
        } else {
            // for debugging without girder.
            self.Highlight(self.AddAnnotation(annot));
        }
    }

    GirderWidget.prototype.LoadGirderImageItem = function(itemId) {
        //var itemId = "564e42fe3f24e538e9a20eb9";
        var data= {"itemId": itemId,
                   "limit": 50,
                   "offset": 0,
                   "sort":"lowerName",
                   "sortdir":1};

        var self = this;
        // This gives an array of {_id:"....",annotation:{name:"...."},itemId:"...."}
        girder.restRequest({
            path:   "annotation",
            method: "GET",
            data:   JSON.stringify(data)
        }).done(function(data) {
            for (var i = 0; i < data.length; ++i) {
                self.LoadAnnotationItem(data._id);
            }
        });
    }

    GirderWidget.prototype.LoadAnnotationItem = function(annotId) {
        //var annotId = "572be29d3f24e53573aa8e91";
        var self = this;
        girder.restRequest({
            path: 'annotation/' + annotId,
            method: 'GET',
            contentType: 'application/json',
        }).done(function(data) {self.AddAnnotationItem(data);});
    }

    // Converts annotation layer widgets into girder annotation elements.
    // returns an elements array.
    GirderWidget.prototype.RecordAnnotation = function() {
        var returnElements = [];
        for (var i = 0; i < this.AnnotationLayer.GetNumberOfWidgets(); ++i) {
            var widget = this.AnnotationLayer.GetWidget(i).Serialize();
            if (widget.type == "circle") {
                var element = {"type": "circle",
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "center":   widget.origin,
                               "radius":   widget.radius};
                returnElements.push(element);
            }
            if (widget.type == "text") {
                // Will not keep scale feature..
                var points = [widget.position, widget.offset];
                points[1][0] += widget.position[0];
                points[1][1] += widget.position[1];
                var element = {"type": "arrow",
                               "label": widget.string,
                               "lineColor":SAM.ConvertColorToHex(widget.color),
                               'lineWidth': 10,
                               "points": points};
                returnElements.push(element);
            }
            if (widget.type == "grid") {
                var element = {"type": "rectanglegrid",
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "center": widget.origin,
                               "width":  widget.bin_width * widget.dimensions[0],
                               "height":  widget.bin_height * widget.dimensions[1],
                               "rotation": widget.orientation,
                               "normal": [0, 0, 1.0],
                               "widthSubdivisions": widget.dimensions[0],
                               "heightSubdivisions": widget.dimensions[1]};
                returnElements.push(element);
            }
            if (widget.type == "polyline") {
                // add the z coordinate
                for (var j = 0; j < widget.points.length; ++j) {
                    widget.points[j].push(0);
                }
                var element = {"type": "polyline",
                               "closed":widget.closedloop,
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "points": widget.points};
                returnElements.push(element);
            }
            if (widget.type == "lasso") {
                // add the z coordinate
                for (var j = 0; j < widget.points.length; ++j) {
                    widget.points[j].push(0);
                }
                var element = {"type": "polyline",
                               "closed": true,
                               "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                               "lineWidth":widget.linewidth,
                               "points": widget.points};
                returnElements.push(element);
            }
            // Pencil scheme not exact match.  Need to split up polylines.
            if (widget.type == "pencil") {
                for (var i = 0; i < widget.shapes.length; ++i) {
                    var points = widget.shapes[i];
                    // add the z coordinate
                    for (var j = 0; j < points.length; ++j) {
                        points[j].push(0);
                    }
                    var element = {"type": "polyline",
                                   "closed":false,
                                   "lineColor":SAM.ConvertColorToHex(widget.outlinecolor),
                                   "lineWidth":widget.linewidth,
                                   "points": points};
                    returnElements.push(element);
                }
            }
        }
        return returnElements;
    }

    // Replace an existing annotation with the current state of the
    // annotation layer.  Saves in the database too.
    // NOTE: We have no safe way for the database save to fail.
    GirderWidget.prototype.SnapShotAnnotation = function(annotObj) {
        this.Highlight(annotObj);
        annotObj.Data.elements = this.RecordAnnotation();
        if (window.girder) {
            // Save in the database
            girder.restRequest({
                path:  "annotation/"+annotObj.Data._id,
                method: 'PUT',
                data: JSON.stringify(annotObj.Data),
                contentType:'application/json'
            });
        }
    }

    // Delete button in menu calls this.
    // Remove the annotation from the gui and database.
    // TODO: animate the circles moving up.
    GirderWidget.prototype.DeleteAnnotation = function(deleteAnnotObj) {
        var found = false;
        var newObjects = [];
        for (var i = 0; i < this.AnnotationObjects.length; ++i) {
            var annotObj = this.AnnotationObjects[i];
            if (found) {
                // Animate the dots up to fill the space.
                var y = 70 + ((i-1)*6*this.Radius);
                annotObj.Circle.animate({'top':y+'px'});
                newObjects.push(annotObj);
            } else if (deleteAnnotObj == annotObj) {
                found = true;
                annotObj.Circle.remove();
                if (window.girder) {
                    // Remove the annotation from the database.
                    girder.restRequest({
                        path:  "annotation/"+annotObj.Data._id,
                        method: 'DELETE',
                        contentType:'application/json'
                    });
                }
            } else {
                newObjects.push(annotObj);
            }
        }
        // Animate the "Add Annotation" button up too.
        var y = 70 + ((i-1)*6*this.Radius);
        this.Plus.animate({'top':y+'px'});
        this.AnnotationObjects = newObjects;
    }

    // Animate the "add annotation" button down to make room for another
    // annotation button.  Make a new annotation and save it in the
    // database. Return the annotationObject which has GUI and data.
    GirderWidget.prototype.AddAnnotation = function(data) {
        var idx = this.AnnotationObjects.length;
        var y = 70 + (idx*6*this.Radius);

        var self = this;
        var circle = $('<div>')
            .appendTo(this.AnnotationLayer.GetCanvasDiv())
            .css({'position':'absolute',
                  'left':(3*this.Radius)+'px',
                  'top': y+'px',
                  'width': (2*this.Radius)+'px',
                  'height': (2*this.Radius)+'px',
                  'background-color':'#55BBFF',
                  'opacity':'0.6',
                  'border':'1px solid #666666',
                  'border-radius':this.Radius+'px'})
            .prop('title', "Show Annotation")
            .hide() // hide until animation is finished.
            .hover(function(){$(this).css({'opacity':'1'});},
                   function(){$(this).css({'opacity':'0.6'});});

        var annotObj = {Data:data,
                        Circle:circle};
        this.AnnotationObjects.push(annotObj);

        circle.mousedown(function(e){
            if( e.button == 0 ) {
                self.DisplayAnnotation(annotObj);
                return false;
            }
            if( e.button == 2 ) {
                self.MenuAnnotationObject = annotObj;
                // Position and show the properties menu.
                var pos = $(this).position();
                self.Menu
                    .css({'left':(5 + pos.left + 2*self.Radius)+'px',
                          'top' :(pos.top)+'px'})
                    .show()
                return false;
            }
            return true;
        });

        // Annotate the "add annotation" button down.
        this.Plus.animate({'top':(y+(6*this.Radius))+'px'}, 400,
                          function () { circle.show(); });

        return annotObj;
    }

    // Make the circle button yellow (and turn off the previous.)
    GirderWidget.prototype.Highlight = function(annotObj) {
        // Highlight the circle for this annotaiton.
        if (this.Highlighted) {
            this.Highlighted.Circle.css({'background-color':'#55BBFF'});
        }
        this.Highlighted = annotObj;
        if (annotObj) {
            annotObj.Circle.css({'background-color':'#FFDD00'});
        }
    }

    // Move the annotation info to the layer widgets and draw.
    GirderWidget.prototype.DisplayAnnotation = function(annotObj) {
        this.Highlight(annotObj);

        this.AnnotationLayer.Reset();
        var annot = annotObj.Data;
        for (var i = 0; i < annot.elements.length; ++i) {
            var element = annot.elements[i];
            var obj = {};
            if (element.type == "circle") {
                obj.type = element.type;
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.origin = element.center;
                obj.radius = element.radius;
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "arrow") {
                obj.type = "text";
                obj.string = element.label;
                obj.color = SAM.ConvertColor(element.lineColor);
                obj.position = element.points[0].slice(0);
                obj.offset = element.points[1].slice(0);
                obj.offset[0] -= obj.position[0];
                obj.offset[1] -= obj.position[1];
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "rectanglegrid") {
                obj.type = "grid",
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.origin = element.center;
                obj.bin_width = element.width / element.widthSubdivisions;
                obj.bin_height = element.height / element.heightSubdivisions;
                obj.orientation = element.rotation;
                obj.dimensions = [element.widthSubdivisions, element.heightSubdivisions];
                this.AnnotationLayer.LoadWidget(obj);
            }
            if (element.type == "polyline") {
                obj.type = element.type;
                obj.closedloop = element.closed;
                obj.outlinecolor = SAM.ConvertColor(element.lineColor);
                obj.linewidth = element.lineWidth;
                obj.points = element.points;
                this.AnnotationLayer.LoadWidget(obj);
            }
        }
        this.AnnotationLayer.EventuallyDraw();
    }

    SAM.GirderWidget = GirderWidget;

})();
<|endoftext|>


<commit_before>$.fn.extend({imageLoaded:function(i){var n=$(this).find("img"),t=n.length;0==t&&i(),n.each(function(n,e){var e=new Image;e.onload=function(){t--,0==t&&i()},e.onerror=function(){t--,0==t&&i()},e.src=$(e).attr("src")})},gridify:function(i){var n=$(this),i=i||{},t=function(i){for(var n=0,t=1;t<i.length;t++)i[t]<i[n]&&(n=t);return n},e=function(){n.css("position","relative");var e=n.find(i.srcNode),a=((i.transition||"all 0.5s ease")+", height 0, width 0",n.innerWidth()),o=parseInt(i.margin||0),r=parseInt(i.max_width||i.width||220),s=Math.max(Math.floor(a/(r+o)),1),h=1==s?o/2:a%(r+o)/2,d=[];i.max_width&&(s=Math.ceil(a/(r+o)),r=(a-s*o-o)/s,h=o/2);for(var f=0;s>f;f++)d.push(0);e.each(function(n,e){var a=$(e),s=t(d);a.css({width:r,position:"absolute",margin:o/2,top:d[s]+o/2,left:(r+o)*s+h,transition:i.transition||"all 0.5s ease"}),d[s]+=a.innerHeight()+o})};if(e(),n.imageLoaded(function(){setTimeout(e,200)}),i.resizable){var a=$(window).on("resize",function(){e(),i.max_width&&setTimeout(e,200)});n.on("remove",a.unbind)}}});<commit_msg>updated gridify-min<commit_after>$.fn.extend({imageLoaded:function(n){var i=$(this).find("img"),t=i.length;0==t&&n(),i.each(function(i,a){var a=new Image;a.onload=function(){t--,0==t&&n()},a.onerror=function(){t--,0==t&&n()},a.src=$(a).attr("src")})},gridify:function(n){var i=$(this),n=n||{},t=function(n){for(var i=0,t=1;t<n.length;t++)n[t]<n[i]&&(i=t);return i},a=function(){i.css("position","relative");var a=i.find(n.srcNode),e=((n.transition||"all 0.5s ease")+", height 0, width 0",i.innerWidth()),o=parseInt(n.margin||0),r=parseInt(n.max_width||n.width||220),s=Math.max(Math.floor(e/(r+o)),1),f=1==s?o/2:e%(r+o)/2,h=[];n.max_width&&(s=Math.ceil(e/(r+o)),r=(e-s*o-o)/s,f=o/2);for(var c=0;s>c;c++)h.push(0);a.each(function(i,a){var e=$(a),s=t(h);e.css({width:r,position:"absolute",margin:o/2,top:h[s]+o/2,left:(r+o)*s+f,transition:n.transition||"all 0.5s ease"}),h[s]+=e.innerHeight()+o})};if(i.imageLoaded(function(){}),n.resizable){var e=$(window).on("resize",function(){a()});i.on("remove",e.unbind)}}});<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {

  var OptionsPage = options.OptionsPage;

  /**
   * ImportDataOverlay class
   * Encapsulated handling of the 'Import Data' overlay page.
   * @class
   */
  function ImportDataOverlay() {
    OptionsPage.call(this, 'importDataOverlay',
                     templateData.import_data_title,
                     'importDataOverlay');
  }

  ImportDataOverlay.throbIntervalId = 0

  cr.addSingletonGetter(ImportDataOverlay);

  ImportDataOverlay.prototype = {
    // Inherit ImportDataOverlay from OptionsPage.
    __proto__: OptionsPage.prototype,

    /**
     * Initialize the page.
     */
    initializePage: function() {
      // Call base class implementation to starts preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      var checkboxes =
          document.querySelectorAll('#import-checkboxes input[type=checkbox]');
      for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i].onchange = function() {
          self.validateCommitButton_();
        };
      }

      $('import-browsers').onchange = function() {
        self.updateCheckboxes_();
        self.validateCommitButton_();
      }

      $('import-data-commit').onclick = function() {
        chrome.send('importData', [
            String($('import-browsers').selectedIndex),
            String($('import-history').checked),
            String($('import-favorites').checked),
            String($('import-passwords').checked),
            String($('import-search').checked)]);
      }

      $('import-data-cancel').onclick = function() {
        ImportDataOverlay.dismiss();
      }
    },

    /**
     * Set enabled and checked state of the commit button.
     * @private
     */
    validateCommitButton_: function() {
      var somethingToImport =
          $('import-history').checked || $('import-favorites').checked ||
          $('import-passwords').checked || $('import-search').checked;
      $('import-data-commit').disabled = !somethingToImport;
    },

    /**
     * Set enabled and checked states a checkbox element.
     * @param {Object} checkbox A checkbox element.
     * @param {boolean} enabled The enabled state of the chekbox.
     * @private
     */
    setUpCheckboxState_: function(checkbox, enabled) {
      checkbox.disabled = !enabled;
      checkbox.checked = enabled;
    },

    /**
     * Update the enabled and checked states of all checkboxes.
     * @private
     */
    updateCheckboxes_: function() {
      var index = $('import-browsers').selectedIndex;
      var browserProfile = ImportDataOverlay.browserProfiles[index];
      var importOptions = ['history', 'favorites', 'passwords', 'search'];
      for (var i = 0; i < importOptions.length; i++) {
        var checkbox = $('import-' + importOptions[i]);
        this.setUpCheckboxState_(checkbox, browserProfile[importOptions[i]]);
      }
    },

    /**
     * Update the supported browsers popup with given entries.
     * @param {array} browsers List of supported browsers name.
     * @private
     */
    updateSupportedBrowsers_: function(browsers) {
      ImportDataOverlay.browserProfiles = browsers;
      var browserSelect = $('import-browsers');
      browserSelect.textContent = '';
      var browserCount = browsers.length;

      if (browserCount == 0) {
        var option = new Option(templateData.no_profile_found, 0);
        browserSelect.appendChild(option);

        var checkboxes =
            document.querySelectorAll(
                '#import-checkboxes input[type=checkbox]');
        for (var i = 0; i < checkboxes.length; i++) {
          setUpCheckboxState_(checkboxes[i], false);
        }
      } else {
        for (var i = 0; i < browserCount; i++) {
          var browser = browsers[i]
          var option = new Option(browser['name'], browser['index']);
          browserSelect.appendChild(option);
        }

        this.updateCheckboxes_();
        this.validateCommitButton_();
      }
    },
  };

  /**
   * Update the supported browsers popup with given entries.
   * @param {array} list of supported browsers name.
   */
  ImportDataOverlay.updateSupportedBrowsers = function(browsers) {
    ImportDataOverlay.getInstance().updateSupportedBrowsers_(browsers);
  };

  /**
   * Update the UI to reflect whether an import operation is in progress.
   * @param {boolean} state True if an import operation is in progress.
   */
  ImportDataOverlay.setImportingState = function(state) {
    if (state) {
      var checkboxes =
          document.querySelectorAll('#import-checkboxes input[type=checkbox]');
      for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i].disabled = true;
      }
    } else {
      ImportDataOverlay.getInstance().updateCheckboxes_();
    }
    $('import-browsers').disabled = state;
    $('import-data-commit').disabled = state;
    $('import-throbber').style.visibility = state ? "visible" : "hidden";

    function advanceThrobber() {
      var throbber = $('import-throbber');
      throbber.style.backgroundPositionX =
          ((parseInt(getComputedStyle(throbber).backgroundPositionX, 10) - 16)
          % 576) + 'px';
    }
    if (state) {
      ImportDataOverlay.throbIntervalId = setInterval(advanceThrobber, 30);
    } else {
      clearInterval(ImportDataOverlay.throbIntervalId);
    }
  };

  /**
   * Remove the import overlay from display.
   */
  ImportDataOverlay.dismiss = function() {
    ImportDataOverlay.setImportingState(false);
    OptionsPage.clearOverlays();
  }

  // Export
  return {
    ImportDataOverlay: ImportDataOverlay
  };

});
<commit_msg>Fix options page breakage.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('options', function() {

  var OptionsPage = options.OptionsPage;

  /**
   * ImportDataOverlay class
   * Encapsulated handling of the 'Import Data' overlay page.
   * @class
   */
  function ImportDataOverlay() {
    OptionsPage.call(this, 'importDataOverlay',
                     templateData.import_data_title,
                     'importDataOverlay');
  }

  ImportDataOverlay.throbIntervalId = 0

  cr.addSingletonGetter(ImportDataOverlay);

  ImportDataOverlay.prototype = {
    // Inherit ImportDataOverlay from OptionsPage.
    __proto__: OptionsPage.prototype,

    /**
     * Initialize the page.
     */
    initializePage: function() {
      // Call base class implementation to starts preference initialization.
      OptionsPage.prototype.initializePage.call(this);

      var self = this;
      var checkboxes =
          document.querySelectorAll('#import-checkboxes input[type=checkbox]');
      for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i].onchange = function() {
          self.validateCommitButton_();
        };
      }

      $('import-browsers').onchange = function() {
        self.updateCheckboxes_();
        self.validateCommitButton_();
      }

      $('import-data-commit').onclick = function() {
        chrome.send('importData', [
            String($('import-browsers').selectedIndex),
            String($('import-history').checked),
            String($('import-favorites').checked),
            String($('import-passwords').checked),
            String($('import-search').checked)]);
      }

      $('import-data-cancel').onclick = function() {
        ImportDataOverlay.dismiss();
      }
    },

    /**
     * Set enabled and checked state of the commit button.
     * @private
     */
    validateCommitButton_: function() {
      var somethingToImport =
          $('import-history').checked || $('import-favorites').checked ||
          $('import-passwords').checked || $('import-search').checked;
      $('import-data-commit').disabled = !somethingToImport;
    },

    /**
     * Set enabled and checked states a checkbox element.
     * @param {Object} checkbox A checkbox element.
     * @param {boolean} enabled The enabled state of the chekbox.
     * @private
     */
    setUpCheckboxState_: function(checkbox, enabled) {
      checkbox.disabled = !enabled;
      checkbox.checked = enabled;
    },

    /**
     * Update the enabled and checked states of all checkboxes.
     * @private
     */
    updateCheckboxes_: function() {
      var index = $('import-browsers').selectedIndex;
      var browserProfile = ImportDataOverlay.browserProfiles[index];
      var importOptions = ['history', 'favorites', 'passwords', 'search'];
      for (var i = 0; i < importOptions.length; i++) {
        var checkbox = $('import-' + importOptions[i]);
        this.setUpCheckboxState_(checkbox, browserProfile[importOptions[i]]);
      }
    },

    /**
     * Update the supported browsers popup with given entries.
     * @param {array} browsers List of supported browsers name.
     * @private
     */
    updateSupportedBrowsers_: function(browsers) {
      ImportDataOverlay.browserProfiles = browsers;
      var browserSelect = $('import-browsers');
      browserSelect.textContent = '';
      var browserCount = browsers.length;

      if (browserCount == 0) {
        var option = new Option(templateData.no_profile_found, 0);
        browserSelect.appendChild(option);

        var checkboxes =
            document.querySelectorAll(
                '#import-checkboxes input[type=checkbox]');
        for (var i = 0; i < checkboxes.length; i++) {
          this.setUpCheckboxState_(checkboxes[i], false);
        }
      } else {
        for (var i = 0; i < browserCount; i++) {
          var browser = browsers[i]
          var option = new Option(browser['name'], browser['index']);
          browserSelect.appendChild(option);
        }

        this.updateCheckboxes_();
        this.validateCommitButton_();
      }
    },
  };

  /**
   * Update the supported browsers popup with given entries.
   * @param {array} list of supported browsers name.
   */
  ImportDataOverlay.updateSupportedBrowsers = function(browsers) {
    ImportDataOverlay.getInstance().updateSupportedBrowsers_(browsers);
  };

  /**
   * Update the UI to reflect whether an import operation is in progress.
   * @param {boolean} state True if an import operation is in progress.
   */
  ImportDataOverlay.setImportingState = function(state) {
    if (state) {
      var checkboxes =
          document.querySelectorAll('#import-checkboxes input[type=checkbox]');
      for (var i = 0; i < checkboxes.length; i++) {
        checkboxes[i].disabled = true;
      }
    } else {
      ImportDataOverlay.getInstance().updateCheckboxes_();
    }
    $('import-browsers').disabled = state;
    $('import-data-commit').disabled = state;
    $('import-throbber').style.visibility = state ? "visible" : "hidden";

    function advanceThrobber() {
      var throbber = $('import-throbber');
      throbber.style.backgroundPositionX =
          ((parseInt(getComputedStyle(throbber).backgroundPositionX, 10) - 16)
          % 576) + 'px';
    }
    if (state) {
      ImportDataOverlay.throbIntervalId = setInterval(advanceThrobber, 30);
    } else {
      clearInterval(ImportDataOverlay.throbIntervalId);
    }
  };

  /**
   * Remove the import overlay from display.
   */
  ImportDataOverlay.dismiss = function() {
    ImportDataOverlay.setImportingState(false);
    OptionsPage.clearOverlays();
  }

  // Export
  return {
    ImportDataOverlay: ImportDataOverlay
  };

});
<|endoftext|>


<commit_before>// Copyright 2013-2016, University of Colorado Boulder

/**
 * A DerivedProperty is computed based on other Properties.  This implementation inherits from Property to (a) simplify
 * implementation and (b) ensure it remains consistent. Note that the setters should not be called directly, so the
 * setters (set, reset and es5 setter) throw an error if used directly.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

define( function( require ) {
  'use strict';

  // modules
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TDerivedProperty = require( 'AXON/TDerivedProperty' );

  /**
   * @param {Property[]} dependencies - Properties that this Property's value is derived from
   * @param {function} derivation - function that derives this Property's value, expects args in the same order as dependencies
   * @param {Object} [options] - see Property
   * @constructor
   */
  function DerivedProperty( dependencies, derivation, options ) {

    options = _.extend( {
      tandem: Tandem.tandemOptional()
    }, options );

    this.dependencies = dependencies; // @private

    var initialValue = derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) );

    // We must pass supertype tandem to parent class so addInstance is called only once in the subclassiest constructor.
    Property.call( this, initialValue, _.extend( {}, options, {
      tandem: options.tandem && options.tandem.createSupertypeTandem()
    } ) );

    // @private - for disposal
    this.derivedPropertyTandem = options.tandem;

    var self = this;

    // @private Keep track of listeners so they can be detached
    this.dependencyListeners = [];

    for ( var i = 0; i < dependencies.length; i++ ) {
      var dependency = dependencies[ i ];
      (function( dependency ) {
        var listener = function() {
          Property.prototype.set.call( self, derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) ) );
        };
        self.dependencyListeners.push( listener );
        dependency.lazyLink( listener );
      })( dependency, i );
    }

    // If running as phet-io and a tandem is supplied, register with tandem.
    options.tandem.supplied && options.tandem.addInstance( this, TDerivedProperty( options.phetioValueType ), options );
  }

  axon.register( 'DerivedProperty', DerivedProperty );

  function equalsFunction( a, b ) {
    return a === b;
  }

  function conjunctionWithProperty( value, property ) {
    return value && property.value;
  }

  function disjunctionWithProperty( value, property ) {
    return value || property.value;
  }

  return inherit( Property, DerivedProperty, {

    // @public
    dispose: function() {

      // Unlink from dependent Properties
      for ( var i = 0; i < this.dependencies.length; i++ ) {
        var dependency = this.dependencies[ i ];
        dependency.unlink( this.dependencyListeners[ i ] );
      }
      this.dependencies = null;
      this.dependencyListeners = null;

      this.derivedPropertyTandem.removeInstance( this );

      Property.prototype.dispose.call( this );
    },

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @param value
     * @override
     * @public
     */
    set: function( value ) { throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value ); },

    /**
     * Override the mutators to provide an error message.  These should not be called directly, the value should only be modified
     * when the dependencies change. Keep the newValue output in the string so the argument won't be stripped by minifier
     * (which would cause crashes like https://github.com/phetsims/axon/issues/15)
     * @param newValue
     * @override
     * @public
     */
    set value( newValue ) { throw new Error( 'Cannot es5-set values directly to a DerivedProperty, tried to set: ' + newValue ); },

    /**
     * Override get value as well to satisfy the linter which wants get/set pairs (even though it just uses the same code as the superclass).
     * @returns {*}
     * @override
     * @public
     */
    get value() {return Property.prototype.get.call( this );},

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @override
     * @public
     */
    reset: function() { throw new Error( 'Cannot reset a DerivedProperty directly' ); }
  }, {

    /**
     * Creates a derived boolean Property whose value is true iff firstProperty's value is equal to secondProperty's
     * value.
     * @public
     *
     * @param {Property.<*>} firstProperty
     * @param {Property.<*>} secondProperty
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    valueEquals: function( firstProperty, secondProperty, options ) {
      return new DerivedProperty( [ firstProperty, secondProperty ], equalsFunction, options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff every input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    and: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, conjunctionWithProperty, true ), options ); // TODO: fix
    },

    /**
     * Creates a derived boolean Property whose value is true iff any input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    or: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, disjunctionWithProperty, false ), options );
    }
  } );
} );<commit_msg>remove private functions to match their associated static methods<commit_after>// Copyright 2013-2016, University of Colorado Boulder

/**
 * A DerivedProperty is computed based on other Properties.  This implementation inherits from Property to (a) simplify
 * implementation and (b) ensure it remains consistent. Note that the setters should not be called directly, so the
 * setters (set, reset and es5 setter) throw an error if used directly.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

define( function( require ) {
  'use strict';

  // modules
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Property = require( 'AXON/Property' );
  var Tandem = require( 'TANDEM/Tandem' );
  var TDerivedProperty = require( 'AXON/TDerivedProperty' );

  /**
   * @param {Property[]} dependencies - Properties that this Property's value is derived from
   * @param {function} derivation - function that derives this Property's value, expects args in the same order as dependencies
   * @param {Object} [options] - see Property
   * @constructor
   */
  function DerivedProperty( dependencies, derivation, options ) {

    options = _.extend( {
      tandem: Tandem.tandemOptional()
    }, options );

    this.dependencies = dependencies; // @private

    var initialValue = derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) );

    // We must pass supertype tandem to parent class so addInstance is called only once in the subclassiest constructor.
    Property.call( this, initialValue, _.extend( {}, options, {
      tandem: options.tandem && options.tandem.createSupertypeTandem()
    } ) );

    // @private - for disposal
    this.derivedPropertyTandem = options.tandem;

    var self = this;

    // @private Keep track of listeners so they can be detached
    this.dependencyListeners = [];

    for ( var i = 0; i < dependencies.length; i++ ) {
      var dependency = dependencies[ i ];
      (function( dependency ) {
        var listener = function() {
          Property.prototype.set.call( self, derivation.apply( null, dependencies.map( function( property ) {return property.get();} ) ) );
        };
        self.dependencyListeners.push( listener );
        dependency.lazyLink( listener );
      })( dependency, i );
    }

    // If running as phet-io and a tandem is supplied, register with tandem.
    options.tandem.supplied && options.tandem.addInstance( this, TDerivedProperty( options.phetioValueType ), options );
  }

  axon.register( 'DerivedProperty', DerivedProperty );

  function equalsFunction( a, b ) {
    return a === b;
  }

  function andFunction( value, property ) {
    return value && property.value;
  }

  function orFunction( value, property ) {
    return value || property.value;
  }

  return inherit( Property, DerivedProperty, {

    // @public
    dispose: function() {

      // Unlink from dependent Properties
      for ( var i = 0; i < this.dependencies.length; i++ ) {
        var dependency = this.dependencies[ i ];
        dependency.unlink( this.dependencyListeners[ i ] );
      }
      this.dependencies = null;
      this.dependencyListeners = null;

      this.derivedPropertyTandem.removeInstance( this );

      Property.prototype.dispose.call( this );
    },

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @param value
     * @override
     * @public
     */
    set: function( value ) { throw new Error( 'Cannot set values directly to a DerivedProperty, tried to set: ' + value ); },

    /**
     * Override the mutators to provide an error message.  These should not be called directly, the value should only be modified
     * when the dependencies change. Keep the newValue output in the string so the argument won't be stripped by minifier
     * (which would cause crashes like https://github.com/phetsims/axon/issues/15)
     * @param newValue
     * @override
     * @public
     */
    set value( newValue ) { throw new Error( 'Cannot es5-set values directly to a DerivedProperty, tried to set: ' + newValue ); },

    /**
     * Override get value as well to satisfy the linter which wants get/set pairs (even though it just uses the same code as the superclass).
     * @returns {*}
     * @override
     * @public
     */
    get value() {return Property.prototype.get.call( this );},

    /**
     * Override the mutators to provide an error message.  These should not be called directly,
     * the value should only be modified when the dependencies change.
     * @override
     * @public
     */
    reset: function() { throw new Error( 'Cannot reset a DerivedProperty directly' ); }
  }, {

    /**
     * Creates a derived boolean Property whose value is true iff firstProperty's value is equal to secondProperty's
     * value.
     * @public
     *
     * @param {Property.<*>} firstProperty
     * @param {Property.<*>} secondProperty
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    valueEquals: function( firstProperty, secondProperty, options ) {
      return new DerivedProperty( [ firstProperty, secondProperty ], equalsFunction, options );
    },

    /**
     * Creates a derived boolean Property whose value is true iff every input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    and: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, andFunction, true ), options ); // TODO: fix
    },

    /**
     * Creates a derived boolean Property whose value is true iff any input Property value is true.
     * @public
     *
     * @param {Array.<Property.<boolean>>} properties
     * @param {Object} [options] - Forwarded to the DerivedProperty
     * @returns {DerivedProperty.<boolean>}
     */
    or: function( properties, options ) {
      return new DerivedProperty( properties, _.reduce.bind( null, properties, orFunction, false ), options );
    }
  } );
} );<|endoftext|>


<commit_before>// Copyright 2013-2021, University of Colorado Boulder

/**
 * Scenery node that represents a simple, non-interactive clock.  It is
 * intended for use in situations where an icon representing time is needed.
 *
 * @author John Blanco
 */

import merge from '../../phet-core/js/merge.js';
import { Circle } from '../../scenery/js/imports.js';
import { Line } from '../../scenery/js/imports.js';
import { Node } from '../../scenery/js/imports.js';
import sceneryPhet from './sceneryPhet.js';

class SimpleClockIcon extends Node {

  /**
   * @param {number} radius
   * @param {Object} [options]
   */
  constructor( radius, options ) {

    super();

    options = merge( {
      fill: 'white',
      stroke: 'black',
      lineWidth: 2
    }, options );

    this.addChild( new Circle( radius, options ) );
    this.addChild( new Circle( radius * 0.15, { fill: options.stroke } ) );
    const lineOptionsForClockHands = {
      stroke: options.stroke,
      lineWidth: options.lineWidth,
      lineCap: 'round',
      lineJoin: 'round'
    };

    // Hands at 4 o'clock
    this.addChild( new Line( 0, 0, 0, -radius * 0.75, lineOptionsForClockHands ) );
    this.addChild( new Line( 0, 0, radius * 0.45, radius * 0.3, lineOptionsForClockHands ) );
    this.centerX = radius;
    this.centerY = radius;

    this.mutate( options );
  }
}

sceneryPhet.register( 'SimpleClockIcon', SimpleClockIcon );
export default SimpleClockIcon;<commit_msg>// @ts-nocheck<commit_after>// Copyright 2013-2021, University of Colorado Boulder

// @ts-nocheck
/**
 * Scenery node that represents a simple, non-interactive clock.  It is
 * intended for use in situations where an icon representing time is needed.
 *
 * @author John Blanco
 */

import merge from '../../phet-core/js/merge.js';
import { Circle } from '../../scenery/js/imports.js';
import { Line } from '../../scenery/js/imports.js';
import { Node } from '../../scenery/js/imports.js';
import sceneryPhet from './sceneryPhet.js';

class SimpleClockIcon extends Node {

  /**
   * @param {number} radius
   * @param {Object} [options]
   */
  constructor( radius, options ) {

    super();

    options = merge( {
      fill: 'white',
      stroke: 'black',
      lineWidth: 2
    }, options );

    this.addChild( new Circle( radius, options ) );
    this.addChild( new Circle( radius * 0.15, { fill: options.stroke } ) );
    const lineOptionsForClockHands = {
      stroke: options.stroke,
      lineWidth: options.lineWidth,
      lineCap: 'round',
      lineJoin: 'round'
    };

    // Hands at 4 o'clock
    this.addChild( new Line( 0, 0, 0, -radius * 0.75, lineOptionsForClockHands ) );
    this.addChild( new Line( 0, 0, radius * 0.45, radius * 0.3, lineOptionsForClockHands ) );
    this.centerX = radius;
    this.centerY = radius;

    this.mutate( options );
  }
}

sceneryPhet.register( 'SimpleClockIcon', SimpleClockIcon );
export default SimpleClockIcon;<|endoftext|>


<commit_before>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Thermometer node, see https://github.com/phetsims/scenery-phet/issues/43
 *
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Shape = require( 'KITE/Shape' );

  function ThermometerNode( minTemperature, maxTemperature, temperatureProperty, options ) {

    options = _.extend( {
      children: [],
      bulbDiameter: 50,
      tubeWidth: 30,
      tubeHeight: 100,
      lineWidth: 5,
      stroke: 'black'
    }, options );

    Node.call( this, options );

    var startAngle = -Math.acos( options.tubeWidth / options.bulbDiameter);
    var endAngle = Math.PI - startAngle;

    var shape = new Shape()
      .arc( options.centerX, options.centerY, options.bulbDiameter / 2, startAngle, endAngle )
      .verticalLineToRelative( -options.tubeHeight );

    var lastPoint = shape.getLastPoint();
    shape.arc( lastPoint.x + options.tubeWidth / 2, lastPoint.y, options.tubeWidth / 2, Math.PI, 0 )
      .verticalLineToRelative( options.tubeHeight );

    var bottomCurve = new Path( shape,
      {
        stroke: options.stroke,
        lineWidth: options.lineWidth,
        lineCap: 'round'
      } );

    this.addChild( bottomCurve );
  }

  return inherit( Node, ThermometerNode );
} );<commit_msg>rename variable<commit_after>// Copyright 2002-2014, University of Colorado Boulder

/**
 * Thermometer node, see https://github.com/phetsims/scenery-phet/issues/43
 *
 * @author Aaron Davis
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var Shape = require( 'KITE/Shape' );

  function ThermometerNode( minTemperature, maxTemperature, temperatureProperty, options ) {

    options = _.extend( {
      children: [],
      bulbDiameter: 50,
      tubeWidth: 30,
      tubeHeight: 100,
      lineWidth: 5,
      stroke: 'black'
    }, options );

    Node.call( this, options );

    var startAngle = -Math.acos( options.tubeWidth / options.bulbDiameter);
    var endAngle = Math.PI - startAngle;

    var shape = new Shape()
      .arc( options.centerX, options.centerY, options.bulbDiameter / 2, startAngle, endAngle )
      .verticalLineToRelative( -options.tubeHeight );

    var lastPoint = shape.getLastPoint();
    shape.arc( lastPoint.x + options.tubeWidth / 2, lastPoint.y, options.tubeWidth / 2, Math.PI, 0 )
      .verticalLineToRelative( options.tubeHeight );

    var outline = new Path( shape,
      {
        stroke: options.stroke,
        lineWidth: options.lineWidth,
        lineCap: 'round'
      } );

    this.addChild( outline );
  }

  return inherit( Node, ThermometerNode );
} );<|endoftext|>


<commit_before>define([], function() {
	Path.map("#!/home").to(function(){
	}).enter(function() {
		require(['tpl!template/home.html'], function(tpl) {
			$('#main').append($(tpl.apply()));
		});
	}).exit(function() {
		// Exit from route
		$('#main').off().empty();
	});
});
<commit_msg>added functionality for switching out the captions<commit_after>define([], function() {
	Path.map("#!/home").to(function(){
	}).enter(function() {
		require(['tpl!template/home.html'], function(tpl) {
			$('#main').append($(tpl.apply()));
		});
	}).exit(function() {
		// Exit from route
		$('#main').off().empty();
	});
});

$('body').on('slid.bs.carousel', '#homeSlider', function () {
	var caption = $("#caption");
	var heading = "heading";
	var body = "body text";

	var carouselData = $(this).data('bs.carousel');
  	var currentIndex = carouselData.getActiveIndex();

  	var content = [
	  		{heading: "Join Now!", body: "The easies way to get started today is to click the Sign Up button on the upper right corner of your screen. We look forward to having you as a new member of our ever-growing community!", btn: "signup",},
	  		{heading: "Get to know Us!", body: "Our community of Parents and Nannies creates such a great community we want to tell you all about it. Click the button below to learn more about Nanny Tracker.", btn: "about",},
	  		{heading: "Having Trouble?", body: "If you're having trouble naviging through Nanny Tracker or finding the information you need to find, then all you need to do is visit our FAQ page.", btn: "faq",},
  		];

    caption.empty();
    caption.append('\

' + content[currentIndex].heading + '

' + content[currentIndex].body + '

\
		learn more\
	');

});<|endoftext|>