<commit_before>angular.module('ngCloudMine', [])

.service('cmWS', ['$q', function($q) {
  var service = {};

  var distanceRE = /#{distance}/,
      latRE = /#{lat}/,
      longRE = /#{long}/;

  function arrayify(data) {
    var ary = [];

    for (var key in data) {
      var obj = data[key];

      ary.push(obj);
      ary[key] = obj;
    }

    return ary;
  };

  function checkDistanceParams(query, options, distance, lat, long) {
    var errorString = null;

    if (!query) {
      errorString = 'Missing query';
    } else if (!options) {
      errorString = 'Missing options';
    } else if (!distance) {
      errorString = 'Missing distance';
    } else if (!lat) {
      errorString = 'Missing latitude';
    } else if (!long) {
      errorString = 'Missing longitude';
    } else if (!query.match(distanceRE)) {
      errorString = 'Missing distance variable in query';
    } else if (!query.match(latRE)) {
      errorString = 'Missing latitude variable in query';
    } else if (!query.match(longRE)) {
      errorString = 'Missing longitude variable in query';
    }

    return errorString;
  }

  function distanceQuery(query, distance, lat, long) {
    query = query.replace(distanceRE, distance);
    query = query.replace(latRE, lat);
    query = query.replace(longRE, long);

    return query;
  };

  function calculateCount(pager) {
    return service.getSearchCount(pager.query, angular.copy(pager.options))
    .then(function(total) {
      pager.total = total;
      calcTotalPages(pager);

      return pager;
    });
  };

  function calcTotalPages(pager) {
    pager.totalPages = Math.ceil(pager.total / pager.countPerPage);
  };

  function deferSuccessAndError(method, args) {
    return deferSuccessAndErrorWithHandlers(method, args);
  };

  function deferSuccessAndErrorWithHandlers(method, args, successHandler, errorHandler) {
    var deferred = $q.defer();

    if (!successHandler) successHandler = function(data, meta, deferred) {
      deferred.resolve(data);
    };

    if (!errorHandler) errorHandler = function(err, deferred) {
      deferred.reject(err);
    };

    window.ws[method].apply(window.ws, args)
    .on('success', function(data, meta) {
      successHandler(arrayify(data), meta, deferred);
    }).on('error', function(err) {
      errorHandler(err, deferred);
    });

    return deferred.promise;
  };

  service.search = function(query, options) {
    return deferSuccessAndError('search', [query, options]);
  };

  service.logout = function(email, password, options) {
    return deferSuccessAndError('logout', []);
  };

  service.set = function(id, object, options) {
    return deferSuccessAndError('set', [id, object, options]);
  };

  service.update = function(id, object, options) {
    return deferSuccessAndError('update', [id, object, options]);
  };

  service.login =  function(email, password, options) {
    return deferSuccessAndError('login', [email, password, options]);
  };

  service.getSearchCount = function(query, options) {
    if (!options) {
      options = {};
    }

    options.applevel = true;
    options.limit = 0;
    options.count = true;

    return deferSuccessAndErrorWithHandlers('search', [query, options], function(data, meta, deferred) {
      deferred.resolve(meta.count);
    });
  };

  service.getDistanceCount = function(query, options, distance, lat, long) {
    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    options.limit = 0;
    options.count = true;
    query = distanceQuery(query, distance, lat, long);

    return deferSuccessAndErrorWithHandlers('search', [query, options], function(data, meta, deferred) {
      deferred.resolve(meta.count);
    });
  };

  service.getDistance = function(query, options, distance, lat, long) {
    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    options.distance = true;
    query = distanceQuery(query, distance, lat, long);

    return deferSuccessAndErrorWithHandlers('search', [query, options], function(data, meta, deferred) {
      for (metaKey in meta) {
        var metaData = meta[metaKey];

        if (data[metaKey] && meta[metaKey].geo && meta[metaKey].geo.distance) {
          data[metaKey].distance = meta[metaKey].geo.distance;
        }
      }

      deferred.resolve(data);
    });
  };

  service.getPager = function(countPerPage, query, options, updater) {
    if (!options) {
      options = {applevel: true};
    }

    if (!updater) {
      updater = function(data) {
        return data;
      };
    }

    var pager = {
      query: query,
      total: 0,
      countPerPage: countPerPage,
      totalPages: 0,
      page: 0,

      setPerPage: function(perPage) {
        pager.countPerPage = perPage;
        calcTotalPages(pager);

        //TODO: Calculate new page to keep first item on page
        this.page = 0;

        var deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
      },

      setQuery: function(query) {
        pager.query = query;
        return calculateCount(pager);
      },

      getPage: function(page) {
        var opts = angular.copy(options);
        this.page = page;

        if (page < 0 || page >= this.totalPages) {
          return $q.reject('Page doesn\'t exist');
        }

        opts.limit = this.countPerPage;
        opts.skip = page * this.countPerPage;

        return deferSuccessAndError('search', [this.query, opts]).then(updater);
      }
    };

    return calculateCount(pager);
  };

  service.getDistancePager = function(countPerPage, query, distance, lat, long, options, updater) {
    if (!options) {
      options = {};
    }

    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    return this.getPager(
      countPerPage,
      distanceQuery(query, distance, lat, long),
      options, updater
    ).then(function(pager) {
      pager.originalQuery = query;
      pager.setDistanceLatAndLong = function(distance, lat, long) {
        var newDistanceQuery = distanceQuery(
          angular.copy(pager.originalQuery),
          distance, lat, long
        );

        pager.query = newDistanceQuery;

        return calculateCount(pager);
      };

      return pager;
    });
  };

  return service;
}]);
<commit_msg>Refactor<commit_after>angular.module('ngCloudMine', [])

