<commit_before>define(['jquery', 'underscore', 'routing', 'oro/messenger', 'oro/translator', 'oro/navigation', 'oro/modal'],
function($, _, routing, messenger, __, Navigation, Modal) {
    'use strict';

    var navigation = Navigation.getInstance();
    var performTransition = function(element, data) {
        $.getJSON(element.data('transition-url'), data ? {'data': data} : null)
            .done(function(response) {
                var doRedirect = function(redirectUrl) {
                    if (navigation) {
                        navigation.setLocation(redirectUrl);
                    } else {
                        window.location.href = redirectUrl;
                    }
                };
                var doReload = function() {
                    if (navigation) {
                        navigation.loadPage();
                    } else {
                        window.location.reload();
                    }
                };

                /** Handle redirectUrl result parameter for RedirectAction */
                element.one('transitions_success', function(e, response) {
                    if (response.workflowItem
                        && response.workflowItem.result
                        && response.workflowItem.result.redirectUrl
                        ) {
                        e.stopImmediatePropagation();
                        doRedirect(response.workflowItem.result.redirectUrl);
                    }
                });
                /** Handle redirect-to-workflow element data parameter */
                element.one('transitions_success', function(e, response) {
                    var workflowItemId = null;
                    if (response.workflowItem && response.workflowItem.id) {
                        workflowItemId = response.workflowItem.id;
                    }
                    var needRedirect = element.data('redirect-to-workflow');
                    if (needRedirect && workflowItemId) {
                        e.stopImmediatePropagation();
                        var redirectUrl = routing.generate(
                            'oro_workflow_step_edit',
                            {id: workflowItemId}
                        );
                        doRedirect(redirectUrl);
                    }
                });
                /** By default reload page */
                element.one('transitions_success', doReload);
                element.trigger('transitions_success', [response]);
            })
            .fail(function(jqxhr, textStatus, error) {
                element.one('transitions_failure', function() {
                    messenger.notificationFlashMessage('error', __('Could not perform transition'));
                });
                element.trigger('transitions_failure', [jqxhr, textStatus, error]);
            });
    };

    /**
     * Transition button click handler
     *
     * @export  oro/workflow-transition-handler
     * @class   oro.WorkflowTransitionHandler
     */
    return function() {
        var element = $(this);
        if (element.data('_in-progress')) {
            return;
        }
        element.data('_in-progress', true);
        var resetInProgress = function() {
            element.data('_in-progress', false);
        };
        element.one('transitions_success', resetInProgress);
        element.one('transitions_failure', resetInProgress);
        if (element.data('dialog-url')) {
            require(['oro/dialog-widget'],
            function(DialogWidget) {
                var dialogOptions = {
                    title: element.data('transition-label') || element.html(),
                    url: element.data('dialog-url'),
                    stateEnabled: false,
                    incrementalPosition: false,
                    loadingMaskEnabled: false,
                    dialogOptions: {
                        modal: true,
                        resizable: false,
                        width: 475,
                        autoResize: true
                    }
                };
                var additionalOptions = element.data('dialog-options');
                if (additionalOptions) {
                    if (additionalOptions.dialogOptions !== undefined) {
                        additionalOptions.dialogOptions = _.extend(
                            dialogOptions.dialogOptions,
                            additionalOptions.dialogOptions
                        );
                    }
                    dialogOptions = _.extend(dialogOptions, additionalOptions);
                }
                var transitionFormWidget = new DialogWidget(dialogOptions);
                transitionFormWidget.on('widgetRemove', resetInProgress);
                transitionFormWidget.on('formSave', function(data) {
                    transitionFormWidget.remove();
                    performTransition(element, data);
                });
                transitionFormWidget.render();
            });
        } else {
            var message = element.data('message');
            if (message) {
                var confirm = new Modal({
                    title: element.data('transition-label'),
                    content: message
                });
                confirm.on('ok', function() {
                    performTransition(element);
                });
                confirm.open();
            } else {
                performTransition(element);
            }
        }
    }
});
<commit_msg>BAP-2608: Adjust B2B sales flow  - small workflow fixes<commit_after>define(['jquery', 'underscore', 'routing', 'oro/messenger', 'oro/translator', 'oro/navigation', 'oro/modal'],
function($, _, routing, messenger, __, Navigation, Modal) {
    'use strict';

    var navigation = Navigation.getInstance();
    var performTransition = function(element, data) {
        $.getJSON(element.data('transition-url'), data ? {'data': data} : null)
            .done(function(response) {
                var doRedirect = function(redirectUrl) {
                    if (navigation) {
                        navigation.setLocation(redirectUrl);
                    } else {
                        window.location.href = redirectUrl;
                    }
                };
                var doReload = function() {
                    if (navigation) {
                        navigation.loadPage();
                    } else {
                        window.location.reload();
                    }
                };

                /** Handle redirectUrl result parameter for RedirectAction */
                element.one('transitions_success', function(e, response) {
                    if (response.workflowItem
                        && response.workflowItem.result
                        && response.workflowItem.result.redirectUrl
                        ) {
                        e.stopImmediatePropagation();
                        doRedirect(response.workflowItem.result.redirectUrl);
                    }
                });
                /** Handle redirect-to-workflow element data parameter */
                element.one('transitions_success', function(e, response) {
                    var workflowItemId = null;
                    if (response.workflowItem && response.workflowItem.id) {
                        workflowItemId = response.workflowItem.id;
                    }
                    var needRedirect = element.data('redirect-to-workflow');
                    if (needRedirect && workflowItemId) {
                        e.stopImmediatePropagation();
                        var redirectUrl = routing.generate(
                            'oro_workflow_step_edit',
                            {id: workflowItemId}
                        );
                        doRedirect(redirectUrl);
                    }
                });
                /** By default reload page */
                element.one('transitions_success', doReload);
                element.trigger('transitions_success', [response]);
            })
            .fail(function(jqxhr, textStatus, error) {
                element.one('transitions_failure', function() {
                    messenger.notificationFlashMessage('error', __('Could not perform transition'));
                });
                element.trigger('transitions_failure', [jqxhr, textStatus, error]);
            });
    };

    /**
     * Transition button click handler
     *
     * @export  oro/workflow-transition-handler
     * @class   oro.WorkflowTransitionHandler
     */
    return function() {
        var element = $(this);
        if (element.data('_in-progress')) {
            return;
        }
        element.data('_in-progress', true);
        var resetInProgress = function() {
            element.data('_in-progress', false);
        };
        element.one('transitions_success', resetInProgress);
        element.one('transitions_failure', resetInProgress);
        if (element.data('dialog-url')) {
            require(['oro/dialog-widget'],
            function(DialogWidget) {
                var dialogOptions = {
                    title: element.data('transition-label') || element.html(),
                    url: element.data('dialog-url'),
                    stateEnabled: false,
                    incrementalPosition: false,
                    loadingMaskEnabled: false,
                    dialogOptions: {
                        modal: true,
                        resizable: false,
                        width: 475,
                        autoResize: true
                    }
                };
                var additionalOptions = element.data('dialog-options');
                if (additionalOptions) {
                    if (additionalOptions.dialogOptions !== undefined) {
                        additionalOptions.dialogOptions = _.extend(
                            dialogOptions.dialogOptions,
                            additionalOptions.dialogOptions
                        );
                    }
                    dialogOptions = _.extend(dialogOptions, additionalOptions);
                }
                var transitionFormWidget = new DialogWidget(dialogOptions);
                transitionFormWidget.on('widgetRemove', resetInProgress);
                transitionFormWidget.on('formSave', function(data) {
                    transitionFormWidget.remove();
                    performTransition(element, data);
                });
                transitionFormWidget.render();
            });
        } else {
            var message = element.data('message');
            if (message) {
                var confirm = new Modal({
                    title: element.data('transition-label'),
                    content: message
                });
                confirm.on('ok', function() {
                    performTransition(element);
                });
                confirm.on('cancel', function() {
                    resetInProgress();
                });
                confirm.open();
            } else {
                performTransition(element);
            }
        }
    }
});
<|endoftext|>


<commit_before>import * as d3 from 'd3'

