<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { pickBoxProps } from '../box';
import cx from 'classnames';
import theme from './theme.css';
import { Heading4 } from '../typography';

class AvatarInitials extends PureComponent {
  getInitials = () => {
    const { name } = this.props;
    const splitName = name.split(' ');
    const firstLetter = splitName[0].charAt(0);
    if (splitName.length > 1) {
      const lastLetter = splitName[splitName.length - 1].charAt(0);
      return `${firstLetter}${lastLetter}`;
    }
    return firstLetter;
  };

  render() {
    const { className, color, shape, size, ...others } = this.props;
    const avatarClassNames = cx(
      theme['avatar-initials'],
      theme[`is-${size}`],
      theme[`is-${shape}`],
      theme[color],
      className,
    );

    const boxProps = pickBoxProps(others);

    return (
      <Box className={avatarClassNames} {...boxProps} data-teamleader-ui="avatar-initials">
        <Heading4 className={theme['content']}>{this.getInitials()}</Heading4>
      </Box>
    );
  }
}

AvatarInitials.propTypes = {
  /** A class name for the wrapper to give custom styles. */
  className: PropTypes.string,
  /** The color of the avatar. */
  color: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby']),
  /** The shape of the avatar. */
  shape: PropTypes.oneOf(['circle', 'rounded']),
  /** The size of the avatar. */
  size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']),
  /** The name for in the avatar. */
  name: PropTypes.string,
};

AvatarInitials.defaultProps = {
  shape: 'circle',
  size: 'medium',
  name: 'Michael Scott',
};

export default AvatarInitials;
<commit_msg>Set a default color value (neutral)<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box, { pickBoxProps } from '../box';
import cx from 'classnames';
import theme from './theme.css';
import { Heading4 } from '../typography';

class AvatarInitials extends PureComponent {
  getInitials = () => {
    const { name } = this.props;
    const splitName = name.split(' ');
    const firstLetter = splitName[0].charAt(0);
    if (splitName.length > 1) {
      const lastLetter = splitName[splitName.length - 1].charAt(0);
      return `${firstLetter}${lastLetter}`;
    }
    return firstLetter;
  };

  render() {
    const { className, color, shape, size, ...others } = this.props;
    const avatarClassNames = cx(
      theme['avatar-initials'],
      theme[`is-${size}`],
      theme[`is-${shape}`],
      theme[color],
      className,
    );

    const boxProps = pickBoxProps(others);

    return (
      <Box className={avatarClassNames} {...boxProps} data-teamleader-ui="avatar-initials">
        <Heading4 className={theme['content']}>{this.getInitials()}</Heading4>
      </Box>
    );
  }
}

AvatarInitials.propTypes = {
  /** A class name for the wrapper to give custom styles. */
  className: PropTypes.string,
  /** The color of the avatar. */
  color: PropTypes.oneOf(['neutral', 'mint', 'aqua', 'violet', 'teal', 'gold', 'ruby']),
  /** The shape of the avatar. */
  shape: PropTypes.oneOf(['circle', 'rounded']),
  /** The size of the avatar. */
  size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large']),
  /** The name for in the avatar. */
  name: PropTypes.string,
};

AvatarInitials.defaultProps = {
  color: 'neutral',
  shape: 'circle',
  size: 'medium',
  name: 'Michael Scott',
};

export default AvatarInitials;
<|endoftext|>


<commit_before>/**
 * Created by k186 on 2016/11/11.
 */