.service('cmWS', ['$q', function($q) {
  var service = {};

  var distanceRE = /#{distance}/,
      latRE = /#{lat}/,
      longRE = /#{long}/;

  function arrayify(data) {
    var ary = [];

    for (var key in data) {
      var obj = data[key];

      ary.push(obj);
      ary[key] = obj;
    }

    return ary;
  };

  function checkDistanceParams(query, options, distance, lat, long) {
    var errorString = null;

    if (!query) {
      errorString = 'Missing query';
    } else if (!options) {
      errorString = 'Missing options';
    } else if (!distance) {
      errorString = 'Missing distance';
    } else if (!lat) {
      errorString = 'Missing latitude';
    } else if (!long) {
      errorString = 'Missing longitude';
    } else if (!query.match(distanceRE)) {
      errorString = 'Missing distance variable in query';
    } else if (!query.match(latRE)) {
      errorString = 'Missing latitude variable in query';
    } else if (!query.match(longRE)) {
      errorString = 'Missing longitude variable in query';
    }

    return errorString;
  }

  function distanceQuery(query, distance, lat, long) {
    query = query.replace(distanceRE, distance);
    query = query.replace(latRE, lat);
    query = query.replace(longRE, long);

    return query;
  };

  function calculateCount(pager) {
    return service.getSearchCount(pager.query, angular.copy(pager.options))
    .then(function(total) {
      pager.total = total;
      calcTotalPages(pager);

      return pager;
    });
  };

  function calcTotalPages(pager) {
    pager.totalPages = Math.ceil(pager.total / pager.countPerPage);
  };

  function deferSuccessAndError(method, args) {
    return deferSuccessAndErrorWithHandlers(method, args);
  };

  function deferSuccessAndErrorWithHandlers(method, args, successHandler, errorHandler) {
    var deferred = $q.defer();

    if (!successHandler) successHandler = function(data, meta, deferred) {
      deferred.resolve(data);
    };

    if (!errorHandler) errorHandler = function(err, deferred) {
      deferred.reject(err);
    };

    window.ws[method].apply(window.ws, args)
    .on('success', function(data, meta) {
      successHandler(arrayify(data), meta, deferred);
    }).on('error', function(err) {
      errorHandler(err, deferred);
    });

    return deferred.promise;
  };

  service.search = function(query, options) {
    return deferSuccessAndError('search', [query, options]);
  };

  service.logout = function(email, password, options) {
    return deferSuccessAndError('logout', []);
  };

  service.set = function(id, object, options) {
    return deferSuccessAndError('set', [id, object, options]);
  };

  service.update = function(id, object, options) {
    return deferSuccessAndError('update', [id, object, options]);
  };

  service.login =  function(email, password, options) {
    return deferSuccessAndError('login', [email, password, options]);
  };

  service.getSearchCount = function(query, options) {
    if (!options) {
      options = {};
    }

    options.applevel = true;
    options.limit = 0;
    options.count = true;

    return deferSuccessAndErrorWithHandlers('search', [query, options], function(data, meta, deferred) {
      deferred.resolve(meta.count);
    });
  };

  service.getDistanceCount = function(query, options, distance, lat, long) {
    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    return service.getSearchCount(
      distanceQuery(query, distance, lat, long), options
    );
  };

  service.getDistance = function(query, options, distance, lat, long) {
    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    options.distance = true;
    query = distanceQuery(query, distance, lat, long);

    return deferSuccessAndErrorWithHandlers('search', [query, options], function(data, meta, deferred) {
      for (metaKey in meta) {
        var metaData = meta[metaKey];

        if (data[metaKey] && meta[metaKey].geo && meta[metaKey].geo.distance) {
          data[metaKey].distance = meta[metaKey].geo.distance;
        }
      }

      deferred.resolve(data);
    });
  };

  service.getPager = function(countPerPage, query, options, updater) {
    if (!options) {
      options = {applevel: true};
    }

    if (!updater) {
      updater = function(data) {
        return data;
      };
    }

    var pager = {
      query: query,
      total: 0,
      countPerPage: countPerPage,
      totalPages: 0,
      page: 0,

      setPerPage: function(perPage) {
        pager.countPerPage = perPage;
        calcTotalPages(pager);

        //TODO: Calculate new page to keep first item on page
        this.page = 0;

        var deferred = $q.defer();
        deferred.resolve();
        return deferred.promise;
      },

      setQuery: function(query) {
        pager.query = query;
        return calculateCount(pager);
      },

      getPage: function(page) {
        var opts = angular.copy(options);
        this.page = page;

        if (page < 0 || page >= this.totalPages) {
          return $q.reject('Page doesn\'t exist');
        }

        opts.limit = this.countPerPage;
        opts.skip = page * this.countPerPage;

        return deferSuccessAndError('search', [this.query, opts]).then(updater);
      }
    };

    return calculateCount(pager);
  };

  service.getDistancePager = function(countPerPage, query, distance, lat, long, options, updater) {
    if (!options) {
      options = {};
    }

    var errorMessage = checkDistanceParams(query, options, distance, lat, long);
    if (errorMessage) {
      return $q.reject(errorMessage);
    }

    return this.getPager(
      countPerPage,
      distanceQuery(query, distance, lat, long),
      options, updater
    ).then(function(pager) {
      pager.originalQuery = query;
      pager.setDistanceLatAndLong = function(distance, lat, long) {
        var newDistanceQuery = distanceQuery(
          angular.copy(pager.originalQuery),
          distance, lat, long
        );

        pager.query = newDistanceQuery;

        return calculateCount(pager);
      };

      return pager;
    });
  };

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


<commit_before>const Connection = require('./connection')
const pckg = require('../package.json')
const util = require('util')

/**
 * A [deepstream](http://deepstream.io) cache connector
 * for [Redis](http://redis.io)
 *
 * Since Redis, on top of caching key/value combinations in
 * memory, writes them to disk it can make a storage connector
 * obsolete
 *
 * @param {Object} options redis connection options. Please see ./connection.js
 *                         for details
 *
 * @constructor
 */
const CacheConnector = function (options) {
  Connection.call(this, options)

  this.name = pckg.name
  this.version = pckg.version
}

util.inherits(CacheConnector, Connection)

/**
 * Gracefully close the connection to redis
 *
 * Called when deepstream.close() is invoked.
 * Emits 'close' event to notify deepstream of clean closure.
 *
 * @public
 * @returns {void}
 */
CacheConnector.prototype.close = function () {
  this.client.removeAllListeners('end')
  this.client.once('end', this.emit.bind(this, 'close'))
  this.client.quit()
}

/**
 * Deletes an entry from the cache.
 *
 * @param   {String}   key
 * @param   {Function} callback Will be called with null for successful deletions or
 *                              with an error message
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.delete = function (key, callback) {
  this.client.del(key, callback)
}

/**
 * Writes a value to the cache.
 *
 * @param {String}   key
 * @param {Object}   value
 * @param {Function} callback Will be called with null for successful set operations or
 *                            with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.set = function (key, value, callback) {
  this.client.set(key, JSON.stringify(value), callback)
}

/**
 * Retrieves a value from the cache
 *
 * @param {String}   key
 * @param {Function} callback Will be called with null and the originally stored object
 *                            for successful operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.get = function (key, callback) {
  this.client.get(key, (error, result) => {
    let parsedResult

    if (result === null) {
      callback(error, null)
      return
    }

    try {
      parsedResult = JSON.parse(result)
    } catch (e) {
      callback(e)
      return
    }

    callback(null, parsedResult)
  })
}

module.exports = CacheConnector
<commit_msg>Fix: use strict for node4 build<commit_after>'use strict'

const Connection = require('./connection')
const pckg = require('../package.json')
const util = require('util')

/**
 * A [deepstream](http://deepstream.io) cache connector
 * for [Redis](http://redis.io)
 *
 * Since Redis, on top of caching key/value combinations in
 * memory, writes them to disk it can make a storage connector
 * obsolete
 *
 * @param {Object} options redis connection options. Please see ./connection.js
 *                         for details
 *
 * @constructor
 */
const CacheConnector = function (options) {
  Connection.call(this, options)

  this.name = pckg.name
  this.version = pckg.version
}

util.inherits(CacheConnector, Connection)

/**
 * Gracefully close the connection to redis
 *
 * Called when deepstream.close() is invoked.
 * Emits 'close' event to notify deepstream of clean closure.
 *
 * @public
 * @returns {void}
 */
CacheConnector.prototype.close = function () {
  this.client.removeAllListeners('end')
  this.client.once('end', this.emit.bind(this, 'close'))
  this.client.quit()
}

/**
 * Deletes an entry from the cache.
 *
 * @param   {String}   key
 * @param   {Function} callback Will be called with null for successful deletions or
 *                              with an error message
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.delete = function (key, callback) {
  this.client.del(key, callback)
}

/**
 * Writes a value to the cache.
 *
 * @param {String}   key
 * @param {Object}   value
 * @param {Function} callback Will be called with null for successful set operations or
 *                            with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.set = function (key, value, callback) {
  this.client.set(key, JSON.stringify(value), callback)
}

/**
 * Retrieves a value from the cache
 *
 * @param {String}   key
 * @param {Function} callback Will be called with null and the originally stored object
 *                            for successful operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.get = function (key, callback) {
  this.client.get(key, (error, result) => {
    let parsedResult

    if (result === null) {
      callback(error, null)
      return
    }

    try {
      parsedResult = JSON.parse(result)
    } catch (e) {
      callback(e)
      return
    }

    callback(null, parsedResult)
  })
}

module.exports = CacheConnector
<|endoftext|>


<commit_before>var Connection = require( './connection' )
var pckg = require( '../package.json' )
var util = require( 'util' )

/**
 * A [deepstream](http://deepstream.io) cache connector
 * for [Redis](http://redis.io)
 *
 * Since Redis, on top of caching key/value combinations in
 * memory, writes them to disk it can make a storage connector
 * obsolete
 *
 * @param {Object} options redis connection options. Please see ./connection.js
 *                         for details
 *
 * @constructor
 */
var CacheConnector = function( options ) {
  Connection.call( this, options )

  this.name = pckg.name
  this.version = pckg.version
}

util.inherits( CacheConnector, Connection )

/**
 * Deletes an entry from the cache.
 *
 * @param   {String}   key
 * @param   {Function} callback Will be called with null for successful deletions or with an error message
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.delete = function( key, callback ) {
  this.client.del( key, callback )
}

/**
 * Writes a value to the cache.
 *
 * @param {String}   key
 * @param {Object}   value
 * @param {Function} callback Will be called with null for successful set operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.set = function( key, value, callback ) {
  this.client.set( key, JSON.stringify( value ), callback )
}

/**
 * Retrieves a value from the cache
 *
 * @param {String}   key
 * @param {Function} callback Will be called with null and the originally stored object
 *                            for successful operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.get = function( key, callback ) {
  this.client.get( key, ( error, result ) => {
    var parsedResult

    if( result === null ) {
      callback( error, null )
      return
    }

    try {
      parsedResult = JSON.parse( result )
    } catch ( e ) {
      callback( e )
      return
    }

    callback( null, parsedResult )
  })
}

module.exports = CacheConnector<commit_msg>added close method to close redis connection<commit_after>var Connection = require( './connection' )
var pckg = require( '../package.json' )
var util = require( 'util' )

/**
 * A [deepstream](http://deepstream.io) cache connector
 * for [Redis](http://redis.io)
 *
 * Since Redis, on top of caching key/value combinations in
 * memory, writes them to disk it can make a storage connector
 * obsolete
 *
 * @param {Object} options redis connection options. Please see ./connection.js
 *                         for details
 *
 * @constructor
 */
var CacheConnector = function( options ) {
  Connection.call( this, options )

  this.name = pckg.name
  this.version = pckg.version
}

util.inherits( CacheConnector, Connection )

/**
 * Gracefully close the connection to redis
 *
 * Called when deepstream.close() is invoked.
 * Emits 'close' event to notify deepstream of clean closure.
 *
 * @public
 * @returns {void}
 */
CacheConnector.prototype.close = function(){
  this.client.removeAllListeners( 'end'  )
  this.client.once( 'end', this.emit.bind( this, 'close'  )  )
  this.client.quit()
}

/**
 * Deletes an entry from the cache.
 *
 * @param   {String}   key
 * @param   {Function} callback Will be called with null for successful deletions or with an error message
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.delete = function( key, callback ) {
  this.client.del( key, callback )
}

/**
 * Writes a value to the cache.
 *
 * @param {String}   key
 * @param {Object}   value
 * @param {Function} callback Will be called with null for successful set operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.set = function( key, value, callback ) {
  this.client.set( key, JSON.stringify( value ), callback )
}

/**
 * Retrieves a value from the cache
 *
 * @param {String}   key
 * @param {Function} callback Will be called with null and the originally stored object
 *                            for successful operations or with an error message string
 *
 * @private
 * @returns {void}
 */
CacheConnector.prototype.get = function( key, callback ) {
  this.client.get( key, ( error, result ) => {
    var parsedResult

    if( result === null ) {
      callback( error, null )
      return
    }

    try {
      parsedResult = JSON.parse( result )
    } catch ( e ) {
      callback( e )
      return
    }

    callback( null, parsedResult )
  })
}

module.exports = CacheConnector
<|endoftext|>


<commit_before>/**
 * @fileOverview Area Chart
 */
import React, { Component, PropTypes } from 'react';
import Smooth from 'react-smooth';
import _ from 'lodash';
import Layer from '../container/Layer';
import Tooltip from '../component/Tooltip';
import Dot from '../shape/Dot';
import Curve from '../shape/Curve';
import { getPresentationAttributes, findChildByType } from '../util/ReactUtils';
import { getMainColorOfGraphicItem } from '../util/CartesianUtils';
import generateCategoricalChart from './generateCategoricalChart';
import Area from '../cartesian/Area';
import AnimationDecorator from '../util/AnimationDecorator';
import composedDataDecorator from '../util/ComposedDataDecorator';

const getCategoryAxisCoordinate = ({ axis, ticks, bandSize, entry, index }) => {
  if (axis.type === 'category') {
    return ticks[index] ? ticks[index].coordinate + bandSize / 2 : null;
  }

  const dataKey = axis.dataKey;

  return dataKey && !_.isNil(entry[dataKey]) ? axis.scale(entry[dataKey]) : null;
};

const getBaseValue = (props, xAxis, yAxis) => {
  const { layout } = props;
  const numberAxis = layout === 'horizontal' ? yAxis : xAxis;
  const domain = numberAxis.scale.domain();

  if (numberAxis.type === 'number') {
    const max = Math.max(domain[0], domain[1]);
    return max < 0 ? max : Math.max(Math.min(domain[0], domain[1]), 0);
  }

  return domain[0];
};

/**
 * Compose the data of each area
 * @param {Object} props The props that are passed to the component
 * @param {Object} xAxis       The configuration of x-axis
 * @param {Object} yAxis       The configuration of y-axis
 * @param {String} dataKey     The unique key of a group
 * @param {Array} stackedData If the area is stacked,
 * the stackedData is an array of min value and max value
 * @return {Array} Composed data
 */
const getComposedData = ({ props, xAxis, yAxis, xTicks, yTicks, bandSize, dataKey,
  stackedData }) => {
  const { layout, dataStartIndex, dataEndIndex } = props;
  const data = props.data.slice(dataStartIndex, dataEndIndex + 1);
  const hasStack = stackedData && stackedData.length;
  const baseValue = getBaseValue(props, xAxis, yAxis);

  const points = data.map((entry, index) => {
    const value = hasStack ? stackedData[dataStartIndex + index] : [baseValue, entry[dataKey]];

    if (layout === 'horizontal') {
      return {
        x: getCategoryAxisCoordinate({ axis: xAxis, ticks: xTicks, bandSize, entry, index }),
        y: _.isNil(value[1]) ? null : yAxis.scale(value[1]),
        value,
        payload: entry,
      };
    }

    return {
      x: _.isNil(value[1]) ? null : xAxis.scale(value[1]),
      y: getCategoryAxisCoordinate({ axis: yAxis, ticks: yTicks, bandSize, entry, index }),
      value,
      payload: entry,
    };
  });

  let baseLine;
  if (hasStack) {
    baseLine = stackedData.slice(dataStartIndex, dataEndIndex + 1).map((entry, index) => ({
      x: layout === 'horizontal' ?
          getCategoryAxisCoordinate({ axis: xAxis, ticks: xTicks, bandSize, entry, index }) :
          xAxis.scale(entry[0]),
      y: layout === 'horizontal' ?
         yAxis.scale(entry[0]) :
         getCategoryAxisCoordinate({ axis: yAxis, ticks: yTicks, bandSize, entry, index }),
    }));
  } else if (layout === 'horizontal') {
    baseLine = yAxis.scale(baseValue);
  } else {
    baseLine = xAxis.scale(baseValue);
  }

  return { points, baseLine, layout };
};

@AnimationDecorator
@composedDataDecorator({ getComposedData })
export class AreaChart extends Component {
  static displayName = 'AreaChart';

  static propTypes = {
    allComposedData: PropTypes.array,
    axisTicks: PropTypes.array,
    layout: PropTypes.oneOf(['horizontal', 'vertical']),
    dataStartIndex: PropTypes.number,
    dataEndIndex: PropTypes.number,
    data: PropTypes.array,
    isTooltipActive: PropTypes.bool,
    activeTooltipIndex: PropTypes.number,
    xAxisMap: PropTypes.object,
    yAxisMap: PropTypes.object,
    offset: PropTypes.object,
    graphicalItems: PropTypes.array,
    children: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.node),
      PropTypes.node,
    ]),
    stackGroups: PropTypes.object,
    // used internally
    isComposed: PropTypes.bool,
    animationId: PropTypes.number,
  };

  renderCursor({ offset }) {
    const { children, isTooltipActive, layout, activeTooltipIndex, axisTicks } = this.props;
    const tooltipItem = findChildByType(children, Tooltip);

    if (!tooltipItem || !tooltipItem.props.cursor || !isTooltipActive ||
      activeTooltipIndex < 0) { return null; }

    const ticks = axisTicks;

    if (!ticks || !ticks[activeTooltipIndex]) { return null; }

    const start = ticks[activeTooltipIndex].coordinate;
    const x1 = layout === 'horizontal' ? start : offset.left;
    const y1 = layout === 'horizontal' ? offset.top : start;
    const x2 = layout === 'horizontal' ? start : offset.left + offset.width;
    const y2 = layout === 'horizontal' ? offset.top + offset.height : start;
    const cursorProps = {
      stroke: '#ccc',
      ...getPresentationAttributes(tooltipItem.props.cursor),
      points: [{ x: x1, y: y1 }, { x: x2, y: y2 }],
    };

    return React.isValidElement(tooltipItem.props.cursor) ?
      React.cloneElement(tooltipItem.props.cursor, cursorProps) :
      <Curve {...cursorProps} type="linear" className="recharts-tooltip-cursor" />;
  }

  renderActiveDot(option, props) {
    let dot;

    if (React.isValidElement(option)) {
      dot = React.cloneElement(option, props);
    } else if (_.isFunction(option)) {
      dot = option(props);
    } else {
      dot = <Dot {...props} />;
    }

    return (
      <Smooth
        from="scale(0)"
        to="scale(1)"
        duration={400}
        key={`dot-${props.dataKey}`}
        attributeName="transform"
      >
        <Layer style={{ transformOrigin: 'center center' }}>
          {dot}
        </Layer>
      </Smooth>
    );
  }

  /**
   * Draw the main part of area chart
   * @param  {Array} items     React elements of Area
   * @param  {Object} xAxisMap The configuration of all x-axis
   * @param  {Object} yAxisMap The configuration of all y-axis
   * @param  {Object} offset   The offset of main part in the svg element
   * @param  {Array} allComposedData The array of pre-created composedData
   *                                 {points, basedLine, layout} for each item
   * @return {ReactComponent} The instances of Area
   */
  renderItems(items, xAxisMap, yAxisMap, offset, allComposedData) {
    const { children, layout, isTooltipActive, activeTooltipIndex } = this.props;
    const tooltipItem = findChildByType(children, Tooltip);
    const hasDot = tooltipItem && isTooltipActive;
    const dotItems = [];
    const { animationId } = this.props;

    const areaItems = items.reduce((result, child, i) => {

      const { dataKey, activeDot } = child.props;
      const currentComposedData = allComposedData[i];
      const activePoint = currentComposedData.points &&
        currentComposedData.points[activeTooltipIndex];

      if (hasDot && activeDot && activePoint) {
        const dotProps = {
          index: activeTooltipIndex,
          dataKey,
          animationId,
          cx: activePoint.x, cy: activePoint.y, r: 4,
          fill: getMainColorOfGraphicItem(child),
          strokeWidth: 2, stroke: '#fff',
          payload: activePoint.payload,
          value: activePoint.value,
          ...getPresentationAttributes(activeDot),
        };
        dotItems.push(this.renderActiveDot(activeDot, dotProps));
      }

      const area = React.cloneElement(child, {
        key: `area-${i}`,
        ...offset,
        ...currentComposedData,
        animationId,
        layout,
      });

      return [...result, area];
    }, []);

    return (
      <Layer className="recharts-area-chart-group">
        <Layer className="recharts-area-chart-shapes">{areaItems}</Layer>
        <Layer className="recharts-area-chart-dots">{dotItems}</Layer>
      </Layer>
    );
  }

  render() {
    const { isComposed, graphicalItems, xAxisMap, yAxisMap, offset, allComposedData } = this.props;

    return (
      <Layer className="recharts-area-graphical">
        {!isComposed && this.renderCursor({ xAxisMap, yAxisMap, offset })}
        {this.renderItems(graphicalItems, xAxisMap, yAxisMap, offset, allComposedData)}
      </Layer>
    );
  }
}