export class VisUnemploymentRate {
  constructor(divId, city_id, ccaa_id) {
    this.container = divId;
    this.data = null;
    this.tbiToken = window.populateData.token;
    this.placeUrl = window.populateData.endpoint + '/datasets/ds-tasa-paro-municipal.json?sort_asc_by=date&filter_by_location_id=' + city_id;
    this.autonomousRegionUrl = window.populateData.endpoint + '/datasets/ds-epa-tasa-paro-autonomica-trimestral.json?sort_asc_by=date&filter_by_location_id=' + ccaa_id;
    this.countryUrl = window.populateData.endpoint + '/datasets/ds-epa-tasa-paro-nacional-trimestral.json?sort_asc_by=date';
    this.parseTime = d3.timeParse('%Y-%m');
    this.valueFormat = d3.format('.1%');
    this.isMobile = window.innerWidth <= 768;

    // Chart dimensions
    this.margin = { top: 25, right: 80, bottom: 25, left: 0 };
    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    // Scales & Ranges
    this.xScale = d3.scaleTime();
    this.yScale = d3.scaleLinear();
    this.color = d3.scaleOrdinal();

    // Create axes
    this.xAxis = d3.axisBottom();
    this.yAxis = d3.axisLeft();

    // Chart objects
    this.svg = null;
    this.chart = null;

    // Create main elements
    this.svg = d3.select(this.container)
      .append('svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom)
      .append('g')
      .attr('class', 'chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    // Append axes containers
    this.svg.append('g').attr('class','x axis');
    this.svg.append('g').attr('class','y axis');

    d3.select(window).on('resize.' + this.container, () => {
      if (this.data) {
        this._resize()
      }
    });
  }

  getData() {
    var place = d3.json(this.placeUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var autonomousRegion = d3.json(this.autonomousRegionUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var country = d3.json(this.countryUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    d3.queue()
      .defer(place.get)
      .defer(autonomousRegion.get)
      .defer(country.get)
      .await(function (error, jsonPlace, jsonAutonomousRegion, jsonCountry) {
        if (error) throw error;

        jsonPlace.forEach(function(d) {
          d.location_type = 'place';
          d.date = this.parseTime(d.date);
        }.bind(this));

        jsonAutonomousRegion.forEach(function(d) {
          d.location_type = 'autonomous_region';
          d.date = this.parseTime(d.date.slice(0, 7));
        }.bind(this));

        jsonCountry.forEach(function(d) {
          d.location_type = 'country';
          d.date = this.parseTime(d.date.slice(0, 7));
        }.bind(this));

        this.data = jsonPlace.concat(jsonAutonomousRegion, jsonCountry);

        this.nest = d3.nest()
          .key(function(d) { return d.location_type; })
          .entries(this.data);

        this.updateRender();
        this._renderLines();
        this._renderVoronoi();

      }.bind(this));
  }

  render() {
    if (this.data === null) {
      this.getData();
    } else {
      this.updateRender();
    }
  }

  updateRender() {
    this.xScale
      .rangeRound([0, this.width])
      .domain([this.parseTime('2011-01'), d3.max(this.data, function(d) { return d.date; })]);

    this.yScale
      .rangeRound([this.height, 0])
      .domain([0, d3.max(this.data, function(d) { return d.value; })]);

    this.color
      .domain(['place', 'autonomous_region', 'country'])
      .range(['#F6B128', '#F39D96', '#007382']);

    this._renderAxis();
  }

  _renderLines() {
    this.line = d3.line()
      .x(function(d) { return this.xScale(d.date); }.bind(this))
      .y(function(d) { return this.yScale(d.value); }.bind(this))
      // .curve(d3.curveCatmullRom.alpha(0.5));

    var lines = this.svg.append('g')
      .attr('class', 'lines')
      .selectAll('path')
      .data(this.nest, function(d) { return d.key; })
      .enter();

    var linesGroup = lines.append('g')
      .attr('class', 'line');

    linesGroup.append('path')
      .attr('d', function(d) { d.line = this; return this.line(d.values); }.bind(this))
      .attr('stroke', function(d) { return this.color(d.key); }.bind(this));

    linesGroup.append('circle')
     .attr('cx', function(d) { return this.xScale(d.values.map(function(d) { return d.date; }).slice(-1)[0]); }.bind(this))
     .attr('cy', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]); }.bind(this))
     .attr('r', 5)
     .attr('fill', function(d) { return this.color(d.key); }.bind(this));

    var linesText = d3.select(this.container).append('div')
      .attr('class', 'lines-labels')
      .selectAll('p')
      .data(this.nest, function(d) { return d.key; })
      .enter();

    linesText.append('div')
      .style('right', '10px')
      .style('top', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]) + 'px'; }.bind(this))
      .text(function(d) {
        return this._getPlaceType(d.key);
      }.bind(this));
  }

  _renderVoronoi() {
    this.focus = this.svg.append('g')
      .attr('transform', 'translate(-100,-100)')
      .attr('class', 'focus');

    this.focus.append('circle')
      .attr('fill', 'white')
      .attr('r', 5);

    this.text = this.focus
      .append('text');

    this.text.append('tspan')
      .attr('y', -10)
      .attr('x', 0);

    this.voronoi = d3.voronoi()
      .x(function(d) {return this.xScale(d.date); }.bind(this))
      .y(function(d) {return this.yScale(d.value); }.bind(this))
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup = this.svg.append('g')
      .attr('class', 'voronoi');

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi.polygons(d3.merge(this.nest.map(function(d) { return d.values; }))))
      .enter().append('path')
      .attr('d', function(d) { return d ? 'M' + d.join('L') + 'Z' : null; })
      .on('mouseover', this._mouseover.bind(this))
      .on('mouseout', this._mouseout.bind(this));
  }

  _mouseover(d) {
    this.focus.select('circle').attr('stroke', this.color(d.data.location_type));

    this.focus.attr('transform', 'translate(' + this.xScale(d.data.date) + ',' + this.yScale(d.data.value) + ')');
    this.focus.select('text').attr('text-anchor', d.data.date >= this.parseTime('2014-01') ? 'end' : 'start');
    this.focus.select('tspan').text(`${this._getPlaceType(d.data.location_type)}: ${d.data.value}% (${d.data.date.toLocaleString(I18n.locale, { month: 'short' })} ${d.data.date.getFullYear()})`);
  }

  _mouseout() {
    this.focus.attr('transform', 'translate(-100,-100)');
  }

  _renderAxis() {
    // X axis
    this.svg.select('.x.axis')
      .attr('transform', 'translate(0,' + this.height + ')');

    this.xAxis
      .ticks(4)
      .tickPadding(10)
      .tickSize(0, 0)
      .scale(this.xScale);

    this.yAxis
      .ticks(3)
      .tickSize(-this.width)
      .tickFormat(function(d) { return d + '%'; })
      .scale(this.yScale);

    this.svg.select('.x.axis').call(this.xAxis);
    this.svg.select('.y.axis').call(this.yAxis);

    // Remove the zero
    this.svg.selectAll('.y.axis .tick')
      .filter(function (d) { return d === 0; })
      .remove();

    // Move y axis ticks on top of the chart
    this.svg.selectAll('.y.axis .tick text')
      .attr('text-anchor', 'start')
      .attr('dx', '0.25em')
      .attr('dy', '-0.55em');
  }

  _getPlaceType(place) {
    switch (place) {
      case 'country':
        return I18n.t('gobierto_common.visualizations.country');
      case 'autonomous_region':
        return window.populateData.ccaaName;
      case 'place':
        return window.populateData.municipalityName;
    }
  }

  _width() {
    return parseInt(d3.select(this.container).style('width'));
  }

  _height() {
    return this.isMobile ? 200 : 250;
  }

  _resize() {
    this.isMobile = window.innerWidth <= 768;

    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    this.updateRender();

    d3.select(this.container + ' svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom);

    this.svg.select('.chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    this.svg.selectAll('.lines path')
      .attr('d', function(d) { d.line = this; return this.line(d.values); }.bind(this));

    this.svg.selectAll('.lines circle')
      .attr('cx', function(d) { return this.xScale(d.values.map(function(d) { return d.date; }).slice(-1)[0]); }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]); }.bind(this));

    d3.selectAll(this.container + ' .lines-labels div')
      .style('top', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]) + 'px'; }.bind(this));

    this.voronoi
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi.polygons(d3.merge(this.nest.map(function(d) { return d.values; }))))
      .attr('d', function(d) { return d ? 'M' + d.join('L') + 'Z' : null; });
  }

}
<commit_msg>Update unemployment_rate.js<commit_after>import { timeParse } from 'd3-time-format'
import { format } from 'd3-format'
import { select, selectAll } from 'd3-selection'
import { scaleTime, scaleLinear, scaleOrdinal } from 'd3-scale'
import { axisBottom, axisLeft } from 'd3-axis'
import { json } from 'd3-request'
import { queue } from 'd3-queue'
import { nest } from 'd3-collection'
import { max, merge } from 'd3-array'
import { line } from 'd3-shape'
import { voronoi } from 'd3-voronoi'