export default {
    name: 'kPicker',
    props: {
        valueStr: {
            type: String,
            default: ''
        },
        visible: {
            type:Boolean,
            default:false,
            required:true
        },
        options:{
            type: Object,
        }
    },
    data () {
        let now = new Date();
        return {
            panelType: 'day',
            monthList: [1,2,3,4,5,6,7,8,9,10,11,12],
            weekList: [0,1,2,3,4,5,6],
            yearList: Array.from({length: 12}, (value, index)=>now.getFullYear() + index),
            hourList: Array.from({length: 24}, (value, index)=>0 + index),
            tmpYear: now.getFullYear(),
            tmpMonth: now.getMonth(),
            tmpDay: now.getDate(),
            tmpHour: now.getHours(),
            selectedYear: now.getFullYear(),
            selectedMonth: now.getMonth(),
            selectedDay: now.getDate(),
            selectedHour: now.getHours(),
            animateMonth: 'off',
            animatePanel: 'off',
            animateTitle: 'toggle-title',
            changeTiltle: 'off',
        }
    },
    methods: {
        changeType(type){
            this.animateMonth='off';
            this.panelType = type;
            if (type = 'year') {
                this.yearList = Array.from({length: 12}, (value, index)=>this.tmpYear + index)
            }
        },
        changeDay(type){

        },
        changeMonth(type){
            if (type === 'next') {
                this.animateMonth='next-Month';
                this.changeTiltle='next-Title';
                this.tmpMonth += 1;
                if (this.tmpMonth > 11) {
                    this.tmpMonth = 0;
                    this.tmpYear += 1;
                }
            } else if (type === 'previous') {
                this.animateMonth='previous-Month';
                this.changeTiltle='previous-Title';
                this.tmpMonth -= 1;
                if (this.tmpMonth < 0) {
                    this.tmpMonth = 11;
                    this.tmpYear -= 1;
                }
            }
        },
        changeYear(type){
            if (type === 'next') {
                this.tmpYear += 1;
                this.yearList = this.yearList.map((i)=>i + 1);
                this.changeTiltle='next-Title';
                this.animateMonth='next-Month';

            } else if (type === 'previous') {
                this.tmpYear -= 1;
                this.yearList = this.yearList.map((i)=>i - 1);
                this.changeTiltle='previous-Title';
                this.animateMonth='previous-Month';

            }
        },
        changeYearRange(type){
            if (type === 'next') {
                this.yearList = this.yearList.map((i)=>i + 12);
                this.changeTiltle='next-Title';
                this.animateMonth='next-Month';
            } else if (type === 'previous') {
                this.yearList = this.yearList.map((i)=>i - 12);
                this.changeTiltle='previous-Title';
                this.animateMonth='previous-Month';
            }
        },
        selectYear(item){
            if(this.validYear(item)){
                this.tmpYear = item;
                this.changeType('month');
            }
        },
        selectMonth(item){
            if(this.validMonth(item)){
                this.tmpMonth = item;
                this.changeType('day');
            }
        },
        isSelected(type, item){
            switch (type) {
                case 'year':
                    if(this.validYear(item)){
                        if (item == this.orYear) {
                            return true
                        } else {
                            return false
                        }
                    }else {
                        return false
                    }

                case 'month':
                {
                    if(this.validMonth(item)){
                        if (this.orYear==this.tmpYear&&item === this.orMonth) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }

                }
                case 'day':
                {
                    if(this.validDay(item)){
                        if (this.orDay == item.value && this.orMonth === this.tmpMonth && item.currentMonth&&this.orYear==this.tmpYear) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }

                }
                case 'hour': {
                    if (this.validHour(item)) {
                        if (this.orDay == this.tmpDay && this.orMonth === this.tmpMonth && this.orYear == this.tmpYear && item == this.orHour) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }
                }
            }
        },
        selectDay(item){
            if(this.validDay(item)){
                /*choose currentMonthDay previous nex*/
                if (item.previousMonthDay) {
                    if (this.tmpMonth === 0) {
                        this.tmpYear -= 1;
                        this.tmpMonth = 11;
                    } else {
                        this.tmpMonth -= 1;
                    }
                } else if (item.nextMonthDay) {
                    if (this.tmpMonth == 11) {
                        this.tmpYear += 1;
                        this.tmpMonth = 0;
                    } else {
                        this.tmpMonth += 1;
                    }
                }
                if (!this.range) {
                    this.tmpDay = item.value;
                }
                this.changeType('hour');
                //this.$emit('selectDay', this.tmpYear + '-' + Number(this.tmpMonth + 1) + '-' + this.tmpDay)
            }
        },
        validYear(year){
            if (this.startDate.split('-')[0] <= year && year <= this.endDate.split('-')[0]) {
                return true
            } else {
                return false
            }
        },
        validMonth(month){
            let satrDate = new Date(this.startDate.split('-')[0],this.startDate.split('-')[1] - 1).getTime();
            let endDate = new Date(this.endDate.split('-')[0],this.endDate.split('-')[1]- 1).getTime();
            let tempDate = new Date(this.tmpYear, month).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        validDay(day){
            let satrDate = new Date(this.startDate.split('-')[0], this.startDate.split('-')[1] - 1,this.startDate.split('-')[2]).getTime();
            let endDate = new Date(this.endDate.split('-')[0], this.endDate.split('-')[1] - 1,this.endDate.split('-')[2]).getTime();
            let tempDate = new Date(this.tmpYear, this.tmpMonth,day.value).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        validHour(hour){
            let satrDate = new Date(this.startDate.split('-')[0], this.startDate.split('-')[1] - 1, this.startDate.split('-')[2]).getTime();
            let endDate = new Date(this.endDate.split('-')[0], this.endDate.split('-')[1] - 1, this.endDate.split('-')[2]).getTime();
            let tempDate = new Date(this.tmpYear, this.tmpMonth, this.tmpDay, hour).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        close(){
            //todo 定位问题 控释显示关闭问题
        },
        hideDatePicker(){
            this.tmpYear=this.orYear;
            this.tmpMonth=this.orMonth;
            this.tmpDay=this.orDay;
            this.panelType='day';
            this.yearList=Array.from({length: 12}, (value, index)=>this.tmpYear + index)
            this.$emit('selectDay');
        }
    },
    computed: {
        format (){
            return this.options.format?this.options.format:'YYYY-MM-DD';
        },
        startDate(){
            return this.options.startDate?this.options.startDate:'1970-01-01';
        },
        endDate(){
            return this.options.endDate?this.options.endDate:'5000-01-01';
        },
        language(){
            return this.options.language?this.options.language:'cn';
        },
        range(){
            return this.options.range?this.options.range:false;
        },
        allTimeList(){
            let total=1440,range=this.options.timeRange?this.options.timeRange:13;
            let arr=[];
            for(let i=0;i<Math.ceil(total/range)+1;i++){
                let minite=i*range;
                let tempH=0,tempM=0;
                tempH=Number.parseInt(minite/60);
                tempM=minite-60*tempH;
                if(tempH==24&&tempM>=0){
                    tempH=23;
                    tempM=59;
                }
                tempH=tempH>=10?tempH:'0'+tempH;
                tempM=tempM>=10?tempM:'0'+tempM;
                arr.push({H:tempH,M:tempM})
            }
            return arr
        },
        timeList(){
            return Array.from({length: 12}, (value, index)=>this.allTimeList[index].H+':'+this.allTimeList[index].M)
        },
        orYear (){
            if (this.valueStr != '') {
                return this.tmpYear =this.selectedYear= Number(this.valueStr.split('-')[0])
            } else {
                return new Date().getFullYear();
            }
        },
        orMonth (){
            if (this.valueStr != '') {
                //this.tmpDay = Number(this.valueStr.split('-')[2]);
                /*when month change the day is not ready so set day in month computed*/
                return this.tmpMonth = Number(this.valueStr.split('-')[1] - 1)
            } else {
                this.tmpDay = new Date().getDate();
                return new Date().getMonth();
            }
        },
        orDay (){
            if (this.valueStr != '') {
                return Number(this.valueStr.split('-')[2]);
            } else {
                return new Date().getDate();
            }

        },
        orHour(){
            if (this.valueStr != '') {
                return this.tmpHour = this.selectHour = Number(this.valueStr.split(' ')[1].split(':')[0])
            } else {
                return this.selectHour = new Date().getHours();
            }
        },
        daylist () {
            /* get currentMonthLenght */
            let currentMonthLength = new Date(this.tmpYear, this.tmpMonth + 1, 0).getDate();
            /* get currentMonth day */
            let daylist = Array.from({length: currentMonthLength}, (value, index) => {
                return {
                    currentMonth: true,
                    value: index + 1
                }
            });
            /* get previous day */
            let currentMonthStartDay = new Date(this.tmpYear, this.tmpMonth, 1).getDay();
            let previousMotnhLength = new Date(this.tmpYear, this.tmpMonth - 1, 0).getDate();
            for (let i = 0; i < currentMonthStartDay; i++) {
                daylist = [{previousMonthDay: true, value: previousMotnhLength - i}].concat(daylist)
            }
            /* get nex day */
            for (let i = daylist.length, day = 1; i < 42; i++, day++) {
                daylist[daylist.length] = {nextMonthDay: true, value: day}
            }
            return daylist
        }
    },
    filters:{
        weekF:(item,lang)=>{
            switch(lang){
                case 'cn':
                    return {0: '日', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六'}[item];
                case 'en':
                    return {0: 'Su', 1: 'Mo', 2: 'Tu', 3: 'We', 4: 'Th', 5: 'Fr', 6: 'Sa'}[item];
                default:
                    return item
            }
        },
        monthF:(month,lang)=>{
            switch(lang){
                case 'cn':
                 return {1: '一月', 2: '二月', 3: '三月', 4: '四月', 5: '五月', 6: '六月', 7: '七月',8:'八月',9:'九月',10:'十月',11:'十一月',12:'十二月'}[month];
                case 'en':
                    return {1: 'JAN', 2: 'FEB', 3: 'MAR', 4: 'APR', 5: 'MAY', 6: 'JUN', 7: 'JUL',8:'AUG',9:'SEP',10:'OCT',11:'NOV',12:'DEC'}[month];
                default:
                    return month
            }
        }
    },
    watch: {
        panelType: function (val, oldVal) {
            this.changeTiltle = 'off';
            if (val == 'day' && oldVal == 'hour') {
                this.animatePanel = 'next-panel'
            } else if (val == 'month' && oldVal == 'day') {
                this.animatePanel = 'next-panel'
            } else if (val == 'year' && oldVal == 'month') {
                this.animatePanel = 'next-panel'
            } else if (val == 'month' && oldVal == 'year') {
                this.animatePanel = 'previous-panel'
            } else if (val == 'day' && oldVal == 'month') {
                this.animatePanel = 'previous-panel';
            } else if (val == 'hour' && oldVal == 'day') {
                this.animatePanel = 'previous-panel';
            }
        },
        visible:function(val,oldVal){
            if(val==true){
                setTimeout(() => document.addEventListener('click', this.hideDatePicker), 0)
            }else {
                document.removeEventListener('click', this.hideDatePicker)
            }
        }
    },
}
<commit_msg>format reg<commit_after>/**
 * Created by k186 on 2016/11/11.
 */
export default {
    name: 'kPicker',
    props: {
        valueStr: {
            type: String,
            default: ''
        },
        visible: {
            type:Boolean,
            default:false,
            required:true
        },
        options:{
            type: Object,
        }
    },
    data () {
        let now = new Date();
        return {
            panelType: 'day',
            monthList: [1,2,3,4,5,6,7,8,9,10,11,12],
            weekList: [0,1,2,3,4,5,6],
            yearList: Array.from({length: 12}, (value, index)=>now.getFullYear() + index),
            hourList: Array.from({length: 24}, (value, index)=>0 + index),
            tmpYear: now.getFullYear(),
            tmpMonth: now.getMonth(),
            tmpDay: now.getDate(),
            tmpHour: now.getHours(),
            selectedYear: now.getFullYear(),
            selectedMonth: now.getMonth(),
            selectedDay: now.getDate(),
            selectedHour: now.getHours(),
            animateMonth: 'off',
            animatePanel: 'off',
            animateTitle: 'toggle-title',
            changeTiltle: 'off',
            Format:{
                year:'yyyy',
                month:'M',
                day:'d',
                isHour:false,
                hour:'HH',
                minute:'mm'
            }
        }
    },
    methods: {
        changeType(type){
            this.animateMonth='off';
            this.panelType = type;
            if (type = 'year') {
                this.yearList = Array.from({length: 12}, (value, index)=>this.tmpYear + index)
            }
        },
        changeDay(type){

        },
        changeMonth(type){
            if (type === 'next') {
                this.animateMonth='next-Month';
                this.changeTiltle='next-Title';
                this.tmpMonth += 1;
                if (this.tmpMonth > 11) {
                    this.tmpMonth = 0;
                    this.tmpYear += 1;
                }
            } else if (type === 'previous') {
                this.animateMonth='previous-Month';
                this.changeTiltle='previous-Title';
                this.tmpMonth -= 1;
                if (this.tmpMonth < 0) {
                    this.tmpMonth = 11;
                    this.tmpYear -= 1;
                }
            }
        },
        changeYear(type){
            if (type === 'next') {
                this.tmpYear += 1;
                this.yearList = this.yearList.map((i)=>i + 1);
                this.changeTiltle='next-Title';
                this.animateMonth='next-Month';

            } else if (type === 'previous') {
                this.tmpYear -= 1;
                this.yearList = this.yearList.map((i)=>i - 1);
                this.changeTiltle='previous-Title';
                this.animateMonth='previous-Month';

            }
        },
        changeYearRange(type){
            if (type === 'next') {
                this.yearList = this.yearList.map((i)=>i + 12);
                this.changeTiltle='next-Title';
                this.animateMonth='next-Month';
            } else if (type === 'previous') {
                this.yearList = this.yearList.map((i)=>i - 12);
                this.changeTiltle='previous-Title';
                this.animateMonth='previous-Month';
            }
        },
        selectYear(item){
            if(this.validYear(item)){
                this.tmpYear = item;
                this.changeType('month');
            }
        },
        selectMonth(item){
            if(this.validMonth(item)){
                this.tmpMonth = item;
                this.changeType('day');
            }
        },
        isSelected(type, item){
            switch (type) {
                case 'year':
                    if(this.validYear(item)){
                        if (item == this.orYear) {
                            return true
                        } else {
                            return false
                        }
                    }else {
                        return false
                    }

                case 'month':
                {
                    if(this.validMonth(item)){
                        if (this.orYear==this.tmpYear&&item === this.orMonth) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }

                }
                case 'day':
                {
                    if(this.validDay(item)){
                        if (this.orDay == item.value && this.orMonth === this.tmpMonth && item.currentMonth&&this.orYear==this.tmpYear) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }

                }
                case 'hour': {
                    if (this.validHour(item)) {
                        if (this.orDay == this.tmpDay && this.orMonth === this.tmpMonth && this.orYear == this.tmpYear && item == this.orHour) {
                            return true
                        } else {
                            return false
                        }
                    } else {
                        return false
                    }
                }
            }
        },
        selectDay(item){
            if(this.validDay(item)){
                /*choose currentMonthDay previous nex*/
                if (item.previousMonthDay) {
                    if (this.tmpMonth === 0) {
                        this.tmpYear -= 1;
                        this.tmpMonth = 11;
                    } else {
                        this.tmpMonth -= 1;
                    }
                } else if (item.nextMonthDay) {
                    if (this.tmpMonth == 11) {
                        this.tmpYear += 1;
                        this.tmpMonth = 0;
                    } else {
                        this.tmpMonth += 1;
                    }
                }
                if (!this.range) {
                    this.tmpDay = item.value;
                }
                this.changeType('hour');
                this.$emit('selectDay', this.tmpYear + '-' + Number(this.tmpMonth + 1) + '-' + this.tmpDay)
            }
        },
        validYear(year){
            if (this.startDate.split('-')[0] <= year && year <= this.endDate.split('-')[0]) {
                return true
            } else {
                return false
            }
        },
        validMonth(month){
            let satrDate = new Date(this.startDate.split('-')[0],this.startDate.split('-')[1] - 1).getTime();
            let endDate = new Date(this.endDate.split('-')[0],this.endDate.split('-')[1]- 1).getTime();
            let tempDate = new Date(this.tmpYear, month).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        validDay(day){
            let satrDate = new Date(this.startDate.split('-')[0], this.startDate.split('-')[1] - 1,this.startDate.split('-')[2]).getTime();
            let endDate = new Date(this.endDate.split('-')[0], this.endDate.split('-')[1] - 1,this.endDate.split('-')[2]).getTime();
            let tempDate = new Date(this.tmpYear, this.tmpMonth,day.value).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        validHour(hour){
            let satrDate = new Date(this.startDate.split('-')[0], this.startDate.split('-')[1] - 1, this.startDate.split('-')[2],24).getTime();
            let endDate = new Date(this.endDate.split('-')[0], this.endDate.split('-')[1] - 1, this.endDate.split('-')[2],24).getTime();
            let tempDate = new Date(this.tmpYear, this.tmpMonth, this.tmpDay, hour).getTime();
            if (satrDate <= tempDate && tempDate <= endDate) {
                return true
            }
            else {
                return false
            }
        },
        close(){
            //todo 定位问题 控释显示关闭问题
        },
        hideDatePicker(){
            this.tmpYear=this.orYear;
            this.tmpMonth=this.orMonth;
            this.tmpDay=this.orDay;
            this.panelType='day';
            this.yearList=Array.from({length: 12}, (value, index)=>this.tmpYear + index)
            this.$emit('selectDay');
        },
        setFormat(){
            /*
            * d      without 0
            * dd     with 01
            * M      without 0
            * MM     with 03
            * yy     2016 16
            * yyyy   2016
            * h      12am 12pm 1 2
            * hh     12am 12pm 01 02
            * H      24h 1 2 3
            * HH     24 01 02
            * m      minute 1
            * mm     minute 01
            * */
            let  format=this.format;
            let reg1=/^[yyyy]{4}-?\/?[M,MM]{1,2}-?\/?[d,dd]{1,2}\s[h,hh,H,HH]{1,2}\:[m,mm]{1,2}$|^[yyyy]{4}-?\/?[M,MM]{1,2}-?\/?[d,dd]{1,2}$/;
            let reg2=/^[yyyy]{4}-?\/?[M,MM]{1,2}-?\/?[d,dd]{1,2}\s[h,hh,H,HH]{1,2}\:[m,mm]{1,2}$/;
            let reg3=/^[yyyy]{4}-?\/?[M,MM]{1,2}-?\/?[d,dd]{1,2}$/;
            let reg4=/^\d{4}-\d{1,2}-\d{1,2}\s\d{1,2}\:\d{1,2}$|^\d{4}-\d{1,2}-\d{1,2}$/;
            if(reg1.test(format)&&(format.split('\-').length==3||format.split('\/').length==3)){
                if(reg2.test(format)){
                    let dateArr=format.split('/\s');
                    let yearArr=dateArr[0],hourArr=dateArr[1];
                    this.Format.isHour=true;
                    this.Format.year=yearArr[0];
                    this.Format.month=yearArr[1];
                    this.Format.day=yearArr[2];
                    this.Format.hour=hourArr[0];
                    this.Format.minute=hourArr[1];
                }else if(reg3.test(format)){

                }
            }else {
                throw Error.warn('format is wrong')
            }

        }
    },
    computed: {
        format (){
            return this.options.format?this.options.format:'YYYY-MM-DD HH:mm';
        },
        startDate(){
            return this.options.startDate?this.options.startDate:'1970-01-01';
        },
        endDate(){
            return this.options.endDate?this.options.endDate:'5000-01-01';
        },
        language(){
            return this.options.language?this.options.language:'cn';
        },
        range(){
            return this.options.range?this.options.range:false;
        },
        allTimeList(){
            let total=1440,range=this.options.timeRange?this.options.timeRange:13;
            let arr=[];
            for(let i=0;i<Math.ceil(total/range)+1;i++){
                let minite=i*range;
                let tempH=0,tempM=0;
                tempH=Number.parseInt(minite/60);
                tempM=minite-60*tempH;
                if(tempH==24&&tempM>=0){
                    tempH=23;
                    tempM=59;
                }
                tempH=tempH>=10?tempH:'0'+tempH;
                tempM=tempM>=10?tempM:'0'+tempM;
                arr.push({H:tempH,M:tempM})
            }
            return arr
        },
        timeList(){
            return Array.from({length: 12}, (value, index)=>this.allTimeList[index].H+':'+this.allTimeList[index].M)
        },
        orYear (){
            if (this.valueStr != '') {
                return this.tmpYear =this.selectedYear= Number(this.valueStr.split('-')[0])
            } else {
                return new Date().getFullYear();
            }
        },
        orMonth (){
            if (this.valueStr != '') {
                //this.tmpDay = Number(this.valueStr.split('-')[2]);
                /*when month change the day is not ready so set day in month computed*/
                return this.tmpMonth = Number(this.valueStr.split('-')[1] - 1)
            } else {
                this.tmpDay = new Date().getDate();
                return new Date().getMonth();
            }
        },
        orDay (){
            if (this.valueStr != '') {
                return Number(this.valueStr.split('-')[2]);
            } else {
                return new Date().getDate();
            }

        },
        orHour(){
            if (this.valueStr != '') {
                return this.tmpHour = this.selectHour = Number(this.valueStr.split(' ')[1].split(':')[0])
            } else {
                return this.selectHour = new Date().getHours();
            }
        },
        daylist () {
            /* get currentMonthLenght */
            let currentMonthLength = new Date(this.tmpYear, this.tmpMonth + 1, 0).getDate();
            /* get currentMonth day */
            let daylist = Array.from({length: currentMonthLength}, (value, index) => {
                return {
                    currentMonth: true,
                    value: index + 1
                }
            });
            /* get previous day */
            let currentMonthStartDay = new Date(this.tmpYear, this.tmpMonth, 1).getDay();
            let previousMotnhLength = new Date(this.tmpYear, this.tmpMonth - 1, 0).getDate();
            for (let i = 0; i < currentMonthStartDay; i++) {
                daylist = [{previousMonthDay: true, value: previousMotnhLength - i}].concat(daylist)
            }
            /* get nex day */
            for (let i = daylist.length, day = 1; i < 42; i++, day++) {
                daylist[daylist.length] = {nextMonthDay: true, value: day}
            }
            return daylist
        }
    },
    filters:{
        weekF:(item,lang)=>{
            switch(lang){
                case 'cn':
                    return {0: '日', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六'}[item];
                case 'en':
                    return {0: 'Su', 1: 'Mo', 2: 'Tu', 3: 'We', 4: 'Th', 5: 'Fr', 6: 'Sa'}[item];
                default:
                    return item
            }
        },
        monthF:(month,lang)=>{
            switch(lang){
                case 'cn':
                 return {1: '一月', 2: '二月', 3: '三月', 4: '四月', 5: '五月', 6: '六月', 7: '七月',8:'八月',9:'九月',10:'十月',11:'十一月',12:'十二月'}[month];
                case 'en':
                    return {1: 'JAN', 2: 'FEB', 3: 'MAR', 4: 'APR', 5: 'MAY', 6: 'JUN', 7: 'JUL',8:'AUG',9:'SEP',10:'OCT',11:'NOV',12:'DEC'}[month];
                default:
                    return month
            }
        }
    },
    watch: {
        panelType: function (val, oldVal) {
            this.changeTiltle = 'off';
            if (val == 'day' && oldVal == 'hour') {
                this.animatePanel = 'next-panel'
            } else if (val == 'month' && oldVal == 'day') {
                this.animatePanel = 'next-panel'
            } else if (val == 'year' && oldVal == 'month') {
                this.animatePanel = 'next-panel'
            } else if (val == 'month' && oldVal == 'year') {
                this.animatePanel = 'previous-panel'
            } else if (val == 'day' && oldVal == 'month') {
                this.animatePanel = 'previous-panel';
            } else if (val == 'hour' && oldVal == 'day') {
                this.animatePanel = 'previous-panel';
            }
        },
        visible:function(val,oldVal){
            if(val==true){
                setTimeout(() => document.addEventListener('click', this.hideDatePicker), 0)
            }else {
                document.removeEventListener('click', this.hideDatePicker)
            }
        }
    },
}
<|endoftext|>


<commit_before>(function () {
  'use strict';

  angular.module('exceptionless.filter')
    .factory('filterService', function ($rootScope, dateRangeParserService, filterStoreService, objectIDService, organizationService) {
      var DEFAULT_TIME_FILTER = 'last week';
      var _time = filterStoreService.getTimeFilter() || DEFAULT_TIME_FILTER;
      var _eventType, _organizationId, _projectId, _raw;

      function apply(source, includeHiddenAndFixedFilter) {
        return angular.extend({}, getDefaultOptions(includeHiddenAndFixedFilter), source);
      }

      function buildFilter(includeHiddenAndFixedFilter) {
        includeHiddenAndFixedFilter = (typeof includeHiddenAndFixedFilter !== 'undefined') ?  includeHiddenAndFixedFilter : true;
        var filters = [];

        if (_organizationId) {
          filters.push('organization:' + _organizationId);
        }

        if (_projectId) {
          filters.push('project:' + _projectId);
        }

        if (_eventType) {
          filters.push('type:' + _eventType);
        }

        var filter = _raw || '';
        var isWildCardFilter = filter.trim() === '*';
        if (includeHiddenAndFixedFilter && !isWildCardFilter) {
          var hasFixed = filter.search(/\bfixed:/i) !== -1;
          if (!hasFixed) {
            filters.push('fixed:false');
          }

          var hasHidden = filter.search(/\bhidden:/i) !== -1;
          if (!hasHidden) {
            filters.push('hidden:false');
          }
        }

        if (!!filter && !isWildCardFilter) {
          filters.push('(' + filter + ')');
        }

        return filters.join(' ').trim();
      }

      function clearFilter() {
        if (!_raw) {
          return;
        }

        setFilter(null, false);
        fireFilterChanged();
      }

      function clearOrganizationAndProjectFilter() {
        if (!_organizationId && !_projectId) {
          return;
        }

        _organizationId = _projectId = null;
        fireFilterChanged();
      }

      function fireFilterChanged(includeHiddenAndFixedFilter) {
        var options = {
          organization_id: _organizationId,
          project_id: _projectId,
          type: _eventType
        };

        $rootScope.$emit('filterChanged', angular.extend(options, getDefaultOptions(includeHiddenAndFixedFilter)));
      }

      function getDefaultOptions(includeHiddenAndFixedFilter) {
        var options = {};

        var offset = getTimeOffset();
        if (offset) {
          angular.extend(options, { offset: offset });
        }

        var filter = buildFilter(includeHiddenAndFixedFilter);
        if (filter) {
          angular.extend(options, { filter: filter });
        }

        if (!!_time && _time !== 'all') {
          angular.extend(options, { time: _time });
        }

        return options;
      }

      function getFilter() {
        return _raw;
      }

      function getProjectId() {
        return _projectId;
      }

      function getOrganizationId() {
        return _organizationId;
      }

      function getEventType() {
        return _eventType;
      }

      function getOldestPossibleEventDate() {
        var date = objectIDService.getDate(getOrganizationId() || getProjectId());
        return date ? moment(date).subtract(3, 'days').toDate() : new Date(2012, 1, 1);
      }

      function getTime() {
        return _time || DEFAULT_TIME_FILTER;
      }

      function getTimeRange() {
        var time = getTime();
        if (time === 'all') {
          return { start: undefined, end: undefined };
        }

        if (time === 'last hour') {
          return { start: moment().subtract(1, 'hours'), end: undefined };
        }

        if (time === 'last 24 hours') {
          return { start: moment().subtract(24, 'hours'), end: undefined };
        }

        if (time === 'last week') {
          return { start: moment().subtract(7, 'days').startOf('day'), end: undefined };
        }

        if (time === 'last 30 days') {
          return { start: moment().subtract(30, 'days').startOf('day'), end: undefined };
        }

        var range = dateRangeParserService.parse(time);
        if (range && range.start && range.end) {
          return { start: moment(range.start), end: moment(range.end) };
        }

        return { start: moment().subtract(7, 'days').startOf('day'), end: undefined };
      }

      function getTimeOffset() {
        var offset = new Date().getTimezoneOffset();
        return offset !== 0 ? offset * -1 + 'm' : undefined;
      }

      function hasFilter() {
        return _raw || (_time && _time !== 'all');
      }

      function includedInProjectOrOrganizationFilter(data) {
        if (!data.organizationId && !data.projectId) {
          return false;
        }

        // The all filter is set.
        if (!_organizationId && !_projectId) {
          return true;
        }

        return _organizationId === data.organizationId || _projectId === data.projectId;
      }

      function setEventType(eventType, suspendNotifications) {
        if (angular.equals(eventType, _eventType)) {
          return;
        }

        _eventType = eventType;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setOrganizationId(id, suspendNotifications) {
        if (angular.equals(id, _organizationId) || (id && !objectIDService.isValid(id))) {
          return;
        }

        _organizationId = id;
        _projectId = null;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setProjectId(id, suspendNotifications) {
        if (angular.equals(id, _projectId) || (id && !objectIDService.isValid(id))) {
          return;
        }

        _projectId = id;
        _organizationId = null;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setTime(time, suspendNotifications) {
        if (angular.equals(time, _time)) {
          return;
        }

        _time = time || DEFAULT_TIME_FILTER;
        filterStoreService.setTimeFilter(_time);

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setFilter(raw, suspendNotifications) {
        if (angular.equals(raw, _raw)) {
          return;
        }

        _raw = raw;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      $rootScope.$on('OrganizationChanged', function ($event, organizationChanged) {
        if (organizationChanged.id === getOrganizationId() &&  organizationChanged.deleted) {
          setOrganizationId();
        }
      });

      $rootScope.$on('ProjectChanged', function ($event, projectChanged) {
        if (projectChanged.id === getProjectId() &&  projectChanged.deleted) {
          setProjectId();
        }
      });

      var service = {
        apply: apply,
        clearFilter: clearFilter,
        clearOrganizationAndProjectFilter: clearOrganizationAndProjectFilter,
        fireFilterChanged: fireFilterChanged,
        getEventType: getEventType,
        getFilter: getFilter,
        getProjectId: getProjectId,
        getOrganizationId: getOrganizationId,
        getOldestPossibleEventDate: getOldestPossibleEventDate,
        getTime: getTime,
        getTimeRange: getTimeRange,
        getTimeOffset: getTimeOffset,
        hasFilter: hasFilter,
        includedInProjectOrOrganizationFilter: includedInProjectOrOrganizationFilter,
        setEventType: setEventType,
        setFilter: setFilter,
        setOrganizationId: setOrganizationId,
        setProjectId: setProjectId,
        setTime: setTime
      };

      return service;
    });
}());
<commit_msg>Update default stack filter to exclude fixed, discarded, ignored or snoozed statuses<commit_after>(function () {
  'use strict';

  angular.module('exceptionless.filter')
    .factory('filterService', function ($rootScope, dateRangeParserService, filterStoreService, objectIDService, organizationService) {
      var DEFAULT_TIME_FILTER = 'last week';
      var _time = filterStoreService.getTimeFilter() || DEFAULT_TIME_FILTER;
      var _eventType, _organizationId, _projectId, _raw;

      function apply(source, includeDiscardedFixedIgnoredSnoozedFilter) {
        return angular.extend({}, getDefaultOptions(includeDiscardedFixedIgnoredSnoozedFilter), source);
      }

      function buildFilter(includeDiscardedFixedIgnoredSnoozedFilter) {
        includeDiscardedFixedIgnoredSnoozedFilter = (typeof includeDiscardedFixedIgnoredSnoozedFilter !== 'undefined') ?  includeDiscardedFixedIgnoredSnoozedFilter : true;
        var filters = [];

        if (_organizationId) {
          filters.push('organization:' + _organizationId);
        }

        if (_projectId) {
          filters.push('project:' + _projectId);
        }

        if (_eventType) {
          filters.push('type:' + _eventType);
        }

        var filter = _raw || '';
        var isWildCardFilter = filter.trim() === '*';
        if (includeDiscardedFixedIgnoredSnoozedFilter && !isWildCardFilter) {
          var hasStatus = filter.search(/\bstatus:/i) !== -1;
          if (!hasStatus) {
            filters.push('status:open', 'status:regressed');
          }
        }

        if (!!filter && !isWildCardFilter) {
          filters.push('(' + filter + ')');
        }

        return filters.join(' ').trim();
      }

      function clearFilter() {
        if (!_raw) {
          return;
        }

        setFilter(null, false);
        fireFilterChanged();
      }

      function clearOrganizationAndProjectFilter() {
        if (!_organizationId && !_projectId) {
          return;
        }

        _organizationId = _projectId = null;
        fireFilterChanged();
      }

      function fireFilterChanged(includeHiddenAndFixedFilter) {
        var options = {
          organization_id: _organizationId,
          project_id: _projectId,
          type: _eventType
        };

        $rootScope.$emit('filterChanged', angular.extend(options, getDefaultOptions(includeHiddenAndFixedFilter)));
      }

      function getDefaultOptions(includeHiddenAndFixedFilter) {
        var options = {};

        var offset = getTimeOffset();
        if (offset) {
          angular.extend(options, { offset: offset });
        }

        var filter = buildFilter(includeHiddenAndFixedFilter);
        if (filter) {
          angular.extend(options, { filter: filter });
        }

        if (!!_time && _time !== 'all') {
          angular.extend(options, { time: _time });
        }

        return options;
      }

      function getFilter() {
        return _raw;
      }

      function getProjectId() {
        return _projectId;
      }

      function getOrganizationId() {
        return _organizationId;
      }

      function getEventType() {
        return _eventType;
      }

      function getOldestPossibleEventDate() {
        var date = objectIDService.getDate(getOrganizationId() || getProjectId());
        return date ? moment(date).subtract(3, 'days').toDate() : new Date(2012, 1, 1);
      }

      function getTime() {
        return _time || DEFAULT_TIME_FILTER;
      }

      function getTimeRange() {
        var time = getTime();
        if (time === 'all') {
          return { start: undefined, end: undefined };
        }

        if (time === 'last hour') {
          return { start: moment().subtract(1, 'hours'), end: undefined };
        }

        if (time === 'last 24 hours') {
          return { start: moment().subtract(24, 'hours'), end: undefined };
        }

        if (time === 'last week') {
          return { start: moment().subtract(7, 'days').startOf('day'), end: undefined };
        }

        if (time === 'last 30 days') {
          return { start: moment().subtract(30, 'days').startOf('day'), end: undefined };
        }

        var range = dateRangeParserService.parse(time);
        if (range && range.start && range.end) {
          return { start: moment(range.start), end: moment(range.end) };
        }

        return { start: moment().subtract(7, 'days').startOf('day'), end: undefined };
      }

      function getTimeOffset() {
        var offset = new Date().getTimezoneOffset();
        return offset !== 0 ? offset * -1 + 'm' : undefined;
      }

      function hasFilter() {
        return _raw || (_time && _time !== 'all');
      }

      function includedInProjectOrOrganizationFilter(data) {
        if (!data.organizationId && !data.projectId) {
          return false;
        }

        // The all filter is set.
        if (!_organizationId && !_projectId) {
          return true;
        }

        return _organizationId === data.organizationId || _projectId === data.projectId;
      }

      function setEventType(eventType, suspendNotifications) {
        if (angular.equals(eventType, _eventType)) {
          return;
        }

        _eventType = eventType;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setOrganizationId(id, suspendNotifications) {
        if (angular.equals(id, _organizationId) || (id && !objectIDService.isValid(id))) {
          return;
        }

        _organizationId = id;
        _projectId = null;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setProjectId(id, suspendNotifications) {
        if (angular.equals(id, _projectId) || (id && !objectIDService.isValid(id))) {
          return;
        }

        _projectId = id;
        _organizationId = null;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setTime(time, suspendNotifications) {
        if (angular.equals(time, _time)) {
          return;
        }

        _time = time || DEFAULT_TIME_FILTER;
        filterStoreService.setTimeFilter(_time);

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      function setFilter(raw, suspendNotifications) {
        if (angular.equals(raw, _raw)) {
          return;
        }

        _raw = raw;

        if (!suspendNotifications) {
          fireFilterChanged();
        }
      }

      $rootScope.$on('OrganizationChanged', function ($event, organizationChanged) {
        if (organizationChanged.id === getOrganizationId() &&  organizationChanged.deleted) {
          setOrganizationId();
        }
      });

      $rootScope.$on('ProjectChanged', function ($event, projectChanged) {
        if (projectChanged.id === getProjectId() &&  projectChanged.deleted) {
          setProjectId();
        }
      });

      var service = {
        apply: apply,
        clearFilter: clearFilter,
        clearOrganizationAndProjectFilter: clearOrganizationAndProjectFilter,
        fireFilterChanged: fireFilterChanged,
        getEventType: getEventType,
        getFilter: getFilter,
        getProjectId: getProjectId,
        getOrganizationId: getOrganizationId,
        getOldestPossibleEventDate: getOldestPossibleEventDate,
        getTime: getTime,
        getTimeRange: getTimeRange,
        getTimeOffset: getTimeOffset,
        hasFilter: hasFilter,
        includedInProjectOrOrganizationFilter: includedInProjectOrOrganizationFilter,
        setEventType: setEventType,
        setFilter: setFilter,
        setOrganizationId: setOrganizationId,
        setProjectId: setProjectId,
        setTime: setTime
      };

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


<commit_before>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import classnames from 'classnames';

/**
 * The RadioButtonGroup component
 */
class RadioButtonGroup extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // generate a unique ID for this element (used to tie the label to the
        // input elements)
        //
        this.id = uniqueId('form-radiobuttongroup-');

        // build a list of permitted values from the options
        //
        this.permittedValues = this.props.options.map((opt) => `${opt.value}`);

        // initialize the component state
        //
        this.state = {
            value: this.isPermittedValue(this.props.value)
                ? `${this.props.value}`
                : `${this.props.options[0].value}`,
        };

        // bind `this` to the onChange event handler
        //
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle a change to the input elements
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the current value & make sure it's a string
        //
        const value = `${event.target.value}`;

        // has the value changed? if so, then update the state & call the
        // onChange handler
        //
        if (value !== this.state.value) {
            // update the component state
            //
            this.setState({ value });

            // do we have an onChange handler? if so, call it
            //
            if (this.props.onChange) {
                this.props.onChange(value);
            }
        }
    }

    /**
     * Check a value to see if it's one of the permitted values
     * @param  {String}  value The value to check
     * @return {Boolean}       True if it's a permitted value; false otherwise
     */
    isPermittedValue(value) {
        return this.permittedValues.findIndex((val) => val === `${value}`) !== -1;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // get the important values from the component properties
        //
        const { label, options } = this.props;

        // render the label element for the component
        //
        const labelElement = label
            ? (<label
                htmlFor={this.id}
                className={classnames('control-label', {
                    [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                })}
            >{label})
            : null;

        // render the set of radio button elements for the component
        //
        let radios = options.map((opt) => (

                    <input
                        type="radio"
                        name={this.id}
                        value={opt.value}
                        checked={this.state.value === opt.value}
                        onChange={this.onChange}
                    />
                    {opt.name}

        ));

        // do we have columns for this component? if so, wrap the radio buttons
        // in a div to implement the columns
        //
        if (this.context.labelColumns) {
            radios = (
                <div
                    className={classnames(
                        'form-radiobuttongroup-input-columns',
                        `col-xs-${12 - this.context.labelColumns}`
                    )}
                >
                    {radios}

            );
        }

        // render the whole component & return it
        //
        return (

                {labelElement}

                {radios}

        );
    }
}

/**
 * The property types for the component
 * @type {Object}
 */
RadioButtonGroup.propTypes = {
    label:    React.PropTypes.string,
    options:  React.PropTypes.array,
    value:    React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange: React.PropTypes.func,
};

/**
 * The context types for the component
 * @type {Object}
 */
RadioButtonGroup.contextTypes = {
    labelColumns:           React.PropTypes.number,
};

// export the component
//
export default RadioButtonGroup;
<commit_msg>added disabled flag to proptypes<commit_after>// dependencies
//
import React from 'react';
import uniqueId from 'lodash/uniqueId';
import classnames from 'classnames';

/**
 * The RadioButtonGroup component
 */
class RadioButtonGroup extends React.Component {
    /**
     * Construct the component instance
     * @param  {Object} props The component props
     */
    constructor(props) {
        super(props);

        // generate a unique ID for this element (used to tie the label to the
        // input elements)
        //
        this.id = uniqueId('form-radiobuttongroup-');

        // build a list of permitted values from the options
        //
        this.permittedValues = this.props.options.map((opt) => `${opt.value}`);

        // initialize the component state
        //
        this.state = {
            value: this.isPermittedValue(this.props.value)
                ? `${this.props.value}`
                : `${this.props.options[0].value}`,
        };

        // bind `this` to the onChange event handler
        //
        this.onChange = this.onChange.bind(this);
    }

    /**
     * Handle a change to the input elements
     * @param  {Object} event The event object
     */
    onChange(event) {
        // get the current value & make sure it's a string
        //
        const value = `${event.target.value}`;

        // has the value changed? if so, then update the state & call the
        // onChange handler
        //
        if (value !== this.state.value) {
            // update the component state
            //
            this.setState({ value });

            // do we have an onChange handler? if so, call it
            //
            if (this.props.onChange) {
                this.props.onChange(value);
            }
        }
    }

    /**
     * Check a value to see if it's one of the permitted values
     * @param  {String}  value The value to check
     * @return {Boolean}       True if it's a permitted value; false otherwise
     */
    isPermittedValue(value) {
        return this.permittedValues.findIndex((val) => val === `${value}`) !== -1;
    }

    /**
     * Render the component
     * @return {React.Element} The React element describing the component
     */
    render() {
        // get the important values from the component properties
        //
        const { label, options } = this.props;

        // render the label element for the component
        //
        const labelElement = label
            ? (<label
                htmlFor={this.id}
                className={classnames('control-label', {
                    [`col-xs-${this.context.labelColumns}`]: this.context.labelColumns,
                })}
            >{label})
            : null;

        // render the set of radio button elements for the component
        //
        let radios = options.map((opt) => (

                    <input
                        type="radio"
                        name={this.id}
                        value={opt.value}
                        checked={this.state.value === opt.value}
                        onChange={this.onChange}
                    />
                    {opt.name}

        ));

        // do we have columns for this component? if so, wrap the radio buttons
        // in a div to implement the columns
        //
        if (this.context.labelColumns) {
            radios = (
                <div
                    className={classnames(
                        'form-radiobuttongroup-input-columns',
                        `col-xs-${12 - this.context.labelColumns}`
                    )}
                >
                    {radios}

            );
        }

        // render the whole component & return it
        //
        return (

                {labelElement}

                {radios}

        );
    }
}

/**
 * The property types for the component
 * @type {Object}
 */
RadioButtonGroup.propTypes = {
    label:    React.PropTypes.string,
    disabled: React.PropTypes.bool,
    options:  React.PropTypes.array,
    value:    React.PropTypes.oneOfType([
        React.PropTypes.string,
        React.PropTypes.number,
    ]),
    onChange: React.PropTypes.func,
};

/**
 * The context types for the component
 * @type {Object}
 */
RadioButtonGroup.contextTypes = {
    labelColumns:           React.PropTypes.number,
};

// export the component
//
export default RadioButtonGroup;
<|endoftext|>


<commit_before>import _forOwn from "lodash/forOwn";
import _map from "lodash/map";
import _minBy from "lodash/minBy";
import { interpolateNumber } from "d3-interpolate";
import { averageColors, averageColorsDict } from "../../util/colorHelpers";
import { bezier } from "./transmissionBezier";
import { NODE_NOT_VISIBLE } from "../../util/globals";
import { getTraitFromNode } from "../../util/treeMiscHelpers";

/* global L */
// L is global in scope and placed by leaflet()

// longs of original map are -180 to 180
// longs of fully triplicated map are -540 to 540
// restrict to longs between -360 to 360
const westBound = -360;
const eastBound = 360;

// interchange. this is a leaflet method that will tell d3 where to draw.
const leafletLatLongToLayerPoint = (lat, long, map) => {
  return map.latLngToLayerPoint(new L.LatLng(lat, long));
};

/* if transmission pair is legal, return a leaflet LatLng origin / dest pair
otherwise return null */
const maybeGetTransmissionPair = (latOrig, longOrig, latDest, longDest, map) => {

  // if either origin or destination are inside bounds, include
  // transmission must be less than 180 lat difference
  let pair = null;
  if (
    (longOrig > westBound || longDest > westBound) &&
    (longOrig < eastBound || longDest < eastBound) &&
    (Math.abs(longOrig - longDest) < 180)
  ) {
    pair = [
      leafletLatLongToLayerPoint(latOrig, longOrig, map),
      leafletLatLongToLayerPoint(latDest, longDest, map)
    ];
  }

  return pair;

};

const getDemeColors = (nodes, visibility, geoResolution, nodeColors) => {
  // do aggregation as intermediate step
  const demeMap = {};
  nodes.forEach((n) => {
    if (!n.children) {
      const location = getTraitFromNode(n, geoResolution);
      if (location) { // check for undefined
        if (!demeMap[location]) {
          demeMap[location] = {};
        }
      }
    }
  });

  // second pass to fill vectors
  nodes.forEach((n, i) => {
    /* demes only count terminal nodes */
    if (!n.children && visibility[i] !== NODE_NOT_VISIBLE) {
      // if tip and visible, push
      const location = getTraitFromNode(n, geoResolution);
      if (location) { // check for undefined
        if (demeMap[location][nodeColors[i]]){
          demeMap[location][nodeColors[i]] += 1;
        }else{
          demeMap[location][nodeColors[i]] = 1;
        }
      }
    }
  });
  return demeMap;
}

const setupDemeData = (nodes, visibility, geoResolution, nodeColors, triplicate, metadata, map) => {

  const demeData = []; /* deme array */
  const demeIndices = {}; /* map of name to indices in array */

  const demeMap = getDemeColors(nodes, visibility, geoResolution, nodeColors);

  const offsets = triplicate ? [-360, 0, 360] : [0];
  const geo = metadata.geographicInfo;

  let index = 0;
  offsets.forEach((OFFSET) => {
    /* count DEMES */
    _forOwn(demeMap, (value, key) => { // value: hash color array, key: deme name
      let lat = 0;
      let long = 0;
      let goodDeme = true;
      if (geo[geoResolution][key]) {
        lat = geo[geoResolution][key].latitude;
        long = geo[geoResolution][key].longitude + OFFSET;
      } else {
        goodDeme = false;
        console.warn("Warning: Lat/long missing from metadata for", key);
      }
      if (long > westBound && long < eastBound && goodDeme === true) {
        const total = Object.values(value).reduce((a,b)=>a+b);
        const deme = {
          name: key,
          count: total,
          color: averageColorsDict(value),
          latitude: lat, // raw latitude value
          longitude: long, // raw longitude value
          coords: leafletLatLongToLayerPoint(lat, long, map) // coords are x,y plotted via d3
        };
        demeData.push(deme);

        if (!demeIndices[key]) {
          demeIndices[key] = [index];
        } else {
          demeIndices[key].push(index);
        }
        index += 1;

      }
    });
  });

  return {
    demeData: demeData,
    demeIndices: demeIndices
  };
};

const constructBcurve = (
  originLatLongPair,
  destinationLatLongPair,
  extend
) => {
  return bezier(originLatLongPair, destinationLatLongPair, extend);
};

const maybeConstructTransmissionEvent = (
  node,
  child,
  metadataGeoLookupTable,
  geoResolution,
  nodeColors,
  visibility,
  map,
  offsetOrig,
  offsetDest,
  demesMissingLatLongs,
  extend
) => {
  let latOrig, longOrig, latDest, longDest;
  let transmission;
  /* checking metadata for lat longs name match - ie., does the metadata list a latlong for Thailand? */
  const nodeLocation = getTraitFromNode(node, geoResolution); //  we're looking this up in the metadata lookup table
  const childLocation = getTraitFromNode(child, geoResolution);
  try {
    latOrig = metadataGeoLookupTable[geoResolution][nodeLocation].latitude;
    longOrig = metadataGeoLookupTable[geoResolution][nodeLocation].longitude;
  } catch (e) {
    demesMissingLatLongs.add(nodeLocation);
  }
  try {
    latDest = metadataGeoLookupTable[geoResolution][childLocation].latitude;
    longDest = metadataGeoLookupTable[geoResolution][childLocation].longitude;
  } catch (e) {
    demesMissingLatLongs.add(childLocation);
  }

  const validLatLongPair = maybeGetTransmissionPair(
    latOrig,
    longOrig + offsetOrig,
    latDest,
    longDest + offsetDest,
    map
  );

  if (validLatLongPair) {

    const Bcurve = constructBcurve(validLatLongPair[0], validLatLongPair[1], extend);

    /* set up interpolator with origin and destination numdates */
    const interpolator = interpolateNumber(node.num_date.value, child.num_date.value);

    /* make a Bdates array as long as Bcurve */
    const Bdates = [];
    Bcurve.forEach((d, i) => {
      /* fill it with interpolated dates */
      Bdates.push(
        interpolator(i / (Bcurve.length - 1)) /* ie., 5 / 15ths of the way through = 2016.3243 */
      );
    });

    /* build up transmissions object */
    transmission = {
      id: node.arrayIdx.toString() + "-" + child.arrayIdx.toString(),
      originNode: node,
      destinationNode: child,
      bezierCurve: Bcurve,
      bezierDates: Bdates,
      originName: getTraitFromNode(node, geoResolution),
      destinationName: getTraitFromNode(child, geoResolution),
      originCoords: validLatLongPair[0], // after interchange
      destinationCoords: validLatLongPair[1], // after interchange
      originLatitude: latOrig, // raw latitude value
      destinationLatitude: latDest, // raw latitude value
      originLongitude: longOrig + offsetOrig, // raw longitude value
      destinationLongitude: longDest + offsetDest, // raw longitude value
      originNumDate: node.num_date.value,
      destinationNumDate: child.num_date.value,
      color: nodeColors[node.arrayIdx],
      visible: visibility[child.arrayIdx] !== NODE_NOT_VISIBLE ? "visible" : "hidden", // transmission visible if child is visible
      extend: extend
    };
  }
  return transmission;
};

const maybeGetClosestTransmissionEvent = (
  node,
  child,
  metadataGeoLookupTable,
  geoResolution,
  nodeColors,
  visibility,
  map,
  offsetOrig,
  demesMissingLatLongs,
  extend
) => {
  const possibleEvents = [];
  // iterate over offsets applied to transmission destination
  // even if map is not tripled - ie., don't let a line go across the whole world
  [-360, 0, 360].forEach((offsetDest) => {
    const t = maybeConstructTransmissionEvent(
      node,
      child,
      metadataGeoLookupTable,
      geoResolution,
      nodeColors,
      visibility,
      map,
      offsetOrig,
      offsetDest,
      demesMissingLatLongs,
      extend
    );
    if (t) { possibleEvents.push(t); }
  });

  if (possibleEvents.length > 0) {

    const closestEvent = _minBy(possibleEvents, (event) => {
      return Math.abs(event.destinationCoords.x - event.originCoords.x);
    });
    return closestEvent;

  }

  return null;

};

const setupTransmissionData = (
  nodes,
  visibility,
  geoResolution,
  nodeColors,
  triplicate,
  metadata,
  map
) => {

  const offsets = triplicate ? [-360, 0, 360] : [0];
  const metadataGeoLookupTable = metadata.geographicInfo;
  const transmissionData = []; /* edges, animation paths */
  const transmissionIndices = {}; /* map of transmission id to array of indices */
  const demesMissingLatLongs = new Set();
  const demeToDemeCounts = {};
  nodes.forEach((n) => {
    const nodeDeme = getTraitFromNode(n, geoResolution);
    if (n.children) {
      n.children.forEach((child) => {
        const childDeme = getTraitFromNode(child, geoResolution);
        if (nodeDeme && childDeme && nodeDeme !== childDeme) {
          // record transmission event
          if ([nodeDeme, childDeme] in demeToDemeCounts) {
            demeToDemeCounts[[nodeDeme, childDeme]] += 1;
          } else {
            demeToDemeCounts[[nodeDeme, childDeme]] = 1;
          }
          const extend = demeToDemeCounts[[nodeDeme, childDeme]];
          // offset is applied to transmission origin
          offsets.forEach((offsetOrig) => {
            const t = maybeGetClosestTransmissionEvent(
              n,
              child,
              metadataGeoLookupTable,
              geoResolution,
              nodeColors,
              visibility,
              map,
              offsetOrig,
              demesMissingLatLongs,
              extend
            );
            if (t) { transmissionData.push(t); }
          });
        }
      });
    }
  });

  transmissionData.forEach((transmission, index) => {
    if (!transmissionIndices[transmission.id]) {
      transmissionIndices[transmission.id] = [index];
    } else {
      transmissionIndices[transmission.id].push(index);
    }
  });
  return {
    transmissionData: transmissionData,
    transmissionIndices: transmissionIndices,
    demesMissingLatLongs
  };
};

export const createDemeAndTransmissionData = (
  nodes,
  visibility,
  geoResolution,
  nodeColors,
  triplicate,
  metadata,
  map
) => {

  /*
    walk through nodes and collect all data
    for demeData we have:
      name, coords, count, color
    for transmissionData we have:
      originNode, destinationNode, originCoords, destinationCoords, originName, destinationName
      originNumDate, destinationNumDate, color, visible
  */
  const {
    demeData,
    demeIndices
  } = setupDemeData(nodes, visibility, geoResolution, nodeColors, triplicate, metadata, map);

  /* second time so that we can get Bezier */
  const { transmissionData, transmissionIndices, demesMissingLatLongs } = setupTransmissionData(
    nodes,
    visibility,
    geoResolution,
    nodeColors,
    triplicate,
    metadata,
    map
  );

  return {
    demeData: demeData,
    transmissionData: transmissionData,
    demeIndices: demeIndices,
    transmissionIndices: transmissionIndices,
    demesMissingLatLongs
  };
};

/* ******************************
********************************
UPDATE DEMES & TRANSMISSIONS
********************************
******************************* */

const updateDemeDataColAndVis = (demeData, demeIndices, nodes, visibility, geoResolution, nodeColors) => {

  const demeDataCopy = demeData.slice();

  const demeMap = getDemeColors(nodes, visibility, geoResolution, nodeColors);

  // update demeData, for each deme, update all elements via demeIndices lookup
  _forOwn(demeMap, (value, key) => { // value: hash color array, key: deme name
    const name = key;
    const total = Object.values(value).reduce((a,b)=>a+b);
    demeIndices[name].forEach((index) => {
      demeDataCopy[index].count = total;
      demeDataCopy[index].color = averageColorsDict(value);
    });
  });
  return demeDataCopy;
};

const updateTransmissionDataColAndVis = (transmissionData, transmissionIndices, nodes, visibility, geoResolution, nodeColors) => {
  const transmissionDataCopy = transmissionData.slice(); /* basically, instead of _.map() since we're not mapping over the data we're mutating */
  nodes.forEach((node) => {
    if (node.children) {
      node.children.forEach((child) => {
        const nodeLocation = getTraitFromNode(node, geoResolution);
        const childLocation = getTraitFromNode(node, geoResolution);
        if (nodeLocation && childLocation && nodeLocation !== childLocation) {
          // this is a transmission event from n to child
          const id = node.arrayIdx.toString() + "-" + child.arrayIdx.toString();
          const col = nodeColors[node.arrayIdx];
          const vis = visibility[child.arrayIdx] !== NODE_NOT_VISIBLE ? "visible" : "hidden"; // transmission visible if child is visible

          // update transmissionData via index lookup
          try {
            transmissionIndices[id].forEach((index) => {
              transmissionDataCopy[index].color = col;
              transmissionDataCopy[index].visible = vis;
            });
          } catch (err) {
            console.warn(`Error trying to access ${id} in transmissionIndices. Map transmissions may be wrong.`);
          }
        }
      });
    }
  });
  return transmissionDataCopy;
};

export const updateDemeAndTransmissionDataColAndVis = (demeData, transmissionData, demeIndices, transmissionIndices, nodes, visibility, geoResolution, nodeColors) => {
  /*
    walk through nodes and update attributes that can mutate
    for demeData we have:
      count, color
    for transmissionData we have:
      color, visible
  */

  let newDemes;
  let newTransmissions;

  if (demeData && transmissionData) {
    newDemes = updateDemeDataColAndVis(demeData, demeIndices, nodes, visibility, geoResolution, nodeColors);
    newTransmissions = updateTransmissionDataColAndVis(transmissionData, transmissionIndices, nodes, visibility, geoResolution, nodeColors);
  }
  return {newDemes, newTransmissions};
};

/* ********************
**********************
ZOOM LEVEL CHANGE
**********************
********************* */

const updateDemeDataLatLong = (demeData, map) => {

  // interchange for all demes
  return _map(demeData, (d) => {
    d.coords = leafletLatLongToLayerPoint(d.latitude, d.longitude, map);
    return d;
  });

};

const updateTransmissionDataLatLong = (transmissionData, map) => {

  const transmissionDataCopy = transmissionData.slice(); /* basically, instead of _.map() since we're not mapping over the data we're mutating */

  // interchange for all transmissions
  transmissionDataCopy.forEach((transmission) => {
    transmission.originCoords = leafletLatLongToLayerPoint(transmission.originLatitude, transmission.originLongitude, map);
    transmission.destinationCoords = leafletLatLongToLayerPoint(transmission.destinationLatitude, transmission.destinationLongitude, map);
    transmission.bezierCurve = constructBcurve(
      transmission.originCoords,
      transmission.destinationCoords,
      transmission.extend
    );
  });

  return transmissionDataCopy;

};

export const updateDemeAndTransmissionDataLatLong = (demeData, transmissionData, map) => {

  /*
    walk through nodes and update attributes that can mutate
    for demeData we have:
      count, color
    for transmissionData we have:
      color, visible
  */

  let newDemes;
  let newTransmissions;

  if (demeData && transmissionData) {
    newDemes = updateDemeDataLatLong(demeData, map);
    newTransmissions = updateTransmissionDataLatLong(transmissionData, map);
  }

  return {
    newDemes,
    newTransmissions
  };
};
<commit_msg>compute arcs using d3<commit_after>import _forOwn from "lodash/forOwn";
import _map from "lodash/map";
import _minBy from "lodash/minBy";
import { interpolateNumber } from "d3-interpolate";
import { averageColors, averageColorsDict } from "../../util/colorHelpers";
import { bezier } from "./transmissionBezier";
import { NODE_NOT_VISIBLE } from "../../util/globals";
import { getTraitFromNode } from "../../util/treeMiscHelpers";
import { pie } from "d3-shape";

/* global L */
// L is global in scope and placed by leaflet()

// longs of original map are -180 to 180
// longs of fully triplicated map are -540 to 540
// restrict to longs between -360 to 360
const westBound = -360;
const eastBound = 360;

// interchange. this is a leaflet method that will tell d3 where to draw.
const leafletLatLongToLayerPoint = (lat, long, map) => {
  return map.latLngToLayerPoint(new L.LatLng(lat, long));
};

/* if transmission pair is legal, return a leaflet LatLng origin / dest pair
otherwise return null */
const maybeGetTransmissionPair = (latOrig, longOrig, latDest, longDest, map) => {

  // if either origin or destination are inside bounds, include
  // transmission must be less than 180 lat difference
  let pair = null;
  if (
    (longOrig > westBound || longDest > westBound) &&
    (longOrig < eastBound || longDest < eastBound) &&
    (Math.abs(longOrig - longDest) < 180)
  ) {
    pair = [
      leafletLatLongToLayerPoint(latOrig, longOrig, map),
      leafletLatLongToLayerPoint(latDest, longDest, map)
    ];
  }

  return pair;

};

const getDemeColors = (nodes, visibility, geoResolution, nodeColors) => {
  // do aggregation as intermediate step
  const demeMap = {};
  nodes.forEach((n) => {
    if (!n.children) {
      const location = getTraitFromNode(n, geoResolution);
      if (location) { // check for undefined
        if (!demeMap[location]) {
          demeMap[location] = {};
        }
      }
    }
  });

  // second pass to fill vectors
  nodes.forEach((n, i) => {
    /* demes only count terminal nodes */
    if (!n.children && visibility[i] !== NODE_NOT_VISIBLE) {
      // if tip and visible, push
      const location = getTraitFromNode(n, geoResolution);
      if (location) { // check for undefined
        if (demeMap[location][nodeColors[i]]){
          demeMap[location][nodeColors[i]] += 1;
        }else{
          demeMap[location][nodeColors[i]] = 1;
        }
      }
    }
  });
  return demeMap;
}

const setupDemeData = (nodes, visibility, geoResolution, nodeColors, triplicate, metadata, map) => {

  const demeData = []; /* deme array */
  const demeIndices = {}; /* map of name to indices in array */

  const demeMap = getDemeColors(nodes, visibility, geoResolution, nodeColors);

  const offsets = triplicate ? [-360, 0, 360] : [0];
  const geo = metadata.geographicInfo;

  let index = 0;
  offsets.forEach((OFFSET) => {
    /* count DEMES */
    _forOwn(demeMap, (value, key) => { // value: hash color array, key: deme name
      const arcs = pie()(Object.values(value));
      let i=0;
      for (let col in value){
        arcs[i].color = col;
        i++;
      }
      let lat = 0;
      let long = 0;
      let goodDeme = true;
      if (geo[geoResolution][key]) {
        lat = geo[geoResolution][key].latitude;
        long = geo[geoResolution][key].longitude + OFFSET;
      } else {
        goodDeme = false;
        console.warn("Warning: Lat/long missing from metadata for", key);
      }
      if (long > westBound && long < eastBound && goodDeme === true) {
        const total = Object.values(value).reduce((a,b)=>a+b);
        const deme = {
          name: key,
          count: total,
          color: averageColorsDict(value),
          arcs: arcs,
          latitude: lat, // raw latitude value
          longitude: long, // raw longitude value
          coords: leafletLatLongToLayerPoint(lat, long, map) // coords are x,y plotted via d3
        };
        demeData.push(deme);

        if (!demeIndices[key]) {
          demeIndices[key] = [index];
        } else {
          demeIndices[key].push(index);
        }
        index += 1;

      }
    });
  });

  return {
    demeData: demeData,
    demeIndices: demeIndices
  };
};

const constructBcurve = (
  originLatLongPair,
  destinationLatLongPair,
  extend
) => {
  return bezier(originLatLongPair, destinationLatLongPair, extend);
};

const maybeConstructTransmissionEvent = (
  node,
  child,
  metadataGeoLookupTable,
  geoResolution,
  nodeColors,
  visibility,
  map,
  offsetOrig,
  offsetDest,
  demesMissingLatLongs,
  extend
) => {
  let latOrig, longOrig, latDest, longDest;
  let transmission;
  /* checking metadata for lat longs name match - ie., does the metadata list a latlong for Thailand? */
  const nodeLocation = getTraitFromNode(node, geoResolution); //  we're looking this up in the metadata lookup table
  const childLocation = getTraitFromNode(child, geoResolution);
  try {
    latOrig = metadataGeoLookupTable[geoResolution][nodeLocation].latitude;
    longOrig = metadataGeoLookupTable[geoResolution][nodeLocation].longitude;
  } catch (e) {
    demesMissingLatLongs.add(nodeLocation);
  }
  try {
    latDest = metadataGeoLookupTable[geoResolution][childLocation].latitude;
    longDest = metadataGeoLookupTable[geoResolution][childLocation].longitude;
  } catch (e) {
    demesMissingLatLongs.add(childLocation);
  }

  const validLatLongPair = maybeGetTransmissionPair(
    latOrig,
    longOrig + offsetOrig,
    latDest,
    longDest + offsetDest,
    map
  );

  if (validLatLongPair) {

    const Bcurve = constructBcurve(validLatLongPair[0], validLatLongPair[1], extend);

    /* set up interpolator with origin and destination numdates */
    const interpolator = interpolateNumber(node.num_date.value, child.num_date.value);

    /* make a Bdates array as long as Bcurve */
    const Bdates = [];
    Bcurve.forEach((d, i) => {
      /* fill it with interpolated dates */
      Bdates.push(
        interpolator(i / (Bcurve.length - 1)) /* ie., 5 / 15ths of the way through = 2016.3243 */
      );
    });

    /* build up transmissions object */
    transmission = {
      id: node.arrayIdx.toString() + "-" + child.arrayIdx.toString(),
      originNode: node,
      destinationNode: child,
      bezierCurve: Bcurve,
      bezierDates: Bdates,
      originName: getTraitFromNode(node, geoResolution),
      destinationName: getTraitFromNode(child, geoResolution),
      originCoords: validLatLongPair[0], // after interchange
      destinationCoords: validLatLongPair[1], // after interchange
      originLatitude: latOrig, // raw latitude value
      destinationLatitude: latDest, // raw latitude value
      originLongitude: longOrig + offsetOrig, // raw longitude value
      destinationLongitude: longDest + offsetDest, // raw longitude value
      originNumDate: node.num_date.value,
      destinationNumDate: child.num_date.value,
      color: nodeColors[node.arrayIdx],
      visible: visibility[child.arrayIdx] !== NODE_NOT_VISIBLE ? "visible" : "hidden", // transmission visible if child is visible
      extend: extend
    };
  }
  return transmission;
};

const maybeGetClosestTransmissionEvent = (
  node,
  child,
  metadataGeoLookupTable,
  geoResolution,
  nodeColors,
  visibility,
  map,
  offsetOrig,
  demesMissingLatLongs,
  extend
) => {
  const possibleEvents = [];
  // iterate over offsets applied to transmission destination
  // even if map is not tripled - ie., don't let a line go across the whole world
  [-360, 0, 360].forEach((offsetDest) => {
    const t = maybeConstructTransmissionEvent(
      node,
      child,
      metadataGeoLookupTable,
      geoResolution,
      nodeColors,
      visibility,
      map,
      offsetOrig,
      offsetDest,
      demesMissingLatLongs,
      extend
    );
    if (t) { possibleEvents.push(t); }
  });

  if (possibleEvents.length > 0) {

    const closestEvent = _minBy(possibleEvents, (event) => {
      return Math.abs(event.destinationCoords.x - event.originCoords.x);
    });
    return closestEvent;

  }

  return null;

};

const setupTransmissionData = (
  nodes,
  visibility,
  geoResolution,
  nodeColors,
  triplicate,
  metadata,
  map
) => {

  const offsets = triplicate ? [-360, 0, 360] : [0];
  const metadataGeoLookupTable = metadata.geographicInfo;
  const transmissionData = []; /* edges, animation paths */
  const transmissionIndices = {}; /* map of transmission id to array of indices */
  const demesMissingLatLongs = new Set();
  const demeToDemeCounts = {};
  nodes.forEach((n) => {
    const nodeDeme = getTraitFromNode(n, geoResolution);
    if (n.children) {
      n.children.forEach((child) => {
        const childDeme = getTraitFromNode(child, geoResolution);
        if (nodeDeme && childDeme && nodeDeme !== childDeme) {
          // record transmission event
          if ([nodeDeme, childDeme] in demeToDemeCounts) {
            demeToDemeCounts[[nodeDeme, childDeme]] += 1;
          } else {
            demeToDemeCounts[[nodeDeme, childDeme]] = 1;
          }
          const extend = demeToDemeCounts[[nodeDeme, childDeme]];
          // offset is applied to transmission origin
          offsets.forEach((offsetOrig) => {
            const t = maybeGetClosestTransmissionEvent(
              n,
              child,
              metadataGeoLookupTable,
              geoResolution,
              nodeColors,
              visibility,
              map,
              offsetOrig,
              demesMissingLatLongs,
              extend
            );
            if (t) { transmissionData.push(t); }
          });
        }
      });
    }
  });

  transmissionData.forEach((transmission, index) => {
    if (!transmissionIndices[transmission.id]) {
      transmissionIndices[transmission.id] = [index];
    } else {
      transmissionIndices[transmission.id].push(index);
    }
  });
  return {
    transmissionData: transmissionData,
    transmissionIndices: transmissionIndices,
    demesMissingLatLongs
  };
};

export const createDemeAndTransmissionData = (
  nodes,
  visibility,
  geoResolution,
  nodeColors,
  triplicate,
  metadata,
  map
) => {

  /*
    walk through nodes and collect all data
    for demeData we have:
      name, coords, count, color
    for transmissionData we have:
      originNode, destinationNode, originCoords, destinationCoords, originName, destinationName
      originNumDate, destinationNumDate, color, visible
  */
  const {
    demeData,
    demeIndices
  } = setupDemeData(nodes, visibility, geoResolution, nodeColors, triplicate, metadata, map);

  /* second time so that we can get Bezier */
  const { transmissionData, transmissionIndices, demesMissingLatLongs } = setupTransmissionData(
    nodes,
    visibility,
    geoResolution,
    nodeColors,
    triplicate,
    metadata,
    map
  );

  return {
    demeData: demeData,
    transmissionData: transmissionData,
    demeIndices: demeIndices,
    transmissionIndices: transmissionIndices,
    demesMissingLatLongs
  };
};

/* ******************************
********************************
UPDATE DEMES & TRANSMISSIONS
********************************
******************************* */

const updateDemeDataColAndVis = (demeData, demeIndices, nodes, visibility, geoResolution, nodeColors) => {

  const demeDataCopy = demeData.slice();

  const demeMap = getDemeColors(nodes, visibility, geoResolution, nodeColors);

  // update demeData, for each deme, update all elements via demeIndices lookup
  _forOwn(demeMap, (value, key) => { // value: hash color array, key: deme name
    const name = key;
    const total = Object.values(value).reduce((a,b)=>a+b);
    demeIndices[name].forEach((index) => {
      demeDataCopy[index].count = total;
      demeDataCopy[index].color = averageColorsDict(value);
    });
  });
  return demeDataCopy;
};

const updateTransmissionDataColAndVis = (transmissionData, transmissionIndices, nodes, visibility, geoResolution, nodeColors) => {
  const transmissionDataCopy = transmissionData.slice(); /* basically, instead of _.map() since we're not mapping over the data we're mutating */
  nodes.forEach((node) => {
    if (node.children) {
      node.children.forEach((child) => {
        const nodeLocation = getTraitFromNode(node, geoResolution);
        const childLocation = getTraitFromNode(node, geoResolution);
        if (nodeLocation && childLocation && nodeLocation !== childLocation) {
          // this is a transmission event from n to child
          const id = node.arrayIdx.toString() + "-" + child.arrayIdx.toString();
          const col = nodeColors[node.arrayIdx];
          const vis = visibility[child.arrayIdx] !== NODE_NOT_VISIBLE ? "visible" : "hidden"; // transmission visible if child is visible

          // update transmissionData via index lookup
          try {
            transmissionIndices[id].forEach((index) => {
              transmissionDataCopy[index].color = col;
              transmissionDataCopy[index].visible = vis;
            });
          } catch (err) {
            console.warn(`Error trying to access ${id} in transmissionIndices. Map transmissions may be wrong.`);
          }
        }
      });
    }
  });
  return transmissionDataCopy;
};

export const updateDemeAndTransmissionDataColAndVis = (demeData, transmissionData, demeIndices, transmissionIndices, nodes, visibility, geoResolution, nodeColors) => {
  /*
    walk through nodes and update attributes that can mutate
    for demeData we have:
      count, color
    for transmissionData we have:
      color, visible
  */

  let newDemes;
  let newTransmissions;

  if (demeData && transmissionData) {
    newDemes = updateDemeDataColAndVis(demeData, demeIndices, nodes, visibility, geoResolution, nodeColors);
    newTransmissions = updateTransmissionDataColAndVis(transmissionData, transmissionIndices, nodes, visibility, geoResolution, nodeColors);
  }
  return {newDemes, newTransmissions};
};

/* ********************
**********************
ZOOM LEVEL CHANGE
**********************
********************* */

const updateDemeDataLatLong = (demeData, map) => {

  // interchange for all demes
  return _map(demeData, (d) => {
    d.coords = leafletLatLongToLayerPoint(d.latitude, d.longitude, map);
    return d;
  });

};

const updateTransmissionDataLatLong = (transmissionData, map) => {

  const transmissionDataCopy = transmissionData.slice(); /* basically, instead of _.map() since we're not mapping over the data we're mutating */

  // interchange for all transmissions
  transmissionDataCopy.forEach((transmission) => {
    transmission.originCoords = leafletLatLongToLayerPoint(transmission.originLatitude, transmission.originLongitude, map);
    transmission.destinationCoords = leafletLatLongToLayerPoint(transmission.destinationLatitude, transmission.destinationLongitude, map);
    transmission.bezierCurve = constructBcurve(
      transmission.originCoords,
      transmission.destinationCoords,
      transmission.extend
    );
  });

  return transmissionDataCopy;

};

export const updateDemeAndTransmissionDataLatLong = (demeData, transmissionData, map) => {

  /*
    walk through nodes and update attributes that can mutate
    for demeData we have:
      count, color
    for transmissionData we have:
      color, visible
  */

  let newDemes;
  let newTransmissions;

  if (demeData && transmissionData) {
    newDemes = updateDemeDataLatLong(demeData, map);
    newTransmissions = updateTransmissionDataLatLong(transmissionData, map);
  }

  return {
    newDemes,
    newTransmissions
  };
};
<|endoftext|>