export default generateCategoricalChart(AreaChart, Area);
<commit_msg>feat: add props `basevalue` in `AreaChart`, fix #190<commit_after>/**
 * @fileOverview Area Chart
 */
import React, { Component, PropTypes } from 'react';
import Smooth from 'react-smooth';
import _ from 'lodash';
import Layer from '../container/Layer';
import Tooltip from '../component/Tooltip';
import Dot from '../shape/Dot';
import Curve from '../shape/Curve';
import { getPresentationAttributes, findChildByType } from '../util/ReactUtils';
import { getMainColorOfGraphicItem } from '../util/CartesianUtils';
import { isNumber } from '../util/DataUtils';
import generateCategoricalChart from './generateCategoricalChart';
import Area from '../cartesian/Area';
import AnimationDecorator from '../util/AnimationDecorator';
import composedDataDecorator from '../util/ComposedDataDecorator';

const getCategoryAxisCoordinate = ({ axis, ticks, bandSize, entry, index }) => {
  if (axis.type === 'category') {
    return ticks[index] ? ticks[index].coordinate + bandSize / 2 : null;
  }

  const dataKey = axis.dataKey;

  return dataKey && !_.isNil(entry[dataKey]) ? axis.scale(entry[dataKey]) : null;
};

const getBaseValue = (props, xAxis, yAxis) => {
  const { layout, baseValue } = props;

  if (isNumber(baseValue)) { return baseValue; }

  const numberAxis = layout === 'horizontal' ? yAxis : xAxis;
  const domain = numberAxis.scale.domain();

  if (numberAxis.type === 'number') {
    const max = Math.max(domain[0], domain[1]);
    const min = Math.min(domain[0], domain[1]);

    if (baseValue === 'dataMin') { return min; }
    if (baseValue === 'dataMax') { return max; }

    return max < 0 ? max : Math.max(Math.min(domain[0], domain[1]), 0);
  }

  if (baseValue === 'dataMin') { return domain[0]; }
  if (baseValue === 'dataMax') { return domain[1]; }

  return domain[0];
};

/**
 * Compose the data of each area
 * @param {Object} props The props that are passed to the component
 * @param {Object} xAxis       The configuration of x-axis
 * @param {Object} yAxis       The configuration of y-axis
 * @param {String} dataKey     The unique key of a group
 * @param {Array} stackedData If the area is stacked,
 * the stackedData is an array of min value and max value
 * @return {Array} Composed data
 */
const getComposedData = ({ props, xAxis, yAxis, xTicks, yTicks, bandSize, dataKey,
  stackedData }) => {
  const { layout, dataStartIndex, dataEndIndex } = props;
  const data = props.data.slice(dataStartIndex, dataEndIndex + 1);
  const hasStack = stackedData && stackedData.length;
  const baseValue = getBaseValue(props, xAxis, yAxis);

  const points = data.map((entry, index) => {
    const value = hasStack ? stackedData[dataStartIndex + index] : [baseValue, entry[dataKey]];

    if (layout === 'horizontal') {
      return {
        x: getCategoryAxisCoordinate({ axis: xAxis, ticks: xTicks, bandSize, entry, index }),
        y: _.isNil(value[1]) ? null : yAxis.scale(value[1]),
        value,
        payload: entry,
      };
    }

    return {
      x: _.isNil(value[1]) ? null : xAxis.scale(value[1]),
      y: getCategoryAxisCoordinate({ axis: yAxis, ticks: yTicks, bandSize, entry, index }),
      value,
      payload: entry,
    };
  });

  let baseLine;
  if (hasStack) {
    baseLine = stackedData.slice(dataStartIndex, dataEndIndex + 1).map((entry, index) => ({
      x: layout === 'horizontal' ?
          getCategoryAxisCoordinate({ axis: xAxis, ticks: xTicks, bandSize, entry, index }) :
          xAxis.scale(entry[0]),
      y: layout === 'horizontal' ?
         yAxis.scale(entry[0]) :
         getCategoryAxisCoordinate({ axis: yAxis, ticks: yTicks, bandSize, entry, index }),
    }));
  } else if (layout === 'horizontal') {
    baseLine = yAxis.scale(baseValue);
  } else {
    baseLine = xAxis.scale(baseValue);
  }

  return { points, baseLine, layout };
};