const d3 = { timeParse, format, select, scaleTime, scaleLinear, scaleOrdinal, axisBottom, axisLeft, json, queue, nest, max, line, voronoi, merge, selectAll }

export class VisUnemploymentRate {
  constructor(divId, city_id, ccaa_id) {
    this.container = divId;
    this.data = null;
    this.tbiToken = window.populateData.token;
    this.placeUrl = window.populateData.endpoint + '/datasets/ds-tasa-paro-municipal.json?sort_asc_by=date&filter_by_location_id=' + city_id;
    this.autonomousRegionUrl = window.populateData.endpoint + '/datasets/ds-epa-tasa-paro-autonomica-trimestral.json?sort_asc_by=date&filter_by_location_id=' + ccaa_id;
    this.countryUrl = window.populateData.endpoint + '/datasets/ds-epa-tasa-paro-nacional-trimestral.json?sort_asc_by=date';
    this.parseTime = d3.timeParse('%Y-%m');
    this.valueFormat = d3.format('.1%');
    this.isMobile = window.innerWidth <= 768;

    // Chart dimensions
    this.margin = { top: 25, right: 80, bottom: 25, left: 0 };
    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    // Scales & Ranges
    this.xScale = d3.scaleTime();
    this.yScale = d3.scaleLinear();
    this.color = d3.scaleOrdinal();

    // Create axes
    this.xAxis = d3.axisBottom();
    this.yAxis = d3.axisLeft();

    // Chart objects
    this.svg = null;
    this.chart = null;

    // Create main elements
    this.svg = d3.select(this.container)
      .append('svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom)
      .append('g')
      .attr('class', 'chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    // Append axes containers
    this.svg.append('g').attr('class','x axis');
    this.svg.append('g').attr('class','y axis');

    d3.select(window).on('resize.' + this.container, () => {
      if (this.data) {
        this._resize()
      }
    });
  }

  getData() {
    var place = d3.json(this.placeUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var autonomousRegion = d3.json(this.autonomousRegionUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    var country = d3.json(this.countryUrl)
      .header('authorization', 'Bearer ' + this.tbiToken)

    d3.queue()
      .defer(place.get)
      .defer(autonomousRegion.get)
      .defer(country.get)
      .await(function (error, jsonPlace, jsonAutonomousRegion, jsonCountry) {
        if (error) throw error;

        jsonPlace.forEach(function(d) {
          d.location_type = 'place';
          d.date = this.parseTime(d.date);
        }.bind(this));

        jsonAutonomousRegion.forEach(function(d) {
          d.location_type = 'autonomous_region';
          d.date = this.parseTime(d.date.slice(0, 7));
        }.bind(this));

        jsonCountry.forEach(function(d) {
          d.location_type = 'country';
          d.date = this.parseTime(d.date.slice(0, 7));
        }.bind(this));

        this.data = jsonPlace.concat(jsonAutonomousRegion, jsonCountry);

        this.nest = d3.nest()
          .key(function(d) { return d.location_type; })
          .entries(this.data);

        this.updateRender();
        this._renderLines();
        this._renderVoronoi();

      }.bind(this));
  }

  render() {
    if (this.data === null) {
      this.getData();
    } else {
      this.updateRender();
    }
  }

  updateRender() {
    this.xScale
      .rangeRound([0, this.width])
      .domain([this.parseTime('2011-01'), d3.max(this.data, function(d) { return d.date; })]);

    this.yScale
      .rangeRound([this.height, 0])
      .domain([0, d3.max(this.data, function(d) { return d.value; })]);

    this.color
      .domain(['place', 'autonomous_region', 'country'])
      .range(['#F6B128', '#F39D96', '#007382']);

    this._renderAxis();
  }

  _renderLines() {
    this.line = d3.line()
      .x(function(d) { return this.xScale(d.date); }.bind(this))
      .y(function(d) { return this.yScale(d.value); }.bind(this))
      // .curve(d3.curveCatmullRom.alpha(0.5));

    var lines = this.svg.append('g')
      .attr('class', 'lines')
      .selectAll('path')
      .data(this.nest, function(d) { return d.key; })
      .enter();

    var linesGroup = lines.append('g')
      .attr('class', 'line');

    linesGroup.append('path')
      .attr('d', function(d) { d.line = this; return this.line(d.values); }.bind(this))
      .attr('stroke', function(d) { return this.color(d.key); }.bind(this));

    linesGroup.append('circle')
     .attr('cx', function(d) { return this.xScale(d.values.map(function(d) { return d.date; }).slice(-1)[0]); }.bind(this))
     .attr('cy', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]); }.bind(this))
     .attr('r', 5)
     .attr('fill', function(d) { return this.color(d.key); }.bind(this));

    var linesText = d3.select(this.container).append('div')
      .attr('class', 'lines-labels')
      .selectAll('p')
      .data(this.nest, function(d) { return d.key; })
      .enter();

    linesText.append('div')
      .style('right', '10px')
      .style('top', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]) + 'px'; }.bind(this))
      .text(function(d) {
        return this._getPlaceType(d.key);
      }.bind(this));
  }

  _renderVoronoi() {
    this.focus = this.svg.append('g')
      .attr('transform', 'translate(-100,-100)')
      .attr('class', 'focus');

    this.focus.append('circle')
      .attr('fill', 'white')
      .attr('r', 5);

    this.text = this.focus
      .append('text');

    this.text.append('tspan')
      .attr('y', -10)
      .attr('x', 0);

    this.voronoi = d3.voronoi()
      .x(function(d) {return this.xScale(d.date); }.bind(this))
      .y(function(d) {return this.yScale(d.value); }.bind(this))
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup = this.svg.append('g')
      .attr('class', 'voronoi');

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi.polygons(d3.merge(this.nest.map(function(d) { return d.values; }))))
      .enter().append('path')
      .attr('d', function(d) { return d ? 'M' + d.join('L') + 'Z' : null; })
      .on('mouseover', this._mouseover.bind(this))
      .on('mouseout', this._mouseout.bind(this));
  }

  _mouseover(d) {
    this.focus.select('circle').attr('stroke', this.color(d.data.location_type));

    this.focus.attr('transform', 'translate(' + this.xScale(d.data.date) + ',' + this.yScale(d.data.value) + ')');
    this.focus.select('text').attr('text-anchor', d.data.date >= this.parseTime('2014-01') ? 'end' : 'start');
    this.focus.select('tspan').text(`${this._getPlaceType(d.data.location_type)}: ${d.data.value}% (${d.data.date.toLocaleString(I18n.locale, { month: 'short' })} ${d.data.date.getFullYear()})`);
  }

  _mouseout() {
    this.focus.attr('transform', 'translate(-100,-100)');
  }

  _renderAxis() {
    // X axis
    this.svg.select('.x.axis')
      .attr('transform', 'translate(0,' + this.height + ')');

    this.xAxis
      .ticks(4)
      .tickPadding(10)
      .tickSize(0, 0)
      .scale(this.xScale);

    this.yAxis
      .ticks(3)
      .tickSize(-this.width)
      .tickFormat(function(d) { return d + '%'; })
      .scale(this.yScale);

    this.svg.select('.x.axis').call(this.xAxis);
    this.svg.select('.y.axis').call(this.yAxis);

    // Remove the zero
    this.svg.selectAll('.y.axis .tick')
      .filter(function (d) { return d === 0; })
      .remove();

    // Move y axis ticks on top of the chart
    this.svg.selectAll('.y.axis .tick text')
      .attr('text-anchor', 'start')
      .attr('dx', '0.25em')
      .attr('dy', '-0.55em');
  }

  _getPlaceType(place) {
    switch (place) {
      case 'country':
        return I18n.t('gobierto_common.visualizations.country');
      case 'autonomous_region':
        return window.populateData.ccaaName;
      case 'place':
        return window.populateData.municipalityName;
    }
  }

  _width() {
    return this.container ? parseInt(d3.select(this.container).style('width')) : 0;
  }

  _height() {
    return this.isMobile ? 200 : 250;
  }

  _resize() {
    this.isMobile = window.innerWidth <= 768;

    this.width = this._width() - this.margin.left - this.margin.right;
    this.height = this._height() - this.margin.top - this.margin.bottom;

    this.updateRender();

    d3.select(this.container + ' svg')
      .attr('width', this.width + this.margin.left + this.margin.right)
      .attr('height', this.height + this.margin.top + this.margin.bottom);

    this.svg.select('.chart-container')
      .attr('transform', 'translate(' + this.margin.left + ',' + this.margin.top + ')');

    this.svg.selectAll('.lines path')
      .attr('d', function(d) { d.line = this; return this.line(d.values); }.bind(this));

    this.svg.selectAll('.lines circle')
      .attr('cx', function(d) { return this.xScale(d.values.map(function(d) { return d.date; }).slice(-1)[0]); }.bind(this))
      .attr('cy', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]); }.bind(this));

    d3.selectAll(this.container + ' .lines-labels div')
      .style('top', function(d) { return this.yScale(d.values.map(function(d) { return d.value; }).slice(-1)[0]) + 'px'; }.bind(this));

    this.voronoi
      .extent([[0, 0], [this.width, this.height]]);

    this.voronoiGroup.selectAll('path')
      .data(this.voronoi.polygons(d3.merge(this.nest.map(function(d) { return d.values; }))))
      .attr('d', function(d) { return d ? 'M' + d.join('L') + 'Z' : null; });
  }

}
<|endoftext|>


<commit_before>/*
 * Vector rendering for all browsers that support canvas.
 */

L.Canvas = L.Renderer.extend({

	onAdd: function () {
		var container = this._container = document.createElement('canvas');

		if (this._zoomAnimated) {
			L.DomUtil.addClass(container, 'leaflet-zoom-animated');
		}

		this._ctx = container.getContext('2d');

		this.getPane().appendChild(container);
		this._update();

		this.fire('redraw');
	},

	onRemove: function () {
		L.DomUtil.remove(this._container);
	},

	_update: function () {
		if (this._map._animatingZoom) { return; }

		L.Renderer.prototype._update.call(this);

		var b = this._bounds,
		    size = b.getSize(),
		    m = L.Browser.retina ? 2 : 1,
		    container = this._container;

		L.DomUtil.setPosition(container, b.min);
		container.width = m * size.x;
		container.height = m * size.y;
		container.style.width = size.x + 'px';
		container.style.height = size.y + 'px';

		if (L.Browser.retina) {
			this._ctx.scale(2, 2);
		}

		this._ctx.translate(-b.min.x, -b.min.y);
	},

	_initPath: function (layer) {
		this.on('redraw', layer._updatePath, layer);

		if (layer.options.clickable) {
			L.DomEvent
				.on(this._container, 'mousemove', this._onMouseMove, layer)
				.on(this._container, 'click', this._onClick, layer);
		}
	},

	_addPath: L.Util.falseFn,

	_removePath: function (layer) {
		if (layer.options.clickable) {
			L.DomEvent
				.off(this._container, 'mousemove', this._onMouseMove, layer)
				.off(this._container, 'click', this._onClick, layer);
		}

		this.off('redraw', layer._updatePath, layer);
		this._requestRedraw();
	},

	_updateStyle: function () {
		this._requestRedraw();
	},

	_requestRedraw: function () {
		if (this._map) {
			this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._fireRedraw, this);
		}
	},

	_fireRedraw: function () {
		this._redrawRequest = null;

		this._ctx.clearRect(0, 0, this._container.width, this._container.height);

		this.fire('redraw');
	},

	_updatePoly: function (layer, closed) {

		var i, j, len2, p,
		    parts = layer._parts,
		    len = parts.length,
		    ctx = this._ctx,
		    options = layer.options;

		if (!len) { return; }

		ctx.beginPath();

		for (i = 0; i < len; i++) {
			for (j = 0, len2 = parts[i].length; j < len2; j++) {
				p = parts[i][j];
				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
			}
			if (closed) {
				ctx.closePath();
			}
		}

		this._fillStroke(ctx, options);

		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
	},

	_updateCircle: function (layer) {
		var p = layer._point,
		    ctx = this._ctx;

		if (!layer._empty()) {
			ctx.beginPath();
			ctx.arc(p.x, p.y, layer._radius, 0, Math.PI * 2, false);

			this._fillStroke(ctx, layer.options);
		}
	},

	_fillStroke: function (ctx, options) {
		ctx.globalAlpha = 1;

		if (options.fill) {
			ctx.globalAlpha = options.fillOpacity;
			ctx.fillStyle = options.fillColor || options.color;
			ctx.fill('evenodd');
		}

		if (options.stroke) {
			ctx.globalAlpha = options.opacity;
			ctx.lineWidth = options.weight;
			ctx.strokeStyle = options.color;
			ctx.lineCap = options.lineCap;
			ctx.lineJoin = options.lineJoin;
			ctx.stroke();
		}
	},

	_onClick: function (e) {
		if (this._containsPoint(this._map.mouseEventToLayerPoint(e))) {
			this._onMouseClick(e);
		}
	},

	_onMouseMove: function (e) {
		if (!this._map || this._map._animatingZoom) { return; }

		var point = this._map.mouseEventToLayerPoint(e);

		// TODO don't do on each move
		if (this._containsPoint(point)) {
			this._renderer._container.style.cursor = 'pointer';
			this._mouseInside = true;
			this._fireMouseEvent(e, 'mouseover');

		} else if (this._mouseInside) {
			this._renderer._container.style.cursor = '';
			this._mouseInside = false;
			this._fireMouseEvent(e, 'mouseout');
		}
	},

	_bringToFront: function () {},
	_bringToBack: function () {}

	// TODO _bringToFront & _bringToBack
});

L.Browser.canvas = (function () {
	return !!document.createElement('canvas').getContext;
}());

L.canvas = function () {
	return L.Browser.canvas ? new L.Canvas() : null;
};

L.Canvas.instance = L.canvas();

L.Polyline.prototype._containsPoint = function (p, closed) {
	var i, j, k, len, len2, part,
	    w = this._clickTolerance();

	if (!this._pxBounds.contains(p)) { return false; }

	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			if (!closed && (j === 0)) { continue; }

			if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
				return true;
			}
		}
	}
	return false;
};

L.Polygon.prototype._containsPoint = function (p) {
	var inside = false,
	    part, p1, p2, i, j, k, len, len2;

	if (!this._pxBounds.contains(p)) { return false; }

	// ray casting algorithm for detecting if point is in polygon
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			p1 = part[j];
			p2 = part[k];

			if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
				inside = !inside;
			}
		}
	}

	// also check if it's on polygon stroke
	return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
};

L.Circle.prototype._containsPoint = function (p) {
	return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
};
<commit_msg>redraw partially when updating canvas layers (massive speedup)<commit_after>/*
 * Vector rendering for all browsers that support canvas.
 */