@AnimationDecorator
@composedDataDecorator({ getComposedData })
export class AreaChart extends Component {
  static displayName = 'AreaChart';

  static propTypes = {
    allComposedData: PropTypes.array,
    axisTicks: PropTypes.array,
    layout: PropTypes.oneOf(['horizontal', 'vertical']),
    dataStartIndex: PropTypes.number,
    dataEndIndex: PropTypes.number,
    data: PropTypes.array,
    isTooltipActive: PropTypes.bool,
    activeTooltipIndex: PropTypes.number,
    xAxisMap: PropTypes.object,
    yAxisMap: PropTypes.object,
    offset: PropTypes.object,
    graphicalItems: PropTypes.array,
    children: PropTypes.oneOfType([
      PropTypes.arrayOf(PropTypes.node),
      PropTypes.node,
    ]),
    stackGroups: PropTypes.object,
    baseValue: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.oneOf(['dataMin', 'dataMax', 'auto']),
    ]),
    // used internally
    isComposed: PropTypes.bool,
    animationId: PropTypes.number,
  };

  static defaultProps = {
    baseValue: 'auto',
  };

  renderCursor({ offset }) {
    const { children, isTooltipActive, layout, activeTooltipIndex, axisTicks } = this.props;
    const tooltipItem = findChildByType(children, Tooltip);

    if (!tooltipItem || !tooltipItem.props.cursor || !isTooltipActive ||
      activeTooltipIndex < 0) { return null; }

    const ticks = axisTicks;

    if (!ticks || !ticks[activeTooltipIndex]) { return null; }

    const start = ticks[activeTooltipIndex].coordinate;
    const x1 = layout === 'horizontal' ? start : offset.left;
    const y1 = layout === 'horizontal' ? offset.top : start;
    const x2 = layout === 'horizontal' ? start : offset.left + offset.width;
    const y2 = layout === 'horizontal' ? offset.top + offset.height : start;
    const cursorProps = {
      stroke: '#ccc',
      ...getPresentationAttributes(tooltipItem.props.cursor),
      points: [{ x: x1, y: y1 }, { x: x2, y: y2 }],
    };

    return React.isValidElement(tooltipItem.props.cursor) ?
      React.cloneElement(tooltipItem.props.cursor, cursorProps) :
      <Curve {...cursorProps} type="linear" className="recharts-tooltip-cursor" />;
  }

  renderActiveDot(option, props) {
    let dot;

    if (React.isValidElement(option)) {
      dot = React.cloneElement(option, props);
    } else if (_.isFunction(option)) {
      dot = option(props);
    } else {
      dot = <Dot {...props} />;
    }

    return (
      <Smooth
        from="scale(0)"
        to="scale(1)"
        duration={400}
        key={`dot-${props.dataKey}`}
        attributeName="transform"
      >
        <Layer style={{ transformOrigin: 'center center' }}>
          {dot}
        </Layer>
      </Smooth>
    );
  }

  /**
   * Draw the main part of area chart
   * @param  {Array} items     React elements of Area
   * @param  {Object} xAxisMap The configuration of all x-axis
   * @param  {Object} yAxisMap The configuration of all y-axis
   * @param  {Object} offset   The offset of main part in the svg element
   * @param  {Array} allComposedData The array of pre-created composedData
   *                                 {points, basedLine, layout} for each item
   * @return {ReactComponent} The instances of Area
   */
  renderItems(items, xAxisMap, yAxisMap, offset, allComposedData) {
    const { children, layout, isTooltipActive, activeTooltipIndex } = this.props;
    const tooltipItem = findChildByType(children, Tooltip);
    const hasDot = tooltipItem && isTooltipActive;
    const dotItems = [];
    const { animationId } = this.props;

    const areaItems = items.reduce((result, child, i) => {

      const { dataKey, activeDot } = child.props;
      const currentComposedData = allComposedData[i];
      const activePoint = currentComposedData.points &&
        currentComposedData.points[activeTooltipIndex];

      if (hasDot && activeDot && activePoint) {
        const dotProps = {
          index: activeTooltipIndex,
          dataKey,
          animationId,
          cx: activePoint.x, cy: activePoint.y, r: 4,
          fill: getMainColorOfGraphicItem(child),
          strokeWidth: 2, stroke: '#fff',
          payload: activePoint.payload,
          value: activePoint.value,
          ...getPresentationAttributes(activeDot),
        };
        dotItems.push(this.renderActiveDot(activeDot, dotProps));
      }

      const area = React.cloneElement(child, {
        key: `area-${i}`,
        ...offset,
        ...currentComposedData,
        animationId,
        layout,
      });

      return [...result, area];
    }, []);

    return (
      <Layer className="recharts-area-chart-group">
        <Layer className="recharts-area-chart-shapes">{areaItems}</Layer>
        <Layer className="recharts-area-chart-dots">{dotItems}</Layer>
      </Layer>
    );
  }

  render() {
    const { isComposed, graphicalItems, xAxisMap, yAxisMap, offset, allComposedData } = this.props;

    return (
      <Layer className="recharts-area-graphical">
        {!isComposed && this.renderCursor({ xAxisMap, yAxisMap, offset })}
        {this.renderItems(graphicalItems, xAxisMap, yAxisMap, offset, allComposedData)}
      </Layer>
    );
  }
}

export default generateCategoricalChart(AreaChart, Area);
<|endoftext|>


<commit_before>import BlindCommandBatcher from './commandBatcher';
import Codec from './commands/codec';
import ClientPresentationModel from './clientPresentationModel'

export default class ClientConnector {

    constructor(transmitter, clientDolphin, slackMS = 0, maxBatchSize = 50) {
        this.commandQueue = [];
        this.currentlySending = false;
        this.pushEnabled = false;
        this.waiting = false;
        this.transmitter = transmitter;
        this.clientDolphin = clientDolphin;
        this.slackMS = slackMS;
        this.codec = new Codec();
        this.commandBatcher = new BlindCommandBatcher(true, maxBatchSize);
    }

    setCommandBatcher(newBatcher) {
        this.commandBatcher = newBatcher;
    }

    setPushEnabled(enabled) {
        this.pushEnabled = enabled;
    }

    setPushListener(newListener) {
        this.pushListener = newListener;
    }

    setReleaseCommand(newCommand) {
        this.releaseCommand = newCommand;
    }

    send(command, onFinished) {
        this.commandQueue.push({ command: command, handler: onFinished });
        if (this.currentlySending) {
            this.release(); // there is not point in releasing if we do not send atm
            return;
        }
        this.doSendNext();
    }

    doSendNext() {
        if (this.commandQueue.length < 1) {
            if (this.pushEnabled) {
                this.enqueuePushCommand();
            }
            else {
                this.currentlySending = false;
                return;
            }
        }
        this.currentlySending = true;
        var cmdsAndHandlers = this.commandBatcher.batch(this.commandQueue);

        if(cmdsAndHandlers.lenght > 0) {
            var callback = cmdsAndHandlers[cmdsAndHandlers.length - 1].handler;
            var commands = cmdsAndHandlers.map(cah => { return cah.command; });
            this.transmitter.transmit(commands, (response) => {
                var touchedPMs = [];
                response.forEach((command) => {
                    var touched = this.handle(command);
                    if (touched)
                        touchedPMs.push(touched);
                });
                if (callback) {
                    callback.onFinished(touchedPMs); // todo: make them unique?
                }
                setTimeout(() => this.doSendNext(), this.slackMS);
            });
        } else {
            setTimeout(() => this.doSendNext(), this.slackMS);
        }
    }

    handle(command) {
        if (command.id == "DeletePresentationModel") {
            return this.handleDeletePresentationModelCommand(command);
        }
        else if (command.id == "CreatePresentationModel") {
            return this.handleCreatePresentationModelCommand(command);
        }
        else if (command.id == "ValueChanged") {
            return this.handleValueChangedCommand(command);
        }
        else if (command.id == "AttributeMetadataChanged") {
            return this.handleAttributeMetadataChangedCommand(command);
        }
        else {
            console.log("Cannot handle, unknown command " + command);
        }
        return null;
    }

    handleDeletePresentationModelCommand(serverCommand) {
        var model = this.clientDolphin.findPresentationModelById(serverCommand.pmId);
        if (!model)
            return null;
        this.clientDolphin.getClientModelStore().deletePresentationModel(model, true);
        return model;
    }

    handleCreatePresentationModelCommand(serverCommand) {
        if (this.clientDolphin.getClientModelStore().containsPresentationModel(serverCommand.pmId)) {
            throw new Error("There already is a presentation model with id " + serverCommand.pmId + "  known to the client.");
        }
        var attributes = [];
        serverCommand.attributes.forEach((attr) => {
            var clientAttribute = this.clientDolphin.attribute(attr.propertyName, attr.qualifier, attr.value);
            if (attr.id && attr.id.match(".*S$")) {
                clientAttribute.id = attr.id;
            }
            attributes.push(clientAttribute);
        });
        var clientPm = new ClientPresentationModel(serverCommand.pmId, serverCommand.pmType);
        clientPm.addAttributes(attributes);
        if (serverCommand.clientSideOnly) {
            clientPm.clientSideOnly = true;
        }
        this.clientDolphin.getClientModelStore().add(clientPm, false);
        this.clientDolphin.updatePresentationModelQualifier(clientPm);
        return clientPm;
    }

    handleValueChangedCommand(serverCommand) {
        var clientAttribute = this.clientDolphin.getClientModelStore().findAttributeById(serverCommand.attributeId);
        if (!clientAttribute) {
            console.log("attribute with id " + serverCommand.attributeId + " not found, cannot update to new value " + serverCommand.newValue);
            return null;
        }
        if (clientAttribute.getValue() == serverCommand.newValue) {
            //console.log("nothing to do. new value == old value");
            return null;
        }
        clientAttribute.setValueFromServer(serverCommand.newValue);
        return null;
    }

    handleAttributeMetadataChangedCommand(serverCommand) {
        var clientAttribute = this.clientDolphin.getClientModelStore().findAttributeById(serverCommand.attributeId);
        if (!clientAttribute)
            return null;
        clientAttribute[serverCommand.metadataName] = serverCommand.value;
        return null;
    }

    listen() {
        if (!this.pushEnabled)
            return;
        if (this.waiting)
            return;
        // todo: how to issue a warning if no pushListener is set?
        if (!this.currentlySending) {
            this.doSendNext();
        }
    }