L.Canvas = L.Renderer.extend({

	onAdd: function () {
		var container = this._container;

		if (!container) {
			container = this._container = document.createElement('canvas');

			if (this._zoomAnimated) {
				L.DomUtil.addClass(container, 'leaflet-zoom-animated');
			}

			this._ctx = container.getContext('2d');
		}

		this.getPane().appendChild(container);
		this._update();

		this.fire('redraw');
	},

	onRemove: function () {
		L.DomUtil.remove(this._container);
	},

	_update: function () {
		if (this._map._animatingZoom) { return; }

		L.Renderer.prototype._update.call(this);

		var b = this._bounds,
		    size = b.getSize(),
		    m = L.Browser.retina ? 2 : 1,
		    container = this._container;

		L.DomUtil.setPosition(container, b.min);
		container.width = m * size.x;
		container.height = m * size.y;
		container.style.width = size.x + 'px';
		container.style.height = size.y + 'px';

		if (L.Browser.retina) {
			this._ctx.scale(2, 2);
		}

		this._ctx.translate(-b.min.x, -b.min.y);
	},

	_initPath: function (layer) {
		this.on('redraw', layer._updatePath, layer);

		if (layer.options.clickable) {
			L.DomEvent
				.on(this._container, 'mousemove', this._onMouseMove, layer)
				.on(this._container, 'click', this._onClick, layer);
		}
	},

	_addPath: L.Util.falseFn,

	_removePath: function (layer) {
		if (layer.options.clickable) {
			L.DomEvent
				.off(this._container, 'mousemove', this._onMouseMove, layer)
				.off(this._container, 'click', this._onClick, layer);
		}

		layer._removed = true;
		this._requestRedraw(layer);
	},

	_updateStyle: function (layer) {
		this._requestRedraw(layer);
	},

	_requestRedraw: function (layer) {
		if (this._map) {
			this._redrawBounds = this._redrawBounds || new L.Bounds();
			this._redrawBounds.extend(layer._pxBounds.min).extend(layer._pxBounds.max);
			this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._fireRedraw, this);
		}
	},

	_fireRedraw: function () {
		this._redrawRequest = null;
		this._clear = true;
		this.fire('redraw');
		this._clear = false;
		this.fire('redraw');
		this._redrawBounds = null;
	},

	_updatePoly: function (layer, closed) {

		var i, j, len2, p,
		    parts = layer._parts,
		    len = parts.length,
		    ctx = this._ctx;

	    if (!len || this._redrawBounds && !this._redrawBounds.intersects(layer._pxBounds)) { return; }

		ctx.beginPath();

		for (i = 0; i < len; i++) {
			for (j = 0, len2 = parts[i].length; j < len2; j++) {
				p = parts[i][j];
				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
			}
			if (closed) {
				ctx.closePath();
			}
		}

		this._fillStroke(ctx, layer);

		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
	},

	_updateCircle: function (layer) {

		if (layer._empty()) { return; }

		var p = layer._point,
		    ctx = this._ctx;

		ctx.beginPath();
		ctx.arc(p.x, p.y, layer._radius, 0, Math.PI * 2, false);

		this._fillStroke(ctx, layer);
	},

	_fillStroke: function (ctx, layer) {
		var clear = this._clear;

		if (layer._removed && !clear) {
			layer._removed = false;
			this.off('redraw', layer._updatePath, layer);
			return;
		}

		var options = layer.options;

		ctx.globalCompositeOperation = clear ? 'destination-out' : 'source-over';

		if (options.fill) {
			ctx.globalAlpha = clear ? 1 : options.fillOpacity;
			ctx.fillStyle = options.fillColor || options.color;
			ctx.fill('evenodd');
		}

		if (options.stroke) {
			ctx.globalAlpha = clear ? 1 : options.opacity;

			// if clearing shape, do it with the previously drawn line width
			layer._prevWeight = ctx.lineWidth = clear ? layer._prevWeight + 1 : options.weight;

			ctx.strokeStyle = options.color;
			ctx.lineCap = options.lineCap;
			ctx.lineJoin = options.lineJoin;
			ctx.stroke();
		}
	},

	_onClick: function (e) {
		if (this._containsPoint(this._map.mouseEventToLayerPoint(e))) {
			this._onMouseClick(e);
		}
	},

	_onMouseMove: function (e) {
		if (!this._map || this._map._animatingZoom) { return; }

		var point = this._map.mouseEventToLayerPoint(e);

		// TODO don't do on each move
		if (this._containsPoint(point)) {
			this._renderer._container.style.cursor = 'pointer';
			this._mouseInside = true;
			this._fireMouseEvent(e, 'mouseover');

		} else if (this._mouseInside) {
			this._renderer._container.style.cursor = '';
			this._mouseInside = false;
			this._fireMouseEvent(e, 'mouseout');
		}
	},

	_bringToFront: function () {},
	_bringToBack: function () {}

	// TODO _bringToFront & _bringToBack
});

L.Browser.canvas = (function () {
	return !!document.createElement('canvas').getContext;
}());

L.canvas = function () {
	return L.Browser.canvas ? new L.Canvas() : null;
};

L.Canvas.instance = L.canvas();

L.Polyline.prototype._containsPoint = function (p, closed) {
	var i, j, k, len, len2, part,
	    w = this._clickTolerance();

	if (!this._pxBounds.contains(p)) { return false; }

	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			if (!closed && (j === 0)) { continue; }

			if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
				return true;
			}
		}
	}
	return false;
};

L.Polygon.prototype._containsPoint = function (p) {
	var inside = false,
	    part, p1, p2, i, j, k, len, len2;

	if (!this._pxBounds.contains(p)) { return false; }

	// ray casting algorithm for detecting if point is in polygon
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			p1 = part[j];
			p2 = part[k];

			if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
				inside = !inside;
			}
		}
	}

	// also check if it's on polygon stroke
	return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
};

L.Circle.prototype._containsPoint = function (p) {
	return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
};
<|endoftext|>


<commit_before>enchant();
var gbraverDebug = {};
var assert;

/**
 * テストデータ
 */
gbraverDebug.statusArray = {
    2 : {
        name : 'ランドーザ',
        pictName : 'Landozer.PNG',
        hp : 4700,
        speed : 150,
        active : 0,
        battery : 5,
        weapons : {
            1 : {
                name : 'ブレイクパンチ',
                power : 1200
            },
            2 : {
                name : 'ブレイクパンチ',
                power : 1700
            },
            3 : {
                name : 'ブレイクパンチ',
                power : 2300
            },
            4 : {
                name : 'ブレイクパンチ',
                power : 2900
            },
            5 : {
                name : 'ブレイクパンチ',
                power : 3800
            }
        }
    },
    1 : {
        name : 'グランブレイバー',
        pictName : 'GranBraver.PNG',
        hp : 3200,
        speed : 250,
        active : 0,
        battery : 5,
        weapons : {
            1 : {
                name : 'バスターナックル',
                power : 800
            },
            2 : {
                name : 'バスターナックル',
                power : 1100
            },
            3 : {
                name : 'バスターナックル',
                power : 1600
            },
            4 : {
                name : 'バスターナックル',
                power : 2100
            },
            5 : {
                name : 'バスターナックル',
                power : 2800
            },
        }
    }
};

window.onload = function(){
    assert = chai.assert;
    firstPlayerAtack_asDefenther();
};

/**
 * 敵が攻撃を選択する
 */
function firstPlayerAtack_asDefenther(){
    var Game = game({
        statusArray : gbraverDebug.statusArray,
        userId : '2'
    });
    Game.start();
    Game.onReady(function() {
        var waitPhaseData = {
            phase : 'wait',
            atackUserId : '1',
            turn : 20,
            statusArray : {
                2 : {
                    hp : 4700,
                    battery : 5,
                    active : 3000
                },
                1 : {
                    hp : 3200,
                    battery : 5,
                    active : 5000
                }
            }
        };
        Game.doWaitPhase(waitPhaseData);
        Game.onCommand(function(command) {
            var data = {
                phase : 'atackCommand',
                statusArray : {
                    1 : {
                        hp : 3200,
                        battery : 5,
                        active : 5000
                    },
                    2 : {
                        hp : 4700,
                        battery : 5,
                        active : 3000
                    }
                }
            };
            Game.doAtackCommandPhase(data);
            Game.onCommand(function(command){
                var expect = {
                    method : 'ok'
                };
                assert.deepEqual(command,expect,'攻撃コマンドフェイズのコマンドが正しい');

                var data = {
                    phase : 'defenthCommand',
                    statusArray : {
                    1 : { hp : 3200,
                        battery : 5,
                        active : 5000
                        },
                        2 : { hp : 4700,
                            battery : 5,
                            active : 3000
                        }
                    }
                };
                Game.doDefenthCommandPhase(data);
                console.log('2で防御する');

                Game.onCommand(function(command){
                    var expect = {
                        method : 'defenth',
                        param : {
                            battery : 2
                        }
                    };
                    assert.deepEqual(command,expect,'防御コマンドフェイズのコマンドが正しい');

                    var data = {
                        phase : 'damage',
                        hit : 1,
                        damage : 1600,
                        atackBattery : 3,
                        defenthBattery : 2,
                        statusArray : {
                            1 : {
                                hp : 3200,
                                battery : 2,
                                active : 0
                            },
                            2 : {
                                hp : 3100,
                                battery : 3,
                                active : 3000
                            }
                        }
                    };
                    Game.doDamagePhase(data);
                    Game.onCommand(function(command){
                        var expect = {
                            method : 'ok'
                        };
                        assert.deepEqual(command,expect,'ウェイトフェイズ2のコマンドが正しい');

                        var data = {
                            phase : 'wait',
                            atackUserId : '2',
                            turn : 14,
                            statusArray : {
                            1 : { hp : 3200,
                                battery : 2,
                                active : 3500
                                },
                                2 : { hp : 3100,
                                    battery : 4,
                                    active : 5100
                                }
                            }
                        };
                        Game.doWaitPhase(data);
                        Game.onCommand(function(command){
                            console.log('finish');
                            $('title').text('finish');
                        });
                    });
                });

                //コマンド入力
                Game.rootScene.tl.delay(60).then(function() {
                    Game.plusBattery();
                }).delay(20).then(function() {
                    Game.selectBattery();
                });

            });
        });
    });
}<commit_msg>ゲーム画面敵攻撃テストをリファクタリングした。<commit_after>enchant();
var gbraverDebug = {};
var assert;

/**
 * テストデータ
 */
gbraverDebug.statusArray = {
    2 : {
        name : 'ランドーザ',
        pictName : 'Landozer.PNG',
        hp : 4700,
        speed : 150,
        active : 0,
        battery : 5,
        weapons : {
            1 : {
                name : 'ブレイクパンチ',
                power : 1200
            },
            2 : {
                name : 'ブレイクパンチ',
                power : 1700
            },
            3 : {
                name : 'ブレイクパンチ',
                power : 2300
            },
            4 : {
                name : 'ブレイクパンチ',
                power : 2900
            },
            5 : {
                name : 'ブレイクパンチ',
                power : 3800
            }
        }
    },
    1 : {
        name : 'グランブレイバー',
        pictName : 'GranBraver.PNG',
        hp : 3200,
        speed : 250,
        active : 0,
        battery : 5,
        weapons : {
            1 : {
                name : 'バスターナックル',
                power : 800
            },
            2 : {
                name : 'バスターナックル',
                power : 1100
            },
            3 : {
                name : 'バスターナックル',
                power : 1600
            },
            4 : {
                name : 'バスターナックル',
                power : 2100
            },
            5 : {
                name : 'バスターナックル',
                power : 2800
            },
        }
    }
};

window.onload = function(){
    assert = chai.assert;
    firstPlayerAtack_asDefenther();
};

/**
 * 敵が攻撃を選択する
 */
function firstPlayerAtack_asDefenther(){
    var Game = game({
        statusArray : gbraverDebug.statusArray,
        userId : '2'
    });
    Game.start();
    Game.onReady(waitPhase);

    function waitPhase(){
        var waitPhaseData = {
            phase : 'wait',
            atackUserId : '1',
            turn : 20,
            statusArray : {
                2 : {
                    hp : 4700,
                    battery : 5,
                    active : 3000
                },
                1 : {
                    hp : 3200,
                    battery : 5,
                    active : 5000
                }
            }
        };
        Game.doWaitPhase(waitPhaseData);
        Game.onCommand(atackCommandPhase);
    }

    function atackCommandPhase(command){
        var data = {
            phase : 'atackCommand',
            statusArray : {
                1 : {
                    hp : 3200,
                    battery : 5,
                    active : 5000
                },
                2 : {
                    hp : 4700,
                    battery : 5,
                    active : 3000
                }
            }
        };
        Game.doAtackCommandPhase(data);
        Game.onCommand(defenthCommandPhase);
    }

    function defenthCommandPhase(command) {
        var expect = {
            method : 'ok'
        };
        assert.deepEqual(command, expect, '攻撃コマンドフェイズのコマンドが正しい');

        var data = {
            phase : 'defenthCommand',
            statusArray : {
                1 : {
                    hp : 3200,
                    battery : 5,
                    active : 5000
                },
                2 : {
                    hp : 4700,
                    battery : 5,
                    active : 3000
                }
            }
        };
        Game.doDefenthCommandPhase(data);
        selectCommnad();
    }

    function selectCommnad(){
        Game.onCommand(damagePhase);

        Game.rootScene.tl.delay(60).then(function() {
            Game.plusBattery();
        }).delay(20).then(function() {
            Game.selectBattery();
        });

    }

    function damagePhase(command) {
        var expect = {

            method : 'defenth',
            param : {
                battery : 2
            }
        };
        assert.deepEqual(command, expect, '防御コマンドフェイズのコマンドが正しい');

        var data = {
            phase : 'damage',
            hit : 1,
            damage : 1600,
            atackBattery : 3,
            defenthBattery : 2,
            statusArray : {
                1 : {
                    hp : 3200,
                    battery : 2,
                    active : 0
                },
                2 : {
                    hp : 3100,
                    battery : 3,
                    active : 3000
                }
            }
        };
        Game.doDamagePhase(data);
        Game.onCommand(waitPhase2);
    }

    function waitPhase2(command){
        var expect = {
            method : 'ok'
        };
        assert.deepEqual(command, expect, 'ウェイトフェイズ2のコマンドが正しい');

        var data = {
            phase : 'wait',
            atackUserId : '2',
            turn : 14,
            statusArray : {
                1 : {
                    hp : 3200,
                    battery : 2,
                    active : 3500
                },
                2 : {
                    hp : 3100,
                    battery : 4,
                    active : 5100
                }
            }
        };
        Game.doWaitPhase(data);
        Game.onCommand(function(command) {
            console.log('finish');
            $('title').text('finish');
        });
    }
}<|endoftext|>


<commit_before>
/*
    Node.js web and websocket server for working with the API quark.

    This allows javascript on webpages to easily communicate with a running SuperCollider language application via APIs.

    Start SuperCollider
    Install the API quark ( > 2.0 )
    Activate the OSC responders: API.mountHTTP
    Start this server:
        node api_server.js
    Navigate to http://localhost:4040

    Have fun

*/
var express = require('express'),
    app = express(),
    http = require('http'),
    server = http.createServer(app),
    io = require('socket.io').listen(server),
    host = "localhost",
    port = 4040;

var dgram = require('dgram'),
    osc = require('osc-min'),
    udp = dgram.createSocket("udp4");

var scport = 57120,
    schost = "localhost";

var sockets = {};

server.listen(port);
console.log("Listening on http://localhost:" + port);

app.get('/', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/templates/index.html');
});

app.get('/fiddle', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/templates/fiddle.html');
});

app.get('/media/js/scapi.js', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/lib/browser/scapi.js');
});

app.use("/socket.io",
    express.static(__dirname + '/node_modules/socket.io/lib'));

// call API via OSC
function call(client_id, request_id, path, args) {
    var a = [client_id, request_id, path];
    args = a.concat(args);
    console.log(args);

    var buf = osc.toBuffer({
        address : '/API/http/call',
        args : args
    });
    udp.send(buf, 0, buf.length, scport, schost);
}

// receive response from API via OSC and forward it to websocket
function reply(signal, msg) {
    var client_id = msg.args[0].value,
        request_id = msg.args[1].value,
        result = msg.args[2].value;

    // socket.io does not yet have a way to fetch socket by id
    // so must store them in this process
    var socket = sockets[client_id];

    if(socket && (!socket.disconnected)) {
        socket.emit(signal, {'request_id': request_id, 'result': result });
    } else {
        // should splice the array out so it doesn't build up empty ids
        console.log("client socket gone away" + client_id);
    }
}

// receive OSC
udp.on('message', function(msgbuf, rinfo) {
    var msg = osc.fromBuffer(msgbuf);
    //console.log("message");
    //console.log(msg);
    if(msg.address === '/API/http/not_found') {
        return reply('scapi_error', msg);
    }
    if(msg.address === '/API/http/error') {
        return reply('scapi_error', msg);
    }
    if(msg.address === '/API/http/reply') {
        return reply('reply', msg);
    }
});

// udp.on('error')

// incoming websockets
io.sockets.on('connection', function(socket) {

    console.log("connection");
    //console.log(socket);

    socket.emit('hello', { msg: 'connected' });
    socket.on('call', function (data) {
        // console.log("CALLING");
        // console.log(data.path);
        // console.log(data.args);
        sockets[socket.id] = socket;
        call(socket.id, data.request_id, data.path, data.args);

    });
});

// TODO on disconnect, forget the socket

<commit_msg>renamed OSC endpoints<commit_after>
/*
    Node.js web and websocket server for working with the API quark.

    This allows javascript on webpages to easily communicate with a running SuperCollider language application via APIs.

    Start SuperCollider
    Install the API quark ( > 2.0 )
    Activate the OSC responders: API.mountHTTP
    Start this server:
        node api_server.js
    Navigate to http://localhost:4040

    Have fun

*/
var express = require('express'),
    app = express(),
    http = require('http'),
    server = http.createServer(app),
    io = require('socket.io').listen(server),
    host = "localhost",
    port = 4040;

var dgram = require('dgram'),
    osc = require('osc-min'),
    udp = dgram.createSocket("udp4");

var scport = 57120,
    schost = "localhost";

var sockets = {};

server.listen(port);
console.log("Listening on http://localhost:" + port);

app.get('/', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/templates/index.html');
});

app.get('/fiddle', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/templates/fiddle.html');
});

app.get('/media/js/scapi.js', function (req, res) {
    // will display api index
    res.sendfile(__dirname + '/lib/browser/scapi.js');
});

app.use("/socket.io",
    express.static(__dirname + '/node_modules/socket.io/lib'));