    enqueuePushCommand() {
        var me = this;
        this.waiting = true;
        this.commandQueue.push({
            command: this.pushListener,
            handler: {
                onFinished: function () { me.waiting = false; },
                onFinishedData: null
            }
        });
    }

    release() {
        if (!this.waiting)
            return;
        this.waiting = false;
        // todo: how to issue a warning if no releaseCommand is set?
        this.transmitter.signal(this.releaseCommand);
    }
}<commit_msg>length != lenght :(<commit_after>import BlindCommandBatcher from './commandBatcher';
import Codec from './commands/codec';
import ClientPresentationModel from './clientPresentationModel'

export default class ClientConnector {

    constructor(transmitter, clientDolphin, slackMS = 0, maxBatchSize = 50) {
        this.commandQueue = [];
        this.currentlySending = false;
        this.pushEnabled = false;
        this.waiting = false;
        this.transmitter = transmitter;
        this.clientDolphin = clientDolphin;
        this.slackMS = slackMS;
        this.codec = new Codec();
        this.commandBatcher = new BlindCommandBatcher(true, maxBatchSize);
    }

    setCommandBatcher(newBatcher) {
        this.commandBatcher = newBatcher;
    }

    setPushEnabled(enabled) {
        this.pushEnabled = enabled;
    }

    setPushListener(newListener) {
        this.pushListener = newListener;
    }

    setReleaseCommand(newCommand) {
        this.releaseCommand = newCommand;
    }

    send(command, onFinished) {
        this.commandQueue.push({ command: command, handler: onFinished });
        if (this.currentlySending) {
            this.release(); // there is not point in releasing if we do not send atm
            return;
        }
        this.doSendNext();
    }

    doSendNext() {
        if (this.commandQueue.length < 1) {
            if (this.pushEnabled) {
                this.enqueuePushCommand();
            }
            else {
                this.currentlySending = false;
                return;
            }
        }
        this.currentlySending = true;
        var cmdsAndHandlers = this.commandBatcher.batch(this.commandQueue);

        if(cmdsAndHandlers.length > 0) {
            var callback = cmdsAndHandlers[cmdsAndHandlers.length - 1].handler;
            var commands = cmdsAndHandlers.map(cah => { return cah.command; });
            this.transmitter.transmit(commands, (response) => {
                var touchedPMs = [];
                response.forEach((command) => {
                    var touched = this.handle(command);
                    if (touched)
                        touchedPMs.push(touched);
                });
                if (callback) {
                    callback.onFinished(touchedPMs); // todo: make them unique?
                }
                setTimeout(() => this.doSendNext(), this.slackMS);
            });
        } else {
            setTimeout(() => this.doSendNext(), this.slackMS);
        }
    }

    handle(command) {
        if (command.id == "DeletePresentationModel") {
            return this.handleDeletePresentationModelCommand(command);
        }
        else if (command.id == "CreatePresentationModel") {
            return this.handleCreatePresentationModelCommand(command);
        }
        else if (command.id == "ValueChanged") {
            return this.handleValueChangedCommand(command);
        }
        else if (command.id == "AttributeMetadataChanged") {
            return this.handleAttributeMetadataChangedCommand(command);
        }
        else {
            console.log("Cannot handle, unknown command " + command);
        }
        return null;
    }

    handleDeletePresentationModelCommand(serverCommand) {
        var model = this.clientDolphin.findPresentationModelById(serverCommand.pmId);
        if (!model)
            return null;
        this.clientDolphin.getClientModelStore().deletePresentationModel(model, true);
        return model;
    }

    handleCreatePresentationModelCommand(serverCommand) {
        if (this.clientDolphin.getClientModelStore().containsPresentationModel(serverCommand.pmId)) {
            throw new Error("There already is a presentation model with id " + serverCommand.pmId + "  known to the client.");
        }
        var attributes = [];
        serverCommand.attributes.forEach((attr) => {
            var clientAttribute = this.clientDolphin.attribute(attr.propertyName, attr.qualifier, attr.value);
            if (attr.id && attr.id.match(".*S$")) {
                clientAttribute.id = attr.id;
            }
            attributes.push(clientAttribute);
        });
        var clientPm = new ClientPresentationModel(serverCommand.pmId, serverCommand.pmType);
        clientPm.addAttributes(attributes);
        if (serverCommand.clientSideOnly) {
            clientPm.clientSideOnly = true;
        }
        this.clientDolphin.getClientModelStore().add(clientPm, false);
        this.clientDolphin.updatePresentationModelQualifier(clientPm);
        return clientPm;
    }

    handleValueChangedCommand(serverCommand) {
        var clientAttribute = this.clientDolphin.getClientModelStore().findAttributeById(serverCommand.attributeId);
        if (!clientAttribute) {
            console.log("attribute with id " + serverCommand.attributeId + " not found, cannot update to new value " + serverCommand.newValue);
            return null;
        }
        if (clientAttribute.getValue() == serverCommand.newValue) {
            //console.log("nothing to do. new value == old value");
            return null;
        }
        clientAttribute.setValueFromServer(serverCommand.newValue);
        return null;
    }

    handleAttributeMetadataChangedCommand(serverCommand) {
        var clientAttribute = this.clientDolphin.getClientModelStore().findAttributeById(serverCommand.attributeId);
        if (!clientAttribute)
            return null;
        clientAttribute[serverCommand.metadataName] = serverCommand.value;
        return null;
    }

    listen() {
        if (!this.pushEnabled)
            return;
        if (this.waiting)
            return;
        // todo: how to issue a warning if no pushListener is set?
        if (!this.currentlySending) {
            this.doSendNext();
        }
    }

    enqueuePushCommand() {
        var me = this;
        this.waiting = true;
        this.commandQueue.push({
            command: this.pushListener,
            handler: {
                onFinished: function () { me.waiting = false; },
                onFinishedData: null
            }
        });
    }

    release() {
        if (!this.waiting)
            return;
        this.waiting = false;
        // todo: how to issue a warning if no releaseCommand is set?
        this.transmitter.signal(this.releaseCommand);
    }
}<|endoftext|>


<commit_before>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Handler.js
 * @requires OpenLayers/Geometry/Point.js
 */

/**
 * Class: OpenLayers.Handler.Point
 * Handler to draw a point on the map. Point is displayed on activation,
 *     moves on mouse move, and is finished on mouse up. The handler triggers
 *     callbacks for 'done', 'cancel', and 'modify'. The modify callback is
 *     called with each change in the sketch and will receive the latest point
 *     drawn.  Create a new instance with the <OpenLayers.Handler.Point>
 *     constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {

    /**
     * Property: point
     * {<OpenLayers.Feature.Vector>} The currently drawn point
     */
    point: null,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
     */
    layer: null,

    /**
     * APIProperty: multi
     * {Boolean} Cast features to multi-part geometries before passing to the
     *     layer.  Default is false.
     */
    multi: false,

    /**
     * Property: mouseDown
     * {Boolean} The mouse is down
     */
    mouseDown: false,

    /**
     * Property: stoppedDown
     * {Boolean} Indicate whether the last mousedown stopped the event
     * propagation.
     */
    stoppedDown: null,

    /**
     * Property: lastDown
     * {<OpenLayers.Pixel>} Location of the last mouse down
     */
    lastDown: null,

    /**
     * Property: lastUp
     * {<OpenLayers.Pixel>}
     */
    lastUp: null,

    /**
     * APIProperty: persist
     * {Boolean} Leave the feature rendered until destroyFeature is called.
     *     Default is false.  If set to true, the feature remains rendered until
     *     destroyFeature is called, typically by deactivating the handler or
     *     starting another drawing.
     */
    persist: false,

    /**
     * APIProperty: stopDown
     * {Boolean} Stop event propagation on mousedown. Must be false to
     *     allow "pan while drawing". Defaults to false.
     */
    stopDown: false,

    /**
     * APIPropery: stopUp
     * {Boolean} Stop event propagation on mouse. Must be false to
     *     allow "pan while dragging". Defaults to fase.
     */
    stopUp: false,

    /**
     * Property: layerOptions
     * {Object} Any optional properties to be set on the sketch layer.
     */
    layerOptions: null,

    /**
     * APIProperty: pixelTolerance
     * {Number} Maximum number of pixels between down and up (mousedown
     *     and mouseup, or touchstart and touchend) for the handler to
     *     add a new point. If set to an integer value, if the
     *     displacement between down and up is great to this value
     *     no point will be added. Default value is 5.
     */
    pixelTolerance: 5,

    /**
     * Property: touch
     * {Boolean} Indcates the support of touch events.
     */
    touch: false,

    /**
     * Property: lastTouchPx
     * {<OpenLayers.Pixel>} The last pixel used to know the distance between
     * two touches (for double touch).
     */
    lastTouchPx: null,

    /**
     * Constructor: OpenLayers.Handler.Point
     * Create a new point handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the point geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {
        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
        }

        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
    },

    /**
     * APIMethod: activate
     * turn on the handler
     */
    activate: function() {
        if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
            return false;
        }
        // create temporary vector layer for rendering geometry sketch
        // TBD: this could be moved to initialize/destroy - setting visibility here
        var options = OpenLayers.Util.extend({
            displayInLayerSwitcher: false,
            // indicate that the temp vector layer will never be out of range
            // without this, resolution properties must be specified at the
            // map-level for this temporary layer to init its resolutions
            // correctly
            calculateInRange: OpenLayers.Function.True
        }, this.layerOptions);
        this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
        this.map.addLayer(this.layer);
        return true;
    },

    /**
     * Method: createFeature
     * Add temporary features
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    createFeature: function(pixel) {
        var lonlat = this.map.getLonLatFromPixel(pixel);
        var geometry = new OpenLayers.Geometry.Point(
            lonlat.lon, lonlat.lat
        );
        this.point = new OpenLayers.Feature.Vector(geometry);
        this.callback("create", [this.point.geometry, this.point]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.point], {silent: true});
    },

    /**
     * APIMethod: deactivate
     * turn off the handler
     */
    deactivate: function() {
        if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
            return false;
        }
        this.cancel();
        // If a layer's map property is set to null, it means that that layer
        // isn't added to the map. Since we ourself added the layer to the map
        // in activate(), we can assume that if this.layer.map is null it means
        // that the layer has been destroyed (as a result of map.destroy() for
        // example.
        if (this.layer.map != null) {
            this.destroyFeature(true);
            this.layer.destroy(false);
        }
        this.layer = null;
        this.touch = false;
        return true;
    },

    /**
     * Method: destroyFeature
     * Destroy the temporary geometries
     *
     * Parameters:
     * force - {Boolean} Destroy even if persist is true.
     */
    destroyFeature: function(force) {
        if(this.layer && (force || !this.persist)) {
            this.layer.destroyFeatures();
        }
        this.point = null;
    },

    /**
     * Method: destroyPersistedFeature
     * Destroy the persisted feature.
     */
    destroyPersistedFeature: function() {
        var layer = this.layer;
        if(layer && layer.features.length > 1) {
            this.layer.features[0].destroy();
        }
    },

    /**
     * Method: finalize
     * Finish the geometry and call the "done" callback.
     *
     * Parameters:
     * cancel - {Boolean} Call cancel instead of done callback.  Default
     *          is false.
     */
    finalize: function(cancel) {
        var key = cancel ? "cancel" : "done";
        this.drawing = false;
        this.mouseDown = false;
        this.lastDown = null;
        this.lastUp = null;
        this.lastTouchPx = null;
        this.callback(key, [this.geometryClone()]);
        this.destroyFeature(cancel);
    },

    /**
     * APIMethod: cancel
     * Finish the geometry and call the "cancel" callback.
     */
    cancel: function() {
        this.finalize(true);
    },

    /**
     * Method: click
     * Handle clicks.  Clicks are stopped from propagating to other listeners
     *     on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    click: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Double-clicks are stopped from propagating to other
     *     listeners on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    dblclick: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given a pixel location.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    modifyFeature: function(pixel) {
        if(!this.point) {
            this.createFeature(pixel);
        }
        var lonlat = this.map.getLonLatFromPixel(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;
        this.callback("modify", [this.point.geometry, this.point, false]);
        this.point.geometry.clearBounds();
        this.drawFeature();
    },

    /**
     * Method: drawFeature
     * Render features on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Point>}
     */
    getGeometry: function() {
        var geometry = this.point && this.point.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
        }
        return geometry;
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry>}
     */
    geometryClone: function() {
        var geom = this.getGeometry();
        return geom && geom.clone();
    },

    /**
     * Method: mousedown
     * Handle mousedown.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        return this.down(evt);
    },

    /**
     * Method: touchstart
     * Handle touchstart.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchstart: function(evt) {
        if (!this.touch) {
            this.touch = true;
            // unregister mouse listeners
            this.map.events.un({
                mousedown: this.mousedown,
                mouseup: this.mouseup,
                mousemove: this.mousemove,
                click: this.click,
                dblclick: this.dblclick,
                scope: this
            });
        }
        this.lastTouchPx = evt.xy;
        return this.down(evt);
    },

    /**
     * Method: mousemove
     * Handle mousemove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousemove: function(evt) {
        return this.move(evt);
    },

    /**
     * Method: touchmove
     * Handle touchmove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchmove: function(evt) {
        this.lastTouchPx = evt.xy;
        return this.move(evt);
    },

    /**
     * Method: mouseup
     * Handle mouseup.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mouseup: function(evt) {
        return this.up(evt);
    },

    /**
     * Method: touchend
     * Handle touchend.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchend: function(evt) {
        evt.xy = this.lastTouchPx;
        return this.up(evt);
    },

    /**
     * Method: down
     * Handle mousedown and touchstart.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    down: function(evt) {
        this.mouseDown = true;
        this.lastDown = evt.xy;
        if(!this.touch) { // no point displayed until up on touch devices
            this.modifyFeature(evt.xy);
        }
        this.stoppedDown = this.stopDown;
        return !this.stopDown;
    },

    /**
     * Method: move
     * Handle mousemove and touchmove.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    move: function (evt) {
        if(!this.touch // no point displayed until up on touch devices
           && (!this.mouseDown || this.stoppedDown)) {
            this.modifyFeature(evt.xy);
        }
        return true;
    },

    /**
     * Method: up
     * Handle mouseup and touchend.  Send the latest point in the geometry to the control.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    up: function (evt) {
        this.mouseDown = false;
        this.stoppedDown = this.stopDown;

        // check keyboard modifiers
        if(!this.checkModifiers(evt)) {
            return true;
        }
        // ignore double-clicks
        if (this.lastUp && this.lastUp.equals(evt.xy)) {
            return true;
        }
        if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy,
                                                  this.pixelTolerance)) {
            if (this.touch) {
                this.modifyFeature(evt.xy);
            }
            if(this.persist) {
                this.destroyPersistedFeature();
            }
            this.lastUp = evt.xy;
            this.finalize();
            return !this.stopUp;
        } else {
            return true;
        }
    },

    /**
     * Method: mouseout
     * Handle mouse out.  For better user experience reset mouseDown
     * and stoppedDown when the mouse leaves the map viewport.
     *
     * Parameters:
     * evt - {Event} The browser event
     */
    mouseout: function(evt) {
        if(OpenLayers.Util.mouseLeft(evt, this.map.eventsDiv)) {
            this.stoppedDown = this.stopDown;
            this.mouseDown = false;
        }
    },

    /**
     * Method: passesTolerance
     * Determine whether the event is within the optional pixel tolerance.
     *
     * Returns:
     * {Boolean} The event is within the pixel tolerance (if specified).
     */
    passesTolerance: function(pixel1, pixel2, tolerance) {
        var passes = true;

        if (tolerance != null && pixel1 && pixel2) {
            var dist = pixel1.distanceTo(pixel2);
            if (dist > tolerance) {
                passes = false;
            }
        }
        return passes;
    },

    CLASS_NAME: "OpenLayers.Handler.Point"
});
<commit_msg>Handler.Point has no "drawing" property anymore, trivial change (references #3316)<commit_after>/* Copyright (c) 2006-2011 by OpenLayers Contributors (see authors.txt for
 * full list of contributors). Published under the Clear BSD license.
 * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
 * full text of the license. */