// call API via OSC
function call(client_id, request_id, path, args) {
    var a = [client_id, request_id, path];
    args = a.concat(args);
    console.log(args);

    var buf = osc.toBuffer({
        address : '/API/call',
        args : args
    });
    udp.send(buf, 0, buf.length, scport, schost);
}

// receive response from API via OSC and forward it to websocket
function reply(signal, msg) {
    var client_id = msg.args[0].value,
        request_id = msg.args[1].value,
        result = msg.args[2].value;

    // socket.io does not yet have a way to fetch socket by id
    // so must store them in this process
    var socket = sockets[client_id];

    if(socket && (!socket.disconnected)) {
        socket.emit(signal, {'request_id': request_id, 'result': result });
    } else {
        // should splice the array out so it doesn't build up empty ids
        console.log("client socket gone away" + client_id);
    }
}

// receive OSC
udp.on('message', function(msgbuf, rinfo) {
    var msg = osc.fromBuffer(msgbuf);
    //console.log("message");
    //console.log(msg);
    // console.log(rinfo);
    if(msg.address === '/API/not_found') {
        return reply('scapi_error', msg);
    }
    if(msg.address === '/API/error') {
        return reply('scapi_error', msg);
    }
    if(msg.address === '/API/reply') {
        return reply('reply', msg);
    }
});

// udp.on('error')

// incoming websockets
io.sockets.on('connection', function(socket) {

    console.log("connection");
    //console.log(socket);

    socket.emit('hello', { msg: 'connected' });
    socket.on('call', function (data) {
        // console.log("CALLING");
        // console.log(data.path);
        // console.log(data.args);
        sockets[socket.id] = socket;
        call(socket.id, data.request_id, data.path, data.args);

    });
});

// TODO on disconnect, forget the socket

<|endoftext|>


<commit_before>/*
 * L.Canvas handles Canvas vector layers rendering and mouse events handling. All Canvas-specific code goes here.
 */

L.Canvas = L.Renderer.extend({

	onAdd: function () {
		L.Renderer.prototype.onAdd.call(this);

		this._layers = this._layers || {};

		// redraw vectors since canvas is cleared upon removal
		this._draw();
	},

	_initContainer: function () {
		var container = this._container = document.createElement('canvas');

		L.DomEvent
			.on(container, 'mousemove', L.Util.throttle(this._onMouseMove, 66, this), this)
			.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)
			.on(container, 'mouseout', this._handleMouseOut, this);

		this._ctx = container.getContext('2d');
	},

	_update: function () {
		if (this._map._animatingZoom && this._bounds) { return; }

		this._drawnLayers = {};

		L.Renderer.prototype._update.call(this);

		var b = this._bounds,
		    container = this._container,
		    size = b.getSize(),
		    m = L.Browser.retina ? 2 : 1;

		L.DomUtil.setPosition(container, b.min);

		// set canvas size (also clearing it); use double size on retina
		container.width = m * size.x;
		container.height = m * size.y;
		container.style.width = size.x + 'px';
		container.style.height = size.y + 'px';

		if (L.Browser.retina) {
			this._ctx.scale(2, 2);
		}

		// translate so we use the same path coordinates after canvas element moves
		this._ctx.translate(-b.min.x, -b.min.y);
	},

	_initPath: function (layer) {
		this._layers[L.stamp(layer)] = layer;
	},

	_addPath: L.Util.falseFn,

	_removePath: function (layer) {
		layer._removed = true;
		this._requestRedraw(layer);
	},

	_updatePath: function (layer) {
		this._redrawBounds = layer._pxBounds;
		this._draw(true);
		layer._project();
		layer._update();
		this._draw();
		this._redrawBounds = null;
	},

	_updateStyle: function (layer) {
		this._requestRedraw(layer);
	},

	_requestRedraw: function (layer) {
		if (!this._map) { return; }

		this._redrawBounds = this._redrawBounds || new L.Bounds();
		this._redrawBounds.extend(layer._pxBounds.min).extend(layer._pxBounds.max);

		this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._redraw, this);
	},

	_redraw: function () {
		this._redrawRequest = null;

		this._draw(true); // clear layers in redraw bounds
		this._draw(); // draw layers

		this._redrawBounds = null;
	},

	_draw: function (clear) {
		this._clear = clear;
		var layer;

		for (var id in this._layers) {
			layer = this._layers[id];

			if (clear && layer._removed) {
				delete layer._removed;
				delete this._layers[id];

			} else if (!this._redrawBounds || layer._pxBounds.intersects(this._redrawBounds)) {
				layer._updatePath();
			}
		}
	},

	_updatePoly: function (layer, closed) {

		var i, j, len2, p,
		    parts = layer._parts,
		    len = parts.length,
		    ctx = this._ctx;

		if (!len) { return; }

		this._drawnLayers[layer._leaflet_id] = layer;

		ctx.beginPath();

		for (i = 0; i < len; i++) {
			for (j = 0, len2 = parts[i].length; j < len2; j++) {
				p = parts[i][j];
				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
			}
			if (closed) {
				ctx.closePath();
			}
		}

		this._fillStroke(ctx, layer);

		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
	},

	_updateCircle: function (layer) {

		if (layer._empty()) { return; }

		var p = layer._point,
		    ctx = this._ctx,
		    r = layer._radius,
		    s = (layer._radiusY || r) / r;

		if (s !== 1) {
			ctx.save();
			ctx.scale(1, s);
		}

		ctx.beginPath();
		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);

		if (s !== 1) {
			ctx.restore();
		}

		this._fillStroke(ctx, layer);
	},

	_fillStroke: function (ctx, layer) {
		var clear = this._clear,
		    options = layer.options;

		ctx.globalCompositeOperation = clear ? 'destination-out' : 'source-over';

		if (options.fill) {
			ctx.globalAlpha = clear ? 1 : options.fillOpacity;
			ctx.fillStyle = options.fillColor || options.color;
			ctx.fill(options.fillRule || 'evenodd');
		}

		if (options.stroke && options.weight !== 0) {
			ctx.globalAlpha = clear ? 1 : options.opacity;

			// if clearing shape, do it with the previously drawn line width
			layer._prevWeight = ctx.lineWidth = clear ? layer._prevWeight + 1 : options.weight;

			ctx.strokeStyle = options.color;
			ctx.lineCap = options.lineCap;
			ctx.lineJoin = options.lineJoin;
			ctx.stroke();
		}
	},

	// Canvas obviously doesn't have mouse events for individual drawn objects,
	// so we emulate that by calculating what's under the mouse on mousemove/click manually

	_onClick: function (e) {
		var point = this._map.mouseEventToLayerPoint(e);

		for (var id in this._layers) {
			if (this._layers[id]._containsPoint(point)) {
				L.DomEvent._fakeStop(e);
				this._fireEvent(this._layers[id], e);
			}
		}
	},

	_onMouseMove: function (e) {
		if (!this._map || this._map.dragging._draggable._moving || this._map._animatingZoom) { return; }

		var point = this._map.mouseEventToLayerPoint(e);
		this._handleMouseOut(e, point);
		this._handleMouseHover(e, point);
	},

	_handleMouseOut: function (e, point) {
		var layer = this._hoveredLayer;
		if (layer && (e.type === 'mouseout' || !layer._containsPoint(point))) {
			// if we're leaving the layer, fire mouseout
			L.DomUtil.removeClass(this._container, 'leaflet-interactive');
			this._fireEvent(layer, e, 'mouseout');
			this._hoveredLayer = null;
		}
	},

	_handleMouseHover: function (e, point) {
		var id, layer;
		if (!this._hoveredLayer) {
			for (id in this._drawnLayers) {
				layer = this._drawnLayers[id];
				if (layer.options.interactive && layer._containsPoint(point)) {
					L.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
					this._fireEvent(layer, e, 'mouseover');
					this._hoveredLayer = layer;
					break;
				}
			}
		}
		if (this._hoveredLayer) {
			this._fireEvent(this._hoveredLayer, e);
		}
	},

	_fireEvent: function (layer, e, type) {
		this._map._fireDOMEvent(e, type || e.type, [layer]);
	},

	// TODO _bringToFront & _bringToBack, pretty tricky

	_bringToFront: L.Util.falseFn,
	_bringToBack: L.Util.falseFn
});

L.Browser.canvas = (function () {
	return !!document.createElement('canvas').getContext;
}());

L.canvas = function (options) {
	return L.Browser.canvas ? new L.Canvas(options) : null;
};