/**
 * @requires OpenLayers/Handler.js
 * @requires OpenLayers/Geometry/Point.js
 */

/**
 * Class: OpenLayers.Handler.Point
 * Handler to draw a point on the map. Point is displayed on activation,
 *     moves on mouse move, and is finished on mouse up. The handler triggers
 *     callbacks for 'done', 'cancel', and 'modify'. The modify callback is
 *     called with each change in the sketch and will receive the latest point
 *     drawn.  Create a new instance with the <OpenLayers.Handler.Point>
 *     constructor.
 *
 * Inherits from:
 *  - <OpenLayers.Handler>
 */
OpenLayers.Handler.Point = OpenLayers.Class(OpenLayers.Handler, {

    /**
     * Property: point
     * {<OpenLayers.Feature.Vector>} The currently drawn point
     */
    point: null,

    /**
     * Property: layer
     * {<OpenLayers.Layer.Vector>} The temporary drawing layer
     */
    layer: null,

    /**
     * APIProperty: multi
     * {Boolean} Cast features to multi-part geometries before passing to the
     *     layer.  Default is false.
     */
    multi: false,

    /**
     * Property: mouseDown
     * {Boolean} The mouse is down
     */
    mouseDown: false,

    /**
     * Property: stoppedDown
     * {Boolean} Indicate whether the last mousedown stopped the event
     * propagation.
     */
    stoppedDown: null,

    /**
     * Property: lastDown
     * {<OpenLayers.Pixel>} Location of the last mouse down
     */
    lastDown: null,

    /**
     * Property: lastUp
     * {<OpenLayers.Pixel>}
     */
    lastUp: null,

    /**
     * APIProperty: persist
     * {Boolean} Leave the feature rendered until destroyFeature is called.
     *     Default is false.  If set to true, the feature remains rendered until
     *     destroyFeature is called, typically by deactivating the handler or
     *     starting another drawing.
     */
    persist: false,

    /**
     * APIProperty: stopDown
     * {Boolean} Stop event propagation on mousedown. Must be false to
     *     allow "pan while drawing". Defaults to false.
     */
    stopDown: false,

    /**
     * APIPropery: stopUp
     * {Boolean} Stop event propagation on mouse. Must be false to
     *     allow "pan while dragging". Defaults to fase.
     */
    stopUp: false,

    /**
     * Property: layerOptions
     * {Object} Any optional properties to be set on the sketch layer.
     */
    layerOptions: null,

    /**
     * APIProperty: pixelTolerance
     * {Number} Maximum number of pixels between down and up (mousedown
     *     and mouseup, or touchstart and touchend) for the handler to
     *     add a new point. If set to an integer value, if the
     *     displacement between down and up is great to this value
     *     no point will be added. Default value is 5.
     */
    pixelTolerance: 5,

    /**
     * Property: touch
     * {Boolean} Indcates the support of touch events.
     */
    touch: false,

    /**
     * Property: lastTouchPx
     * {<OpenLayers.Pixel>} The last pixel used to know the distance between
     * two touches (for double touch).
     */
    lastTouchPx: null,

    /**
     * Constructor: OpenLayers.Handler.Point
     * Create a new point handler.
     *
     * Parameters:
     * control - {<OpenLayers.Control>} The control that owns this handler
     * callbacks - {Object} An object with a properties whose values are
     *     functions.  Various callbacks described below.
     * options - {Object} An optional object with properties to be set on the
     *           handler
     *
     * Named callbacks:
     * create - Called when a sketch is first created.  Callback called with
     *     the creation point geometry and sketch feature.
     * modify - Called with each move of a vertex with the vertex (point)
     *     geometry and the sketch feature.
     * done - Called when the point drawing is finished.  The callback will
     *     recieve a single argument, the point geometry.
     * cancel - Called when the handler is deactivated while drawing.  The
     *     cancel callback will receive a geometry.
     */
    initialize: function(control, callbacks, options) {
        if(!(options && options.layerOptions && options.layerOptions.styleMap)) {
            this.style = OpenLayers.Util.extend(OpenLayers.Feature.Vector.style['default'], {});
        }

        OpenLayers.Handler.prototype.initialize.apply(this, arguments);
    },

    /**
     * APIMethod: activate
     * turn on the handler
     */
    activate: function() {
        if(!OpenLayers.Handler.prototype.activate.apply(this, arguments)) {
            return false;
        }
        // create temporary vector layer for rendering geometry sketch
        // TBD: this could be moved to initialize/destroy - setting visibility here
        var options = OpenLayers.Util.extend({
            displayInLayerSwitcher: false,
            // indicate that the temp vector layer will never be out of range
            // without this, resolution properties must be specified at the
            // map-level for this temporary layer to init its resolutions
            // correctly
            calculateInRange: OpenLayers.Function.True
        }, this.layerOptions);
        this.layer = new OpenLayers.Layer.Vector(this.CLASS_NAME, options);
        this.map.addLayer(this.layer);
        return true;
    },

    /**
     * Method: createFeature
     * Add temporary features
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    createFeature: function(pixel) {
        var lonlat = this.map.getLonLatFromPixel(pixel);
        var geometry = new OpenLayers.Geometry.Point(
            lonlat.lon, lonlat.lat
        );
        this.point = new OpenLayers.Feature.Vector(geometry);
        this.callback("create", [this.point.geometry, this.point]);
        this.point.geometry.clearBounds();
        this.layer.addFeatures([this.point], {silent: true});
    },

    /**
     * APIMethod: deactivate
     * turn off the handler
     */
    deactivate: function() {
        if(!OpenLayers.Handler.prototype.deactivate.apply(this, arguments)) {
            return false;
        }
        this.cancel();
        // If a layer's map property is set to null, it means that that layer
        // isn't added to the map. Since we ourself added the layer to the map
        // in activate(), we can assume that if this.layer.map is null it means
        // that the layer has been destroyed (as a result of map.destroy() for
        // example.
        if (this.layer.map != null) {
            this.destroyFeature(true);
            this.layer.destroy(false);
        }
        this.layer = null;
        this.touch = false;
        return true;
    },

    /**
     * Method: destroyFeature
     * Destroy the temporary geometries
     *
     * Parameters:
     * force - {Boolean} Destroy even if persist is true.
     */
    destroyFeature: function(force) {
        if(this.layer && (force || !this.persist)) {
            this.layer.destroyFeatures();
        }
        this.point = null;
    },

    /**
     * Method: destroyPersistedFeature
     * Destroy the persisted feature.
     */
    destroyPersistedFeature: function() {
        var layer = this.layer;
        if(layer && layer.features.length > 1) {
            this.layer.features[0].destroy();
        }
    },

    /**
     * Method: finalize
     * Finish the geometry and call the "done" callback.
     *
     * Parameters:
     * cancel - {Boolean} Call cancel instead of done callback.  Default
     *          is false.
     */
    finalize: function(cancel) {
        var key = cancel ? "cancel" : "done";
        this.mouseDown = false;
        this.lastDown = null;
        this.lastUp = null;
        this.lastTouchPx = null;
        this.callback(key, [this.geometryClone()]);
        this.destroyFeature(cancel);
    },

    /**
     * APIMethod: cancel
     * Finish the geometry and call the "cancel" callback.
     */
    cancel: function() {
        this.finalize(true);
    },

    /**
     * Method: click
     * Handle clicks.  Clicks are stopped from propagating to other listeners
     *     on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    click: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: dblclick
     * Handle double-clicks.  Double-clicks are stopped from propagating to other
     *     listeners on map.events or other dom elements.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    dblclick: function(evt) {
        OpenLayers.Event.stop(evt);
        return false;
    },

    /**
     * Method: modifyFeature
     * Modify the existing geometry given a pixel location.
     *
     * Parameters:
     * pixel - {<OpenLayers.Pixel>} A pixel location on the map.
     */
    modifyFeature: function(pixel) {
        if(!this.point) {
            this.createFeature(pixel);
        }
        var lonlat = this.map.getLonLatFromPixel(pixel);
        this.point.geometry.x = lonlat.lon;
        this.point.geometry.y = lonlat.lat;
        this.callback("modify", [this.point.geometry, this.point, false]);
        this.point.geometry.clearBounds();
        this.drawFeature();
    },

    /**
     * Method: drawFeature
     * Render features on the temporary layer.
     */
    drawFeature: function() {
        this.layer.drawFeature(this.point, this.style);
    },

    /**
     * Method: getGeometry
     * Return the sketch geometry.  If <multi> is true, this will return
     *     a multi-part geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry.Point>}
     */
    getGeometry: function() {
        var geometry = this.point && this.point.geometry;
        if(geometry && this.multi) {
            geometry = new OpenLayers.Geometry.MultiPoint([geometry]);
        }
        return geometry;
    },

    /**
     * Method: geometryClone
     * Return a clone of the relevant geometry.
     *
     * Returns:
     * {<OpenLayers.Geometry>}
     */
    geometryClone: function() {
        var geom = this.getGeometry();
        return geom && geom.clone();
    },

    /**
     * Method: mousedown
     * Handle mousedown.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousedown: function(evt) {
        return this.down(evt);
    },

    /**
     * Method: touchstart
     * Handle touchstart.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchstart: function(evt) {
        if (!this.touch) {
            this.touch = true;
            // unregister mouse listeners
            this.map.events.un({
                mousedown: this.mousedown,
                mouseup: this.mouseup,
                mousemove: this.mousemove,
                click: this.click,
                dblclick: this.dblclick,
                scope: this
            });
        }
        this.lastTouchPx = evt.xy;
        return this.down(evt);
    },

    /**
     * Method: mousemove
     * Handle mousemove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mousemove: function(evt) {
        return this.move(evt);
    },

    /**
     * Method: touchmove
     * Handle touchmove.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchmove: function(evt) {
        this.lastTouchPx = evt.xy;
        return this.move(evt);
    },

    /**
     * Method: mouseup
     * Handle mouseup.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    mouseup: function(evt) {
        return this.up(evt);
    },

    /**
     * Method: touchend
     * Handle touchend.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    touchend: function(evt) {
        evt.xy = this.lastTouchPx;
        return this.up(evt);
    },

    /**
     * Method: down
     * Handle mousedown and touchstart.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    down: function(evt) {
        this.mouseDown = true;
        this.lastDown = evt.xy;
        if(!this.touch) { // no point displayed until up on touch devices
            this.modifyFeature(evt.xy);
        }
        this.stoppedDown = this.stopDown;
        return !this.stopDown;
    },

    /**
     * Method: move
     * Handle mousemove and touchmove.  Adjust the geometry and redraw.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    move: function (evt) {
        if(!this.touch // no point displayed until up on touch devices
           && (!this.mouseDown || this.stoppedDown)) {
            this.modifyFeature(evt.xy);
        }
        return true;
    },

    /**
     * Method: up
     * Handle mouseup and touchend.  Send the latest point in the geometry to the control.
     * Return determines whether to propagate the event on the map.
     *
     * Parameters:
     * evt - {Event} The browser event
     *
     * Returns:
     * {Boolean} Allow event propagation
     */
    up: function (evt) {
        this.mouseDown = false;
        this.stoppedDown = this.stopDown;

        // check keyboard modifiers
        if(!this.checkModifiers(evt)) {
            return true;
        }
        // ignore double-clicks
        if (this.lastUp && this.lastUp.equals(evt.xy)) {
            return true;
        }
        if (this.lastDown && this.passesTolerance(this.lastDown, evt.xy,
                                                  this.pixelTolerance)) {
            if (this.touch) {
                this.modifyFeature(evt.xy);
            }
            if(this.persist) {
                this.destroyPersistedFeature();
            }
            this.lastUp = evt.xy;
            this.finalize();
            return !this.stopUp;
        } else {
            return true;
        }
    },

    /**
     * Method: mouseout
     * Handle mouse out.  For better user experience reset mouseDown
     * and stoppedDown when the mouse leaves the map viewport.
     *
     * Parameters:
     * evt - {Event} The browser event
     */
    mouseout: function(evt) {
        if(OpenLayers.Util.mouseLeft(evt, this.map.eventsDiv)) {
            this.stoppedDown = this.stopDown;
            this.mouseDown = false;
        }
    },

    /**
     * Method: passesTolerance
     * Determine whether the event is within the optional pixel tolerance.
     *
     * Returns:
     * {Boolean} The event is within the pixel tolerance (if specified).
     */
    passesTolerance: function(pixel1, pixel2, tolerance) {
        var passes = true;

        if (tolerance != null && pixel1 && pixel2) {
            var dist = pixel1.distanceTo(pixel2);
            if (dist > tolerance) {
                passes = false;
            }
        }
        return passes;
    },

    CLASS_NAME: "OpenLayers.Handler.Point"
});
<|endoftext|>


<commit_before>'use strict';
function leveshtein(a, b){
  if(a.length === 0) return b.length;
  if(b.length === 0) return a.length;

  var matrix = [];

  // increment along the first column of each row
  var i;
  for(i = 0; i <= b.length; i++){
    matrix[i] = [i];
  }

  // increment each column in the first row
  var j;
  for(j = 0; j <= a.length; j++){
    matrix[0][j] = j;
  }

  // Fill in the rest of the matrix
  for(i = 1; i <= b.length; i++){
    for(j = 1; j <= a.length; j++){
      if(b.charAt(i-1) == a.charAt(j-1)){
        matrix[i][j] = matrix[i-1][j-1];
      } else {
        matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
                                Math.min(matrix[i][j-1] + 1, // insertion
                                         matrix[i-1][j] + 1)); // deletion
      }
    }
  }

  return matrix[b.length][a.length];
}

function getSmallestIndex(arr) {
  var i = 0, l = arr.length;
  var min = Number.MAX_VALUE;
  var mi = -1;
  for (; i < l; i++) {
    if (arr[i] < min) {
      min = arr[i];
      mi = i;
    }
  }
  return mi;
}

// TODO not very fast at all
function getAllProperties(t) {
  let prop = [];
  function acq(obj) {
    if (obj === null || obj === undefined) return; // recursive approach
    const p = Object.getOwnPropertyNames(obj);
    for (let i = 0; i < p.length; i++) {
      const a = p[i];
      if (!prop.includes(a)) {
        prop.push(a);
      }
    }
    acq(Object.getPrototypeOf(obj));
  }
  acq(t);
  return prop;
}
function getClosest(target, name) {
  const rankings = [];
  // getOwnPropertyNames does not return inherited properties, but .keys does not return non-enumerable properties; discussion needed
  const targ = getAllProperties(target);

  // sort the array, for fast-tracking (the best match should be the shortest one, right?)
  // for verifying: aw.clear === clearTimeout, not clearInterval
  // longest string first:
  //targ.sort((a, b) => b.length - a.length);
  // shortest string first:
  targ.sort((a, b) => a.length - b.length);

  console.log('targ: ' + targ);

  for (let i = 0; i < targ.length; i++) {
    const t = targ[i];
    // FAST-TRACK if any key in the object starts with the requested name. without this, aw.clo === aw.clc rather than aw.close
    if (t.startsWith(name)) {
      //return target[t];
      console.log('1:'+t);
      return tryProxy(target[t]);
    }

    rankings.push(leveshtein(name, t));
  }

  const res = target[targ[getSmallestIndex(rankings)]];
  // debugging purposes, get the name of the real key being returned:
  console.log('2:'+res);

  // return a new proxy on the object using window._proxyHandler
  //return target[targ[getSmallestIndex(rankings)]];
  return tryProxy(res);
}