L.Polyline.prototype._containsPoint = function (p, closed) {
	var i, j, k, len, len2, part,
	    w = this._clickTolerance();

	if (!this._pxBounds.contains(p)) { return false; }

	// hit detection for polylines
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			if (!closed && (j === 0)) { continue; }

			if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
				return true;
			}
		}
	}
	return false;
};

L.Polygon.prototype._containsPoint = function (p) {
	var inside = false,
	    part, p1, p2, i, j, k, len, len2;

	if (!this._pxBounds.contains(p)) { return false; }

	// ray casting algorithm for detecting if point is in polygon
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			p1 = part[j];
			p2 = part[k];

			if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
				inside = !inside;
			}
		}
	}

	// also check if it's on polygon stroke
	return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
};

L.CircleMarker.prototype._containsPoint = function (p) {
	return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
};
<commit_msg>reduce the throttle for canvas layers<commit_after>/*
 * L.Canvas handles Canvas vector layers rendering and mouse events handling. All Canvas-specific code goes here.
 */

L.Canvas = L.Renderer.extend({

	onAdd: function () {
		L.Renderer.prototype.onAdd.call(this);

		this._layers = this._layers || {};

		// redraw vectors since canvas is cleared upon removal
		this._draw();
	},

	_initContainer: function () {
		var container = this._container = document.createElement('canvas');

		L.DomEvent
			.on(container, 'mousemove', L.Util.throttle(this._onMouseMove, 32, this), this)
			.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)
			.on(container, 'mouseout', this._handleMouseOut, this);

		this._ctx = container.getContext('2d');
	},

	_update: function () {
		if (this._map._animatingZoom && this._bounds) { return; }

		this._drawnLayers = {};

		L.Renderer.prototype._update.call(this);

		var b = this._bounds,
		    container = this._container,
		    size = b.getSize(),
		    m = L.Browser.retina ? 2 : 1;

		L.DomUtil.setPosition(container, b.min);

		// set canvas size (also clearing it); use double size on retina
		container.width = m * size.x;
		container.height = m * size.y;
		container.style.width = size.x + 'px';
		container.style.height = size.y + 'px';

		if (L.Browser.retina) {
			this._ctx.scale(2, 2);
		}

		// translate so we use the same path coordinates after canvas element moves
		this._ctx.translate(-b.min.x, -b.min.y);
	},

	_initPath: function (layer) {
		this._layers[L.stamp(layer)] = layer;
	},

	_addPath: L.Util.falseFn,

	_removePath: function (layer) {
		layer._removed = true;
		this._requestRedraw(layer);
	},

	_updatePath: function (layer) {
		this._redrawBounds = layer._pxBounds;
		this._draw(true);
		layer._project();
		layer._update();
		this._draw();
		this._redrawBounds = null;
	},

	_updateStyle: function (layer) {
		this._requestRedraw(layer);
	},

	_requestRedraw: function (layer) {
		if (!this._map) { return; }

		this._redrawBounds = this._redrawBounds || new L.Bounds();
		this._redrawBounds.extend(layer._pxBounds.min).extend(layer._pxBounds.max);

		this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._redraw, this);
	},

	_redraw: function () {
		this._redrawRequest = null;

		this._draw(true); // clear layers in redraw bounds
		this._draw(); // draw layers

		this._redrawBounds = null;
	},

	_draw: function (clear) {
		this._clear = clear;
		var layer;

		for (var id in this._layers) {
			layer = this._layers[id];

			if (clear && layer._removed) {
				delete layer._removed;
				delete this._layers[id];

			} else if (!this._redrawBounds || layer._pxBounds.intersects(this._redrawBounds)) {
				layer._updatePath();
			}
		}
	},

	_updatePoly: function (layer, closed) {

		var i, j, len2, p,
		    parts = layer._parts,
		    len = parts.length,
		    ctx = this._ctx;

		if (!len) { return; }

		this._drawnLayers[layer._leaflet_id] = layer;

		ctx.beginPath();

		for (i = 0; i < len; i++) {
			for (j = 0, len2 = parts[i].length; j < len2; j++) {
				p = parts[i][j];
				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
			}
			if (closed) {
				ctx.closePath();
			}
		}

		this._fillStroke(ctx, layer);

		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
	},

	_updateCircle: function (layer) {

		if (layer._empty()) { return; }

		var p = layer._point,
		    ctx = this._ctx,
		    r = layer._radius,
		    s = (layer._radiusY || r) / r;

		if (s !== 1) {
			ctx.save();
			ctx.scale(1, s);
		}

		ctx.beginPath();
		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);

		if (s !== 1) {
			ctx.restore();
		}

		this._fillStroke(ctx, layer);
	},

	_fillStroke: function (ctx, layer) {
		var clear = this._clear,
		    options = layer.options;

		ctx.globalCompositeOperation = clear ? 'destination-out' : 'source-over';

		if (options.fill) {
			ctx.globalAlpha = clear ? 1 : options.fillOpacity;
			ctx.fillStyle = options.fillColor || options.color;
			ctx.fill(options.fillRule || 'evenodd');
		}

		if (options.stroke && options.weight !== 0) {
			ctx.globalAlpha = clear ? 1 : options.opacity;

			// if clearing shape, do it with the previously drawn line width
			layer._prevWeight = ctx.lineWidth = clear ? layer._prevWeight + 1 : options.weight;

			ctx.strokeStyle = options.color;
			ctx.lineCap = options.lineCap;
			ctx.lineJoin = options.lineJoin;
			ctx.stroke();
		}
	},

	// Canvas obviously doesn't have mouse events for individual drawn objects,
	// so we emulate that by calculating what's under the mouse on mousemove/click manually

	_onClick: function (e) {
		var point = this._map.mouseEventToLayerPoint(e);

		for (var id in this._layers) {
			if (this._layers[id]._containsPoint(point)) {
				L.DomEvent._fakeStop(e);
				this._fireEvent(this._layers[id], e);
			}
		}
	},

	_onMouseMove: function (e) {
		if (!this._map || this._map.dragging._draggable._moving || this._map._animatingZoom) { return; }

		var point = this._map.mouseEventToLayerPoint(e);
		this._handleMouseOut(e, point);
		this._handleMouseHover(e, point);
	},

	_handleMouseOut: function (e, point) {
		var layer = this._hoveredLayer;
		if (layer && (e.type === 'mouseout' || !layer._containsPoint(point))) {
			// if we're leaving the layer, fire mouseout
			L.DomUtil.removeClass(this._container, 'leaflet-interactive');
			this._fireEvent(layer, e, 'mouseout');
			this._hoveredLayer = null;
		}
	},

	_handleMouseHover: function (e, point) {
		var id, layer;
		if (!this._hoveredLayer) {
			for (id in this._drawnLayers) {
				layer = this._drawnLayers[id];
				if (layer.options.interactive && layer._containsPoint(point)) {
					L.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
					this._fireEvent(layer, e, 'mouseover');
					this._hoveredLayer = layer;
					break;
				}
			}
		}
		if (this._hoveredLayer) {
			this._fireEvent(this._hoveredLayer, e);
		}
	},

	_fireEvent: function (layer, e, type) {
		this._map._fireDOMEvent(e, type || e.type, [layer]);
	},

	// TODO _bringToFront & _bringToBack, pretty tricky

	_bringToFront: L.Util.falseFn,
	_bringToBack: L.Util.falseFn
});

L.Browser.canvas = (function () {
	return !!document.createElement('canvas').getContext;
}());

L.canvas = function (options) {
	return L.Browser.canvas ? new L.Canvas(options) : null;
};

L.Polyline.prototype._containsPoint = function (p, closed) {
	var i, j, k, len, len2, part,
	    w = this._clickTolerance();

	if (!this._pxBounds.contains(p)) { return false; }

	// hit detection for polylines
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			if (!closed && (j === 0)) { continue; }

			if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
				return true;
			}
		}
	}
	return false;
};

L.Polygon.prototype._containsPoint = function (p) {
	var inside = false,
	    part, p1, p2, i, j, k, len, len2;

	if (!this._pxBounds.contains(p)) { return false; }

	// ray casting algorithm for detecting if point is in polygon
	for (i = 0, len = this._parts.length; i < len; i++) {
		part = this._parts[i];

		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
			p1 = part[j];
			p2 = part[k];

			if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
				inside = !inside;
			}
		}
	}

	// also check if it's on polygon stroke
	return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
};

L.CircleMarker.prototype._containsPoint = function (p) {
	return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
};
<|endoftext|>