function tryProxy(res) {
  console.log('the RES ' + res);
  // Proxy will only accept non-null, non-undefined 'object' (and apparently 'function')
  return res !== undefined && res !== null && (typeof res == 'object' || typeof res == 'function') ? new Proxy(res, window._proxyHandler) : res;
}

{
  const altaw = {};

  // proxyHandler is mirrored to window so we can call it recursively
  const proxyHandler = window._proxyHandler = {
    get: function(target, name) {
      // side note: zZçÇyYx (only the lowercase form of x) are all fairly unused in the global namespace
      // ones i've used: qQ$
      // ones i haven't used yet: _ (lodash)

      // fast-track if we've got jQuery/moo business (TODO: proxy these)
      if (name == '$' && '_steamrollerjQuery' in target) {
        return target._steamrollerjQuery;
      }
      if (name == 'Q' && '_steamrollerMooTools' in target) {
        return target._steamrollerMooTools;
      }
      if (name in altaw) {
        return altaw[name];
      }
      //
      return name in target ?
        tryProxy(target[name]) :
        getClosest(target, name);
    }
  };

  let aw = new Proxy(window, proxyHandler);
  window.aw = aw;

  // expose jQuery from SleazyCatcher if it's available
  if (window._steamrollerjQuery) {
    if (window.$) {
      console.error('you have two jquery installed. gonna expose to window.q instead; you can still use aw.$');
      window.q = new Proxy(window._steamrollerjQuery, proxyHandler);
    } else {
      window.$ = new Proxy(window._steamrollerjQuery, proxyHandler);
    }
  }
  // the same for mootools
  if (window._steamrollerMooTools) {
    altaw.oo = new Proxy(window._steamrollerMooTools, proxyHandler);
  }
  // and other libs
  if (window._steamroller_) {
    altaw._ = new Proxy(window._steamroller_, proxyHandler);
  }
  if (window._steamrollerswal) {
    altaw.sw = new Proxy(window._steamrollerswal, proxyHandler);
  }
  if (window._steamrollerd3) {
    altaw.ç = new Proxy(window._steamrollerd3, proxyHandler);
  }
  if (window._steamrollerWordList) {
    altaw.z = new Proxy(window._steamrollerWordList, proxyHandler);
  }
  if (window._steamrollerxml2js) {
    altaw.x = new Proxy(window._steamrollerxml2js, proxyHandler);
  }
  if (window._steamrollerjsdom) {
    altaw.jd = new Proxy(window._steamrollerjsdom, proxyHandler);
  }

  // now we get to the fun stuff!
  function getInfinity() {
    return typeof Infinity !== 'undefined' ? Infinity : 'Infinity' in window ? window['Infinity'] : 9e999;
  }
  window.ƒ = {
      π: Math.PI,
      ø: [],
      Ø: NaN,
      e: 2.7182818284590452353602874713527,
      root2: 2.7182818284590452353602874713527,
      rt2: 2.7182818284590452353602874713527,
      sqrt2: 2.7182818284590452353602874713527,
      α: 2.5029,
      δ: 4.6692,
      ζ: 1.2020569,
      φ: 1.61803398874,
      γ: 1.30357,
      K: 2.6854520010,
      oo: getInfinity(),
      A: 1.2824271291,
      C10: 0.12345678910111213141516171819202122232425252728293031323334353637,
      c: 299792458
  };
}
<commit_msg>MORE LIBS<commit_after>'use strict';
function leveshtein(a, b){
  if(a.length === 0) return b.length;
  if(b.length === 0) return a.length;

  var matrix = [];

  // increment along the first column of each row
  var i;
  for(i = 0; i <= b.length; i++){
    matrix[i] = [i];
  }

  // increment each column in the first row
  var j;
  for(j = 0; j <= a.length; j++){
    matrix[0][j] = j;
  }

  // Fill in the rest of the matrix
  for(i = 1; i <= b.length; i++){
    for(j = 1; j <= a.length; j++){
      if(b.charAt(i-1) == a.charAt(j-1)){
        matrix[i][j] = matrix[i-1][j-1];
      } else {
        matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
                                Math.min(matrix[i][j-1] + 1, // insertion
                                         matrix[i-1][j] + 1)); // deletion
      }
    }
  }

  return matrix[b.length][a.length];
}

function getSmallestIndex(arr) {
  var i = 0, l = arr.length;
  var min = Number.MAX_VALUE;
  var mi = -1;
  for (; i < l; i++) {
    if (arr[i] < min) {
      min = arr[i];
      mi = i;
    }
  }
  return mi;
}

// TODO not very fast at all
function getAllProperties(t) {
  let prop = [];
  function acq(obj) {
    if (obj === null || obj === undefined) return; // recursive approach
    const p = Object.getOwnPropertyNames(obj);
    for (let i = 0; i < p.length; i++) {
      const a = p[i];
      if (!prop.includes(a)) {
        prop.push(a);
      }
    }
    acq(Object.getPrototypeOf(obj));
  }
  acq(t);
  return prop;
}
function getClosest(target, name) {
  const rankings = [];
  // getOwnPropertyNames does not return inherited properties, but .keys does not return non-enumerable properties; discussion needed
  const targ = getAllProperties(target);

  // sort the array, for fast-tracking (the best match should be the shortest one, right?)
  // for verifying: aw.clear === clearTimeout, not clearInterval
  // longest string first:
  //targ.sort((a, b) => b.length - a.length);
  // shortest string first:
  targ.sort((a, b) => a.length - b.length);

  console.log('targ: ' + targ);

  for (let i = 0; i < targ.length; i++) {
    const t = targ[i];
    // FAST-TRACK if any key in the object starts with the requested name. without this, aw.clo === aw.clc rather than aw.close
    if (t.startsWith(name)) {
      //return target[t];
      console.log('1:'+t);
      return tryProxy(target[t]);
    }

    rankings.push(leveshtein(name, t));
  }

  const res = target[targ[getSmallestIndex(rankings)]];
  // debugging purposes, get the name of the real key being returned:
  console.log('2:'+res);

  // return a new proxy on the object using window._proxyHandler
  //return target[targ[getSmallestIndex(rankings)]];
  return tryProxy(res);
}

function tryProxy(res) {
  console.log('the RES ' + res);
  // Proxy will only accept non-null, non-undefined 'object' (and apparently 'function')
  return res !== undefined && res !== null && (typeof res == 'object' || typeof res == 'function') ? new Proxy(res, window._proxyHandler) : res;
}

{
  const altaw = {};

  // proxyHandler is mirrored to window so we can call it recursively
  const proxyHandler = window._proxyHandler = {
    get: function(target, name) {
      // side note: ZyY (only the lowercase form of x) are all fairly unused in the global namespace
      // ones i've used: qQ$çÇx
      // ones i haven't used yet: _ (lodash)

      // fast-track if we've got jQuery/moo business (TODO: proxy these)
      if (name == '$' && '_steamrollerjQuery' in target) {
        return target._steamrollerjQuery;
      }
      if (name == 'Q' && '_steamrollerMooTools' in target) {
        return target._steamrollerMooTools;
      }
      if (name in altaw) {
        return altaw[name];
      }
      //
      return name in target ?
        tryProxy(target[name]) :
        getClosest(target, name);
    }
  };

  let aw = new Proxy(window, proxyHandler);
  window.aw = aw;

  // expose jQuery from SleazyCatcher if it's available
  if (window._steamrollerjQuery) {
    if (window.$) {
      console.error('you have two jquery installed. gonna expose to window.q instead; you can still use aw.$');
      window.q = new Proxy(window._steamrollerjQuery, proxyHandler);
    } else {
      window.$ = new Proxy(window._steamrollerjQuery, proxyHandler);
    }
  }
  // the same for mootools
  if (window._steamrollerMooTools) {
    altaw.oo = new Proxy(window._steamrollerMooTools, proxyHandler);
  }
  // and other libs
  if (window._steamroller_) {
    altaw._ = new Proxy(window._steamroller_, proxyHandler);
  }
  if (window._steamrollerswal) {
    altaw.sw = new Proxy(window._steamrollerswal, proxyHandler);
  }
  if (window._steamrollerd3) {
    altaw.ç = new Proxy(window._steamrollerd3, proxyHandler);
  }
  if (window._steamrollerWordList) {
    altaw.z = new Proxy(window._steamrollerWordList, proxyHandler);
  }
  if (window._steamrollerxml2js) {
    altaw.x = new Proxy(window._steamrollerxml2js, proxyHandler);
  }
  if (window._steamrollerjsdom) {
    altaw.jd = new Proxy(window._steamrollerjsdom, proxyHandler);
  }
  if (window._steamrollerSugar) {
    altaw.sg = new Proxy(window._steamrollerSugar, proxyHandler);
  }
  if (window._steamrollerR) {
    altaw.Ç = new Proxy(window._steamrollerR, proxyHandler);
  }
  if (window._steamrollerBoiler) {
    altaw.bl = new Proxy(window._steamrollerBoiler, proxyHandler);
  }
  if (window._steamrollerparse5) {
    altaw.p5 = new Proxy(window._steamrollerparse5, proxyHandler);
  }
  if (window._steamrollerjshint) {
    altaw.jh = new Proxy(window._steamrollerjshint, proxyHandler);
  }
  if (window._steamrolleranime) {
    altaw.ame = new Proxy(window._steamrolleranime, proxyHandler);
  }
  if (window._steamrollerzxcvbn) {
    altaw.zx = new Proxy(window._steamrollerzxcvbn, proxyHandler);
  }
  if (window._steamrolleris) {
    altaw.is = new Proxy(window._steamrolleris, proxyHandler);
  }

  // now we get to the fun stuff!
  function getInfinity() {
    return typeof Infinity !== 'undefined' ? Infinity : 'Infinity' in window ? window['Infinity'] : 9e999;
  }
  window.ƒ = {
      π: Math.PI,
      ø: [],
      Ø: NaN,
      e: 2.7182818284590452353602874713527,
      root2: 2.7182818284590452353602874713527,
      rt2: 2.7182818284590452353602874713527,
      sqrt2: 2.7182818284590452353602874713527,
      α: 2.5029,
      δ: 4.6692,
      ζ: 1.2020569,
      φ: 1.61803398874,
      γ: 1.30357,
      K: 2.6854520010,
      oo: getInfinity(),
      A: 1.2824271291,
      C10: 0.12345678910111213141516171819202122232425252728293031323334353637,
      c: 299792458
  };
}
<|endoftext|>