<commit_before>'use strict';
var path = require('path');
var npmName = require('npm-name');
var yeoman = require('yeoman-generator');
var color = require('colors');
var gitScopeConfig = require('git-scope-config')({
  scope: "global"
});
var gitHubInit = require('github-init');

module.exports = yeoman.generators.Base.extend({
  init: function() {
    this.pkg = require('../package.json');

    var bode = "\n\n" +
      "                                                 dddddddd\n".yellow +
      "BBBBBBBBBBBBBBBBB                                d::::::d\n".yellow +
      "B::::::::::::::::B                               d::::::d\n".yellow +
      "B::::::BBBBBB:::::B                              d::::::d\n".yellow +
      "BB:::::B     B:::::B                             d:::::d\n".green +
      "  B::::B     B:::::B   ooooooooooo       ddddddddd:::::d     eeeeeeeeeeee\n".green +
      "  B::::B     B:::::B oo:::::::::::oo   dd::::::::::::::d   ee::::::::::::ee\n".green +
      "  B::::BBBBBB:::::B o:::::::::::::::o d::::::::::::::::d  e::::::eeeee:::::ee\n".green +
      "  B:::::::::::::BB  o:::::ooooo:::::od:::::::ddddd:::::d e::::::e     e:::::e\n" +
      "  B::::BBBBBB:::::B o::::o     o::::od::::::d    d:::::d e:::::::eeeee::::::e\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e:::::::::::::::::e\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e::::::eeeeeeeeeee\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e:::::::e\n".blue +
      "BB:::::BBBBBB::::::Bo:::::ooooo:::::od::::::ddddd::::::dde::::::::e\n".red +
      "B:::::::::::::::::B o:::::::::::::::o d:::::::::::::::::d e::::::::eeeeeeee\n".red +
      "B::::::::::::::::B   oo:::::::::::oo   d:::::::::ddd::::d  ee:::::::::::::e\n".red +
      "BBBBBBBBBBBBBBBBB      ooooooooooo      ddddddddd   ddddd    eeeeeeeeeeeeee\n".red;

    this.log(bode +
      '\nThe name of your project shouldn\'t contain "node" or "js" and'.cyan +
      '\nshould be a unique ID not already in use at npmjs.org.'.cyan);
  },
  askForModuleName: function() {
    var done = this.async();

    var prompts = [{
      name: 'name',
      message: 'Module Name'.green,
      default: path.basename(process.cwd()),
    }, {
      type: 'confirm',
      name: 'pkgName',
      message: 'npm package already exist, please choose another name'.green,
      default: true,
      when: function(answers) {
        var done = this.async();
        npmName(answers.name, function(err, available) {
          if (!available) {
            done(true);
            return;
          }
          done(false);
        });
      }
    }];

    this.prompt(prompts, function(props) {
      if (props.pkgName) {
        return this.askForModuleName();
      }

      this.slugname = this._.slugify(props.name);
      this.safeSlugname = this.slugname.replace(/-+([a-zA-Z0-9])/g, function(g) {
        return g[1].toUpperCase();
      });
      done();
    }.bind(this));
  },

  askForGithubProcess: function() {
    var done = this.async();
    var githubToken;

    var prompt = [{
      type: 'confirm',
      name: 'git',
      message: "create github repo with module name?".green,
      default: true,
    }, {
      when: function(response) {
        var done = this.async();
        if (response.git) {
          gitScopeConfig.get('github.token', function(err, token) {
            if (err) {
              done(true);
              return;
            }
            if (token) {
              githubToken = token;
              done(false);
              return;
            }
          });
        } else {
          done(false);
          return;
        }
      },
      type: 'message',
      name: 'token',
      message: "Github token not found, create new from here".red + " https://github.com/settings/applications".blue
    }]

    this.prompt(prompt, function(props) {
      var _this = this;
      if (props.token) {
        gitScopeConfig.set('github.token', props.token, function(err, status) {
          if (err) {
            done();
            return;
          }
          _this.githubToken = props.token;
          done();
        })
      } else {
        this.githubToken = githubToken;
        done();
      }
    }.bind(this));
  },

  askFor: function() {
    var cb = this.async();

    var prompts = [{
      name: 'version',
      message: 'version(0.0.0)'.green,
      default: '0.0.1'
    }, {
      name: 'description',
      message: 'Description'.green,
      default: 'This is awesome application'
    }, {
      name: 'homepage',
      message: 'Homepage'.green
    }, {
      name: 'license',
      message: 'License'.green,
      default: 'MIT'
    }, {
      name: 'githubUsername',
      message: 'GitHub username'.green,
      store: true
    }, {
      name: 'authorName',
      message: 'Author\'s Name'.green,
      store: true
    }, {
      name: 'authorEmail',
      message: 'Author\'s Email'.green,
      store: true
    }, {
      name: 'authorUrl',
      message: 'Author\'s Homepage'.green,
      store: true
    }, {
      name: 'keywords',
      message: 'Give me some Keywords (comma to split)'.green
    }, {
      type: 'confirm',
      name: 'cli',
      message: 'Lets run it from CLI'.green
    }, {
      type: 'confirm',
      name: 'browser',
      message: 'Shall I add Browserify support?'.green
    }, {
      type: "list",
      name: 'taskRunner',
      message: 'Select Task runner'.green,
      choices: [{
        name: 'gulpfile'
      }, {
        name: 'Gruntfile'
      }, {
        name: 'simple'
      }],
      filter: function(val) {
        return val + ".js"
      }
    }, {
      type: "list",
      name: 'test',
      message: 'Choose your test suite'.green,
      choices: [{
        name: 'node_unit'
      }, {
        name: 'mocha_chai'
      }, {
        name: 'jasmine'
      }, {
        name: 'no_test'
      }],
      filter: function(val) {
        return val
      }
    }];

    this.currentYear = (new Date()).getFullYear();

    this.prompt(prompts, function(props) {
      if (props.githubUsername) {
        this.githubUsername = props.githubUsername;
        this.repoUrl = props.githubUsername + '/' + this.slugname;
      } else {
        this.repoUrl = 'user/repo';
      }

      this.keywords = props.keywords.split(',').map(function(el) {
        return el.trim();
      });

      this.props = props;

      cb();
    }.bind(this));
  },

  app: function() {
    this.config.save();
    this.copy('editorconfig', '.editorconfig');
    this.copy('gitignore', '.gitignore');
    this.copy('gitattributes', '.gitattributes');
    this.copy('travis.yml', '.travis.yml');
    this.copy('.npmignore', '.npmignore');

    this.props.unit = {
      "node_unit": true,
      "mocha_chai": false,
      "jasmine": false
    };

    for (var key in this.props.unit) {
      this.props.unit[key] = key === this.props.test ? true : false
    }

    this.template('jshintrc', '.jshintrc');

    var fileName = this.props.taskRunner
    if (fileName !== 'simple.js') {
      this.template(fileName, fileName);
    }

    this.template('README.md', 'README.md');

    this.template('_package.json', 'package.json');

    if (this.props.cli) {
      this.template('cli.js', 'cli.js');
    }
    var license = this.props.license.trim().toUpperCase();
    if (license === 'MIT') {
      this.template('MIT_LICENSE', 'LICENSE');
    }
    if (fileName !== 'simple.js') {
      this.copy('CONTRIBUTING.md', 'CONTRIBUTING.md');
    }
  },

  projectfiles: function() {
    if (this.props.taskRunner === "simple.js") {
      this.mkdir('lib');
      this.template('index.js', 'index.js');
      this.template('test/test.js', 'test.js');
    } else {
      this.mkdir('lib');
      this.template('index.js', 'lib/index.js');
      this.template('test/test.js', 'test/test.js');
    }
  },

  install: function() {
    var self = this;
    this.installDependencies({
      bower: false,
      skipInstall: this.options['skip-install'],
      callback: function(err) {
        gitHubInit({
          username: self.githubUsername,
          token: self.githubToken,
          reponame: self.slugname,
          callback: function(err, data) {
            if (err) {
              self.log(err.red);
              return;
            }
            self.log("I am all done".green);
          }
        })
      }
    });
  }
});
<commit_msg>no need of empty lib folder<commit_after>'use strict';
var path = require('path');
var npmName = require('npm-name');
var yeoman = require('yeoman-generator');
var color = require('colors');
var gitScopeConfig = require('git-scope-config')({
  scope: "global"
});
var gitHubInit = require('github-init');

module.exports = yeoman.generators.Base.extend({
  init: function() {
    this.pkg = require('../package.json');

    var bode = "\n\n" +
      "                                                 dddddddd\n".yellow +
      "BBBBBBBBBBBBBBBBB                                d::::::d\n".yellow +
      "B::::::::::::::::B                               d::::::d\n".yellow +
      "B::::::BBBBBB:::::B                              d::::::d\n".yellow +
      "BB:::::B     B:::::B                             d:::::d\n".green +
      "  B::::B     B:::::B   ooooooooooo       ddddddddd:::::d     eeeeeeeeeeee\n".green +
      "  B::::B     B:::::B oo:::::::::::oo   dd::::::::::::::d   ee::::::::::::ee\n".green +
      "  B::::BBBBBB:::::B o:::::::::::::::o d::::::::::::::::d  e::::::eeeee:::::ee\n".green +
      "  B:::::::::::::BB  o:::::ooooo:::::od:::::::ddddd:::::d e::::::e     e:::::e\n" +
      "  B::::BBBBBB:::::B o::::o     o::::od::::::d    d:::::d e:::::::eeeee::::::e\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e:::::::::::::::::e\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e::::::eeeeeeeeeee\n".blue +
      "  B::::B     B:::::Bo::::o     o::::od:::::d     d:::::d e:::::::e\n".blue +
      "BB:::::BBBBBB::::::Bo:::::ooooo:::::od::::::ddddd::::::dde::::::::e\n".red +
      "B:::::::::::::::::B o:::::::::::::::o d:::::::::::::::::d e::::::::eeeeeeee\n".red +
      "B::::::::::::::::B   oo:::::::::::oo   d:::::::::ddd::::d  ee:::::::::::::e\n".red +
      "BBBBBBBBBBBBBBBBB      ooooooooooo      ddddddddd   ddddd    eeeeeeeeeeeeee\n".red;

    this.log(bode +
      '\nThe name of your project shouldn\'t contain "node" or "js" and'.cyan +
      '\nshould be a unique ID not already in use at npmjs.org.'.cyan);
  },
  askForModuleName: function() {
    var done = this.async();

    var prompts = [{
      name: 'name',
      message: 'Module Name'.green,
      default: path.basename(process.cwd()),
    }, {
      type: 'confirm',
      name: 'pkgName',
      message: 'npm package already exist, please choose another name'.green,
      default: true,
      when: function(answers) {
        var done = this.async();
        npmName(answers.name, function(err, available) {
          if (!available) {
            done(true);
            return;
          }
          done(false);
        });
      }
    }];

    this.prompt(prompts, function(props) {
      if (props.pkgName) {
        return this.askForModuleName();
      }

      this.slugname = this._.slugify(props.name);
      this.safeSlugname = this.slugname.replace(/-+([a-zA-Z0-9])/g, function(g) {
        return g[1].toUpperCase();
      });
      done();
    }.bind(this));
  },

  askForGithubProcess: function() {
    var done = this.async();
    var githubToken;

    var prompt = [{
      type: 'confirm',
      name: 'git',
      message: "create github repo with module name?".green,
      default: true,
    }, {
      when: function(response) {
        var done = this.async();
        if (response.git) {
          gitScopeConfig.get('github.token', function(err, token) {
            if (err) {
              done(true);
              return;
            }
            if (token) {
              githubToken = token;
              done(false);
              return;
            }
          });
        } else {
          done(false);
          return;
        }
      },
      type: 'message',
      name: 'token',
      message: "Github token not found, create new from here".red + " https://github.com/settings/applications".blue
    }]

    this.prompt(prompt, function(props) {
      var _this = this;
      if (props.token) {
        gitScopeConfig.set('github.token', props.token, function(err, status) {
          if (err) {
            done();
            return;
          }
          _this.githubToken = props.token;
          done();
        })
      } else {
        this.githubToken = githubToken;
        done();
      }
    }.bind(this));
  },

  askFor: function() {
    var cb = this.async();

    var prompts = [{
      name: 'version',
      message: 'version(0.0.0)'.green,
      default: '0.0.1'
    }, {
      name: 'description',
      message: 'Description'.green,
      default: 'This is awesome application'
    }, {
      name: 'homepage',
      message: 'Homepage'.green
    }, {
      name: 'license',
      message: 'License'.green,
      default: 'MIT'
    }, {
      name: 'githubUsername',
      message: 'GitHub username'.green,
      store: true
    }, {
      name: 'authorName',
      message: 'Author\'s Name'.green,
      store: true
    }, {
      name: 'authorEmail',
      message: 'Author\'s Email'.green,
      store: true
    }, {
      name: 'authorUrl',
      message: 'Author\'s Homepage'.green,
      store: true
    }, {
      name: 'keywords',
      message: 'Give me some Keywords (comma to split)'.green
    }, {
      type: 'confirm',
      name: 'cli',
      message: 'Lets run it from CLI'.green
    }, {
      type: 'confirm',
      name: 'browser',
      message: 'Shall I add Browserify support?'.green
    }, {
      type: "list",
      name: 'taskRunner',
      message: 'Select Task runner'.green,
      choices: [{
        name: 'gulpfile'
      }, {
        name: 'Gruntfile'
      }, {
        name: 'simple'
      }],
      filter: function(val) {
        return val + ".js"
      }
    }, {
      type: "list",
      name: 'test',
      message: 'Choose your test suite'.green,
      choices: [{
        name: 'node_unit'
      }, {
        name: 'mocha_chai'
      }, {
        name: 'jasmine'
      }, {
        name: 'no_test'
      }],
      filter: function(val) {
        return val
      }
    }];

    this.currentYear = (new Date()).getFullYear();

    this.prompt(prompts, function(props) {
      if (props.githubUsername) {
        this.githubUsername = props.githubUsername;
        this.repoUrl = props.githubUsername + '/' + this.slugname;
      } else {
        this.repoUrl = 'user/repo';
      }

      this.keywords = props.keywords.split(',').map(function(el) {
        return el.trim();
      });

      this.props = props;

      cb();
    }.bind(this));
  },

  app: function() {
    this.config.save();
    this.copy('editorconfig', '.editorconfig');
    this.copy('gitignore', '.gitignore');
    this.copy('gitattributes', '.gitattributes');
    this.copy('travis.yml', '.travis.yml');
    this.copy('.npmignore', '.npmignore');

    this.props.unit = {
      "node_unit": true,
      "mocha_chai": false,
      "jasmine": false
    };

    for (var key in this.props.unit) {
      this.props.unit[key] = key === this.props.test ? true : false
    }

    this.template('jshintrc', '.jshintrc');

    var fileName = this.props.taskRunner
    if (fileName !== 'simple.js') {
      this.template(fileName, fileName);
    }

    this.template('README.md', 'README.md');

    this.template('_package.json', 'package.json');

    if (this.props.cli) {
      this.template('cli.js', 'cli.js');
    }
    var license = this.props.license.trim().toUpperCase();
    if (license === 'MIT') {
      this.template('MIT_LICENSE', 'LICENSE');
    }
    if (fileName !== 'simple.js') {
      this.copy('CONTRIBUTING.md', 'CONTRIBUTING.md');
    }
  },

  projectfiles: function() {
    if (this.props.taskRunner === "simple.js") {
      this.template('index.js', 'index.js');
      this.template('test/test.js', 'test.js');
    } else {
      this.mkdir('lib');
      this.template('index.js', 'lib/index.js');
      this.template('test/test.js', 'test/test.js');
    }
  },

  install: function() {
    var self = this;
    this.installDependencies({
      bower: false,
      skipInstall: this.options['skip-install'],
      callback: function(err) {
        gitHubInit({
          username: self.githubUsername,
          token: self.githubToken,
          reponame: self.slugname,
          callback: function(err, data) {
            if (err) {
              self.log(err.red);
              return;
            }
            self.log("I am all done".green);
          }
        })
      }
    });
  }
});
<|endoftext|>


<commit_before>import * as maptalks from 'maptalks';
import echarts from 'echarts';

const options = {
    'container' : 'front',
    'renderer' : 'dom',
    'hideOnZooming' : false,
    'hideOnMoving' : false,
    'hideOnRotating' : false
};

/**
 * ECharts3 plugin for maptalks.js
 *
 * Thanks to Echarts Team (https://github.com/ecomfe/echarts)
 *
 * @author fuzhenn (fuzhen@maptalks.org)
 *
 * MIT License
 */
export class E3Layer extends maptalks.Layer {

    constructor(id, ecOptions, options) {
        super(id, options);
        this._ecOptions = ecOptions;
    }

    getEChartsOption() {
        return this._ecOptions;
    }

    setEChartsOption(ecOption) {
        this._ecOptions = ecOption;
        if (this._getRenderer()) {
            this._getRenderer()._clearAndRedraw();
        }
        return this;
    }

    /**
     * Export the E3Layer's JSON.
     * @return {Object} layer's JSON
     */
    toJSON() {
        return {
            'type'      : this.getJSONType(),
            'id'        : this.getId(),
            'ecOptions' : this._ecOptions,
            'options'   : this.config()
        };
    }

    /**
     * Reproduce an E3Layer from layer's JSON.
     * @param  {Object} json - layer's JSON
     * @return {maptalks.E3Layer}
     * @static
     * @private
     * @function
     */
    static fromJSON(json) {
        if (!json || json['type'] !== this.getJSONType()) { return null; }
        return new E3Layer(json['id'], json['ecOptions'], json['options']);
    }
}

E3Layer.mergeOptions(options);

E3Layer.registerJSONType('E3Layer');

E3Layer.registerRenderer('dom', class {

    constructor(layer) {
        this.layer = layer;
    }

    render() {
        if (!this._container) {
            this._createLayerContainer();
        }
        if (!this._ec) {
            this._ec = echarts.init(this._container);
            this._prepareECharts();
            this._ec.setOption(this.layer._ecOptions, false);
        } else if (this._isVisible()) {
            this._ec.resize();
        }
        this.layer.fire('layerload');
    }

    drawOnInteracting() {
        if (this._isVisible()) {
            this._ec.resize();
        }
    }

    needToRedraw() {
        const map = this.getMap();
        const renderer = map._getRenderer();
        return map.isInteracting() || renderer && renderer.isStateChanged();
    }

    getMap() {
        return this.layer.getMap();
    }

    _isVisible() {
        return this._container && this._container.style.display === '';
    }

    show() {
        if (this._container) {
            this._container.style.display = '';
        }
    }

    hide() {
        if (this._container) {
            this._container.style.display = 'none';
            this.clear();
        }
    }

    remove() {
        this._ec.clear();
        this._ec.dispose();
        delete this._ec;
        this._removeLayerContainer();
    }

    clear() {
        this._ec.clear();
    }

    setZIndex(z) {
        this._zIndex = z;
        if (this._container) {
            this._container.style.zIndex = z;

        }
    }

    isCanvasRender() {
        return false;
    }

    _prepareECharts() {
        if (!this._registered) {
            echarts.registerCoordinateSystem(
                'maptalks', this._getE3CoordinateSystem(this.getMap())
            );
            this._registered = true;
        }
        const series = this.layer._ecOptions.series;
        if (series) {
            for (let i = series.length - 1; i >= 0; i--) {
                //change coordinateSystem to maptalks
                series[i]['coordinateSystem'] = 'maptalks';
                //disable update animations
                series[i]['animation'] = false;
            }
        }
    }

    _createLayerContainer() {
        const container = this._container = maptalks.DomUtil.createEl('div');
        container.style.cssText = 'position:absolute;left:0px;top:0px;';
        if (this._zIndex) {
            container.style.zIndex = this._zIndex;
        }
        this._resetContainer();
        const parentContainer = this.layer.options['container'] === 'front' ? this.getMap()._panels['frontStatic'] : this.getMap()._panels['backStatic'];
        parentContainer.appendChild(container);
    }

    _removeLayerContainer() {
        if (this._container) {
            maptalks.DomUtil.removeDomNode(this._container);
        }
        delete this._levelContainers;
    }

    _resetContainer() {
        const size = this.getMap().getSize();
        // maptalks.DomUtil.offsetDom(this._container, point.multi(-1));
        this._container.style.width = size.width + 'px';
        this._container.style.height = size.height + 'px';
    }

    /**
     * Coordinate System for echarts 3
     * based on echarts's bmap plugin
     * https://github.com/ecomfe/echarts/blob/f383dcc1adb4c7b9e1888bda3fc976561a788020/extension/bmap/BMapCoordSys.js
     */
    _getE3CoordinateSystem(map) {
        const CoordSystem = function (map) {
            this.map = map;
            this._mapOffset = [0, 0];
        };

        CoordSystem.create = function (ecModel/*, api*/) {
            ecModel.eachSeries(function (seriesModel) {
                if (seriesModel.get('coordinateSystem') === 'maptalks') {
                    seriesModel.coordinateSystem = new CoordSystem(map);
                }
            });
        };

        CoordSystem.getDimensionsInfo = function () {
            return ['x', 'y'];
        };

        CoordSystem.dimensions = ['x', 'y'];

        maptalks.Util.extend(CoordSystem.prototype, {
            dimensions : ['x', 'y'],

            setMapOffset(mapOffset) {
                this._mapOffset = mapOffset;
            },

            dataToPoint(data) {
                const coord = new maptalks.Coordinate(data);
                const px = this.map.coordinateToContainerPoint(coord);
                const mapOffset = this._mapOffset;
                return [px.x - mapOffset[0], px.y - mapOffset[1]];
            },

            pointToData(pt) {
                const mapOffset = this._mapOffset;
                const data = this.map.containerPointToCoordinate({
                    x: pt[0] + mapOffset[0],
                    y: pt[1] + mapOffset[1]
                });
                return [data.x, data.y];
            },

            getViewRect() {
                const size = this.map.getSize();
                return new echarts.graphic.BoundingRect(0, 0, size.width, size.height);
            },

            getRoamTransform() {
                return echarts.matrix.create();
            }
        });

        return CoordSystem;
    }

    getEvents() {
        return {
            '_zoomstart' : this.onZoomStart,
            '_zoomend'   : this.onZoomEnd,
            '_dragrotatestart' : this.onDragRotateStart,
            '_dragrotateend'   : this.onDragRotateEnd,
            '_movestart' : this.onMoveStart,
            '_moveend'   : this.onMoveEnd,
            '_resize'    : this._resetContainer
        };
    }

    _clearAndRedraw() {
        if (this._container && this._container.style.display === 'none') {
            return;
        }
        this._ec.clear();
        this._ec.resize();
        this._prepareECharts();
        this._ec.setOption(this.layer._ecOptions, false);
    }

    onZoomStart() {
        if (!this.layer.options['hideOnZooming']) {
            return;
        }
        this.hide();
    }

    onZoomEnd() {
        if (!this.layer.options['hideOnZooming']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }

    onDragRotateStart() {
        if (!this.layer.options['hideOnRotating']) {
            return;
        }
        this.hide();
    }

    onDragRotateEnd() {
        if (!this.layer.options['hideOnRotating']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }

    onMoveStart() {
        if (!this.layer.options['hideOnMoving']) {
            return;
        }
        this.hide();
    }

    onMoveEnd() {
        if (!this.layer.options['hideOnMoving']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }
});
<commit_msg>fix fromJSON<commit_after>import * as maptalks from 'maptalks';
import echarts from 'echarts';

const options = {
    'container' : 'front',
    'renderer' : 'dom',
    'hideOnZooming' : false,
    'hideOnMoving' : false,
    'hideOnRotating' : false
};

/**
 * ECharts3 plugin for maptalks.js
 *
 * Thanks to Echarts Team (https://github.com/ecomfe/echarts)
 *
 * @author fuzhenn (fuzhen@maptalks.org)
 *
 * MIT License
 */
export class E3Layer extends maptalks.Layer {

    constructor(id, ecOptions, options) {
        super(id, options);
        this._ecOptions = ecOptions;
    }

    getEChartsOption() {
        return this._ecOptions;
    }

    setEChartsOption(ecOption) {
        this._ecOptions = ecOption;
        if (this._getRenderer()) {
            this._getRenderer()._clearAndRedraw();
        }
        return this;
    }

    /**
     * Export the E3Layer's JSON.
     * @return {Object} layer's JSON
     */
    toJSON() {
        return {
            'type'      : this.getJSONType(),
            'id'        : this.getId(),
            'ecOptions' : this._ecOptions,
            'options'   : this.config()
        };
    }

    /**
     * Reproduce an E3Layer from layer's JSON.
     * @param  {Object} json - layer's JSON
     * @return {maptalks.E3Layer}
     * @static
     * @private
     * @function
     */
    static fromJSON(json) {
        if (!json || json['type'] !== 'E3Layer') { return null; }
        return new E3Layer(json['id'], json['ecOptions'], json['options']);
    }
}

E3Layer.mergeOptions(options);

E3Layer.registerJSONType('E3Layer');

E3Layer.registerRenderer('dom', class {

    constructor(layer) {
        this.layer = layer;
    }

    render() {
        if (!this._container) {
            this._createLayerContainer();
        }
        if (!this._ec) {
            this._ec = echarts.init(this._container);
            this._prepareECharts();
            this._ec.setOption(this.layer._ecOptions, false);
        } else if (this._isVisible()) {
            this._ec.resize();
        }
        this.layer.fire('layerload');
    }

    drawOnInteracting() {
        if (this._isVisible()) {
            this._ec.resize();
        }
    }

    needToRedraw() {
        const map = this.getMap();
        const renderer = map._getRenderer();
        return map.isInteracting() || renderer && renderer.isStateChanged();
    }

    getMap() {
        return this.layer.getMap();
    }

    _isVisible() {
        return this._container && this._container.style.display === '';
    }

    show() {
        if (this._container) {
            this._container.style.display = '';
        }
    }

    hide() {
        if (this._container) {
            this._container.style.display = 'none';
            this.clear();
        }
    }

    remove() {
        this._ec.clear();
        this._ec.dispose();
        delete this._ec;
        this._removeLayerContainer();
    }

    clear() {
        this._ec.clear();
    }

    setZIndex(z) {
        this._zIndex = z;
        if (this._container) {
            this._container.style.zIndex = z;

        }
    }

    isCanvasRender() {
        return false;
    }

    _prepareECharts() {
        if (!this._registered) {
            echarts.registerCoordinateSystem(
                'maptalks', this._getE3CoordinateSystem(this.getMap())
            );
            this._registered = true;
        }
        const series = this.layer._ecOptions.series;
        if (series) {
            for (let i = series.length - 1; i >= 0; i--) {
                //change coordinateSystem to maptalks
                series[i]['coordinateSystem'] = 'maptalks';
                //disable update animations
                series[i]['animation'] = false;
            }
        }
    }

    _createLayerContainer() {
        const container = this._container = maptalks.DomUtil.createEl('div');
        container.style.cssText = 'position:absolute;left:0px;top:0px;';
        if (this._zIndex) {
            container.style.zIndex = this._zIndex;
        }
        this._resetContainer();
        const parentContainer = this.layer.options['container'] === 'front' ? this.getMap()._panels['frontStatic'] : this.getMap()._panels['backStatic'];
        parentContainer.appendChild(container);
    }

    _removeLayerContainer() {
        if (this._container) {
            maptalks.DomUtil.removeDomNode(this._container);
        }
        delete this._levelContainers;
    }

    _resetContainer() {
        const size = this.getMap().getSize();
        // maptalks.DomUtil.offsetDom(this._container, point.multi(-1));
        this._container.style.width = size.width + 'px';
        this._container.style.height = size.height + 'px';
    }

    /**
     * Coordinate System for echarts 3
     * based on echarts's bmap plugin
     * https://github.com/ecomfe/echarts/blob/f383dcc1adb4c7b9e1888bda3fc976561a788020/extension/bmap/BMapCoordSys.js
     */
    _getE3CoordinateSystem(map) {
        const CoordSystem = function (map) {
            this.map = map;
            this._mapOffset = [0, 0];
        };

        CoordSystem.create = function (ecModel/*, api*/) {
            ecModel.eachSeries(function (seriesModel) {
                if (seriesModel.get('coordinateSystem') === 'maptalks') {
                    seriesModel.coordinateSystem = new CoordSystem(map);
                }
            });
        };

        CoordSystem.getDimensionsInfo = function () {
            return ['x', 'y'];
        };

        CoordSystem.dimensions = ['x', 'y'];

        maptalks.Util.extend(CoordSystem.prototype, {
            dimensions : ['x', 'y'],

            setMapOffset(mapOffset) {
                this._mapOffset = mapOffset;
            },

            dataToPoint(data) {
                const coord = new maptalks.Coordinate(data);
                const px = this.map.coordinateToContainerPoint(coord);
                const mapOffset = this._mapOffset;
                return [px.x - mapOffset[0], px.y - mapOffset[1]];
            },

            pointToData(pt) {
                const mapOffset = this._mapOffset;
                const data = this.map.containerPointToCoordinate({
                    x: pt[0] + mapOffset[0],
                    y: pt[1] + mapOffset[1]
                });
                return [data.x, data.y];
            },

            getViewRect() {
                const size = this.map.getSize();
                return new echarts.graphic.BoundingRect(0, 0, size.width, size.height);
            },

            getRoamTransform() {
                return echarts.matrix.create();
            }
        });

        return CoordSystem;
    }

    getEvents() {
        return {
            '_zoomstart' : this.onZoomStart,
            '_zoomend'   : this.onZoomEnd,
            '_dragrotatestart' : this.onDragRotateStart,
            '_dragrotateend'   : this.onDragRotateEnd,
            '_movestart' : this.onMoveStart,
            '_moveend'   : this.onMoveEnd,
            '_resize'    : this._resetContainer
        };
    }

    _clearAndRedraw() {
        if (this._container && this._container.style.display === 'none') {
            return;
        }
        this._ec.clear();
        this._ec.resize();
        this._prepareECharts();
        this._ec.setOption(this.layer._ecOptions, false);
    }

    onZoomStart() {
        if (!this.layer.options['hideOnZooming']) {
            return;
        }
        this.hide();
    }

    onZoomEnd() {
        if (!this.layer.options['hideOnZooming']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }

    onDragRotateStart() {
        if (!this.layer.options['hideOnRotating']) {
            return;
        }
        this.hide();
    }

    onDragRotateEnd() {
        if (!this.layer.options['hideOnRotating']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }

    onMoveStart() {
        if (!this.layer.options['hideOnMoving']) {
            return;
        }
        this.hide();
    }

    onMoveEnd() {
        if (!this.layer.options['hideOnMoving']) {
            return;
        }
        this.show();
        this._clearAndRedraw();
    }
});
<|endoftext|>


<commit_before>'use strict';

var yeoman = require('yeoman-generator'),
  util = require('util'),
  path = require('path'),
  chalk = require('chalk'),
  _ = require('lodash'),
  npmLatest = require('npm-latest'),
  bowerLatest = require('bower-latest');

var SandboxGenerator =  module.exports = function SandboxGenerator(args, options) {
  yeoman.generators.Base.apply(this, arguments);

  this.options = _.merge(this.options, {
    reqTimeout : 15000
  });
  _.merge(this.options, options);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });
};

util.inherits(SandboxGenerator, yeoman.generators.Base);

SandboxGenerator.prototype._stringifyPrettyJSON = function _stringifyPrettyJSON(obj) {
  return JSON.stringify(obj, null, 2);
};

// Welcome message
SandboxGenerator.prototype.welcome = function welcome() {
  this.log(this.yeoman);
  this.log(chalk.magenta('Welcome to the Sandbox generator.'));
};

SandboxGenerator.prototype.promptUser = function promptUser() {
  var done = this.async();

  var prompts = [{
    name: 'appName',
    message: 'What is the name of your app?',
    default: path.basename(process.cwd())
  }, {
    type: 'checkbox',
    name: 'basicFeatures',
    message: 'What would you like to include?',
    choices: [{
      name: 'AngularJS',
      value: 'includeAngular',
      checked: false
    }, {
      name: 'Lo-dash',
      value: 'includeLodash',
      checked: false
    }, {
      name: 'SCSS',
      value: 'includeScss',
      checked: false
    }]
  }, {
    when: function (answers) {
      return answers.basicFeatures.indexOf('includeScss') !== -1;
    },
    type: 'checkbox',
    name: 'scssFeatures',
    message: 'Which SCSS features would you like to include?',
    choices: [{
      name: 'Normalize.scss',
      value: 'includeNormalizeScss',
      checked: false
    }, {
      name: 'Csswizardry-grids',
      value: 'includeCsswizardryGrids',
      checked: false
    },
    {
      name: 'Bourbon',
      value: 'includeBourbon',
      checked: false
    }]
  }];

  this.prompt(prompts, function (answers) {
    this.appName = answers.appName;
    var features = answers.basicFeatures.concat(answers.scssFeatures);

    function hasFeature(feat) {
      return features.indexOf(feat) !== -1;
    }
    this.includeAngular = hasFeature('includeAngular');
    this.includeLodash = hasFeature('includeLodash');
    this.includeScss = hasFeature('includeScss');
    this.includeNormalizeScss = hasFeature('includeNormalizeScss');
    this.includeCsswizardryGrids = hasFeature('includeCsswizardryGrids');
    this.includeBourbon = hasFeature('includeBourbon');

    done();
  }.bind(this));
};

SandboxGenerator.prototype.app = function app() {
  this.mkdir('public');
  this.mkdir('public/scripts');
  this.mkdir('public/styles');

  this.template('_index.html', 'public/index.html');
  this.template('_main.js', 'public/scripts/main.js');

  if (this.includeScss) {
    this.mkdir('public/styles/css');
    this.mkdir('public/styles/scss');
    this.template('_main.scss', 'public/styles/scss/main.scss');
  } else {
    this.copy('_main.css', 'public/styles/main.css');
  }
};

SandboxGenerator.prototype.gulpfile = function gulpfile() {
  this.template('_gulpfile.js', 'gulpfile.js');
};

SandboxGenerator.prototype.packageJSON = function packageJSON() {
  var cb = this.async();

  // Generate package.json
  var _packageJSON = require(path.join(__dirname + '/templates/_package.json'));
  _packageJSON.name = this.appName;

  var npmList = [];

  // Add dev-dependencies
  npmList.push('gulp');
  if (this.includeScss === true) {
    npmList.push('gulp-ruby-sass');
  }
  npmList.push('gulp-jshint');
  npmList.push('gulp-jscs');
  npmList.push('jshint-stylish');
  npmList.push('gulp-open');
  npmList.push('gulp-livereload');
  npmList.push('gulp-notify-growl');
  npmList.push('gulp-connect');
  npmList.push('wiredep');

  var count = npmList.length;

  if (count === 0) {
    return cb();
  }

  var that = this;
  _.each(npmList, function (packageName) {
    npmLatest(packageName, {timeout: that.options.reqTimeout}, function (err, result) {
      if (!err && result.name && result.version) {
        _packageJSON.devDependencies[result.name] = result.version;
      } else {
        // take the latest
        _packageJSON.devDependencies[packageName] = '*';
      }
      if (!--count) {
        // Write to file
        this.write('package.json', this._stringifyPrettyJSON(_packageJSON));
        cb();
      }
    }.bind(this));
  }, this);

};

SandboxGenerator.prototype.bower = function bower() {

  var cb = this.async();

  // Generate bower.json
  var _bowerJSON = require(path.join(__dirname + '/templates/_bower.json'));
  _bowerJSON.name = this.appName;

  var bowerList = [];
  // Add dependencies
  if (this.includeAngular === true) {
    bowerList.push('angular');
  }
  if (this.includeLodash === true) {
    bowerList.push('lodash');
  }
  if (this.includeNormalizeScss === true) {
    bowerList.push('normalize.scss');
  }
  if (this.includeCsswizardryGrids === true) {
    bowerList.push('csswizardry-grids');
  }
  if (this.includeBourbon === true) {
    bowerList.push('bourbon');
  }

  var count = bowerList.length;

  if (count === 0) {
    this.write('bower.json', this._stringifyPrettyJSON(_bowerJSON));
    this.copy('bowerrc', '.bowerrc');
    return cb();
  }

  var that = this;
  _.each(bowerList, function (packageName) {
    bowerLatest(packageName, {timeout: that.options.reqTimeout}, function (result) {
      if (result && result.name && result.version) {
        _bowerJSON.dependencies[result.name] = result.version;
      } else {
        // take the latest
        _bowerJSON.dependencies[packageName] = '*';
      }
      if (!--count) {
        // Write to file
        that.write('bower.json', that._stringifyPrettyJSON(_bowerJSON));
        that.copy('bowerrc', '.bowerrc');
        cb();
      }
    });
  });
};

SandboxGenerator.prototype.jsHint = function jsHint() {
  this.template('jshintrc', '.jshintrc');
};

SandboxGenerator.prototype.jscsJson = function jscsJson() {
  this.copy('jscs.json', '.jscs.json');
};

SandboxGenerator.prototype.editorConfig = function editorConfig() {
  this.copy('editorconfig', '.editorconfig');
};

SandboxGenerator.prototype.git = function git() {
  this.copy('gitattributes', '.gitattributes');
  this.template('gitignore', '.gitignore');
};

SandboxGenerator.prototype.readme = function readme() {
  this.template('_README.md', 'README.md');
};
<commit_msg>replace gulp-connect with connect<commit_after>'use strict';

var yeoman = require('yeoman-generator'),
  util = require('util'),
  path = require('path'),
  chalk = require('chalk'),
  _ = require('lodash'),
  npmLatest = require('npm-latest'),
  bowerLatest = require('bower-latest');

var SandboxGenerator =  module.exports = function SandboxGenerator(args, options) {
  yeoman.generators.Base.apply(this, arguments);

  this.options = _.merge(this.options, {
    reqTimeout : 15000
  });
  _.merge(this.options, options);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });
};

util.inherits(SandboxGenerator, yeoman.generators.Base);

SandboxGenerator.prototype._stringifyPrettyJSON = function _stringifyPrettyJSON(obj) {
  return JSON.stringify(obj, null, 2);
};

// Welcome message
SandboxGenerator.prototype.welcome = function welcome() {
  this.log(this.yeoman);
  this.log(chalk.magenta('Welcome to the Sandbox generator.'));
};

SandboxGenerator.prototype.promptUser = function promptUser() {
  var done = this.async();

  var prompts = [{
    name: 'appName',
    message: 'What is the name of your app?',
    default: path.basename(process.cwd())
  }, {
    type: 'checkbox',
    name: 'basicFeatures',
    message: 'What would you like to include?',
    choices: [{
      name: 'AngularJS',
      value: 'includeAngular',
      checked: false
    }, {
      name: 'Lo-dash',
      value: 'includeLodash',
      checked: false
    }, {
      name: 'SCSS',
      value: 'includeScss',
      checked: false
    }]
  }, {
    when: function (answers) {
      return answers.basicFeatures.indexOf('includeScss') !== -1;
    },
    type: 'checkbox',
    name: 'scssFeatures',
    message: 'Which SCSS features would you like to include?',
    choices: [{
      name: 'Normalize.scss',
      value: 'includeNormalizeScss',
      checked: false
    }, {
      name: 'Csswizardry-grids',
      value: 'includeCsswizardryGrids',
      checked: false
    },
    {
      name: 'Bourbon',
      value: 'includeBourbon',
      checked: false
    }]
  }];

  this.prompt(prompts, function (answers) {
    this.appName = answers.appName;
    var features = answers.basicFeatures.concat(answers.scssFeatures);

    function hasFeature(feat) {
      return features.indexOf(feat) !== -1;
    }
    this.includeAngular = hasFeature('includeAngular');
    this.includeLodash = hasFeature('includeLodash');
    this.includeScss = hasFeature('includeScss');
    this.includeNormalizeScss = hasFeature('includeNormalizeScss');
    this.includeCsswizardryGrids = hasFeature('includeCsswizardryGrids');
    this.includeBourbon = hasFeature('includeBourbon');

    done();
  }.bind(this));
};

SandboxGenerator.prototype.app = function app() {
  this.mkdir('public');
  this.mkdir('public/scripts');
  this.mkdir('public/styles');

  this.template('_index.html', 'public/index.html');
  this.template('_main.js', 'public/scripts/main.js');

  if (this.includeScss) {
    this.mkdir('public/styles/css');
    this.mkdir('public/styles/scss');
    this.template('_main.scss', 'public/styles/scss/main.scss');
  } else {
    this.copy('_main.css', 'public/styles/main.css');
  }
};

SandboxGenerator.prototype.gulpfile = function gulpfile() {
  this.template('_gulpfile.js', 'gulpfile.js');
};

SandboxGenerator.prototype.packageJSON = function packageJSON() {
  var cb = this.async();

  // Generate package.json
  var _packageJSON = require(path.join(__dirname + '/templates/_package.json'));
  _packageJSON.name = this.appName;

  var npmList = [];

  // Add dev-dependencies
  npmList.push('gulp');
  if (this.includeScss === true) {
    npmList.push('gulp-ruby-sass');
  }
  npmList.push('gulp-jshint');
  npmList.push('gulp-jscs');
  npmList.push('jshint-stylish');
  npmList.push('gulp-open');
  npmList.push('gulp-livereload');
  npmList.push('gulp-notify-growl');
  npmList.push('connect');
  npmList.push('wiredep');

  var count = npmList.length;

  if (count === 0) {
    return cb();
  }

  var that = this;
  _.each(npmList, function (packageName) {
    npmLatest(packageName, {timeout: that.options.reqTimeout}, function (err, result) {
      if (!err && result.name && result.version) {
        _packageJSON.devDependencies[result.name] = result.version;
      } else {
        // take the latest
        _packageJSON.devDependencies[packageName] = '*';
      }
      if (!--count) {
        // Write to file
        this.write('package.json', this._stringifyPrettyJSON(_packageJSON));
        cb();
      }
    }.bind(this));
  }, this);

};

SandboxGenerator.prototype.bower = function bower() {

  var cb = this.async();

  // Generate bower.json
  var _bowerJSON = require(path.join(__dirname + '/templates/_bower.json'));
  _bowerJSON.name = this.appName;

  var bowerList = [];
  // Add dependencies
  if (this.includeAngular === true) {
    bowerList.push('angular');
  }
  if (this.includeLodash === true) {
    bowerList.push('lodash');
  }
  if (this.includeNormalizeScss === true) {
    bowerList.push('normalize.scss');
  }
  if (this.includeCsswizardryGrids === true) {
    bowerList.push('csswizardry-grids');
  }
  if (this.includeBourbon === true) {
    bowerList.push('bourbon');
  }

  var count = bowerList.length;

  if (count === 0) {
    this.write('bower.json', this._stringifyPrettyJSON(_bowerJSON));
    this.copy('bowerrc', '.bowerrc');
    return cb();
  }

  var that = this;
  _.each(bowerList, function (packageName) {
    bowerLatest(packageName, {timeout: that.options.reqTimeout}, function (result) {
      if (result && result.name && result.version) {
        _bowerJSON.dependencies[result.name] = result.version;
      } else {
        // take the latest
        _bowerJSON.dependencies[packageName] = '*';
      }
      if (!--count) {
        // Write to file
        that.write('bower.json', that._stringifyPrettyJSON(_bowerJSON));
        that.copy('bowerrc', '.bowerrc');
        cb();
      }
    });
  });
};

SandboxGenerator.prototype.jsHint = function jsHint() {
  this.template('jshintrc', '.jshintrc');
};

SandboxGenerator.prototype.jscsJson = function jscsJson() {
  this.copy('jscs.json', '.jscs.json');
};

SandboxGenerator.prototype.editorConfig = function editorConfig() {
  this.copy('editorconfig', '.editorconfig');
};

SandboxGenerator.prototype.git = function git() {
  this.copy('gitattributes', '.gitattributes');
  this.template('gitignore', '.gitignore');
};

SandboxGenerator.prototype.readme = function readme() {
  this.template('_README.md', 'README.md');
};
<|endoftext|>


<commit_before>(function(root, definition) {
    if (typeof define === 'function' && define.amd) {
        define(['equation-tokenizer/equation-tokenizer'], definition);
    } else if (typeof exports === 'object') {
        var tokenize = require('../equation-tokenizer/equation-tokenizer');
        module.exports = definition(tokenize);
    } else {
        root.infix2postfix = definition(root.tokenize_equation);
    }
})(this, function(tokenize) {
    function precedence(a, b) {
        if ((a === '*' || a === '/') && (b === '+' || b === '-')) {
            return -1;
        } else if ((a === '+' || a === '-') && (b === '*' || b === '/')) {
            return 1;
        }
        return 0;
    }

    function convert(equation, keep_tokens) {
        var tokens = equation instanceof Array ? equation : tokenize(equation, true);
        var stack = [];
        var postfix = [];

        tokens.forEach(function(token) {
            if (token.type === 'operand') {
                postfix.push(token);
            } else if (token.type === 'operator') {
                if (!stack.length) {
                    stack.push(token);
                } else {
                    var top = stack.pop();
                    if (precedence(token.value, top.value) <= 0) {
                        stack.push(top, token);
                    } else {
                        stack.push(token);
                        postfix.push(top);
                    }
                }
            } else if (token.type === 'equation') {
                postfix = postfix.concat(convert(token.value, true));
            }
        });

        while (stack.length) {
            postfix.push(stack.pop());
        }

        if (!keep_tokens) {
            var values = [];
            postfix.forEach(function(token) {
                values.push(token.value)
            });
            return values.join(' ');
        }
        return postfix;
    }

    return convert;
});<commit_msg>fixed a bug in infix to postfix converter that makes it fail test case<commit_after>(function(root, definition) {
    if (typeof define === 'function' && define.amd) {
        define(['equation-tokenizer/equation-tokenizer'], definition);
    } else if (typeof exports === 'object') {
        var tokenize = require('../equation-tokenizer/equation-tokenizer');
        module.exports = definition(tokenize);
    } else {
        root.infix2postfix = definition(root.tokenize_equation);
    }
})(this, function(tokenize) {
    function precedence(a, b) {
        if ((a === '*' || a === '/') && (b === '+' || b === '-')) {
            return -1;
        } else if ((a === '+' || a === '-') && (b === '*' || b === '/')) {
            return 1;
        }
        return 0;
    }

    function convert(equation, keep_tokens) {
        var tokens = equation instanceof Array ? equation : tokenize(equation, true);
        var stack = [];
        var postfix = [];

        tokens.forEach(function(token) {
            if (token.type === 'operand') {
                postfix.push(token);
            } else if (token.type === 'operator') {
                if (!stack.length) {
                    stack.push(token);
                } else {
                    var top = stack.pop();
                    if (precedence(token.value, top.value) < 0) {
                        stack.push(top, token);
                    } else {
                        stack.push(token);
                        postfix.push(top);
                    }
                }
            } else if (token.type === 'equation') {
                postfix = postfix.concat(convert(token.value, true));
            }
        });

        while (stack.length) {
            postfix.push(stack.pop());
        }

        if (!keep_tokens) {
            var values = [];
            postfix.forEach(function(token) {
                values.push(token.value)
            });
            return values.join(' ');
        }
        return postfix;
    }

    return convert;
});<|endoftext|>


<commit_before>"use strict"

var webglew = require("webglew")
var createBuffer = require("gl-buffer")
var createVAO = require("gl-vao")
var ndarray = require("ndarray")
var ops = require("ndarray-ops")
var pool = require("typedarray-pool")

var Mesh = require("./lib/mesh.js")

function EmptyMesh(gl) {
  this.gl = gl
  this.mode = gl.POINTS
  this.numElements = 0
  this.elements = null
  this.attributes = {}
}
EmptyMesh.prototype.dispose = function() {}
EmptyMesh.prototype.bind = function() {}
EmptyMesh.prototype.unbind = function() {}
EmptyMesh.prototype.draw = function() {}

function MeshAttribute(buffer, size, type, normalized) {
  this.buffer = buffer
  this.size = size
  this.type = type
  this.normalized = normalized
}

function getGLType(gl, array) {
  if((array instanceof Uint8Array) ||
     (array instanceof Uint8ClampedArray)) {
    return gl.UNSIGNED_BYTE
  } else if(array instanceof Int8Array) {
    return gl.BYTE
  } else if(array instanceof Uint16Array) {
    return gl.UNSIGNED_SHORT
  } else if(array instanceof Int16Array) {
    return gl.SHORT
  } else if(array instanceof Uint32Array) {
    return gl.UNSIGNED_INT
  } else if(array instanceof Int32Array) {
    return gl.INT
  } else if(array instanceof Float32Array) {
    return gl.FLOAT
  }
  return 0
}

function createTmpArray(gl, type, n) {
  if(type === gl.UNSIGNED_BYTE) {
    return pool.mallocUint8(n)
  } else if(type === gl.BYTE) {
    return pool.mallocInt8(n)
  } else if(type === gl.UNSIGNED_SHORT) {
    return pool.mallocUint16(n)
  } else if(type === gl.SHORT) {
    return pool.mallocInt16(n)
  } else if(type === gl.UNSIGNED_INT) {
    return pool.mallocUint32(n)
  } else if(type === gl.INT) {
    return pool.mallocInt32(n)
  }
  return pool.mallocFloat32(n)
}

function packAttributes(gl, numVertices, attributes) {
  var attrNames = []
  var attrVals = []
  for(var name in attributes) {
    var attr = attributes[name]
    var buffer, type, normalized, size
    if(typeof attr.length === "number") {
      if(attr.length !== numVertices) {
        throw new Error("Incorrect vertex count for attribute " + name)
      }
      if(typeof attr[0] === "number") {
        var gltype = getGLType(attr)
        if(gltype) {
          //Case: typed array
          size = 1
          type = gltype
          normalized = (gltype === gl.BYTE || gltype === gl.UNSIGNED_BYTE)
          buffer = createBuffer(gl, attr)
        } else {
          //Case: native array of numbers
          var tmp_buf = pool.mallocFloat32(numVertices)
          for(var i=0; i<numVertices; ++i) {
            tmp_buf[i] = attr[i]
          }
          size = 1
          type = gl.FLOAT
          normalized = false
          buffer = createBuffer(gl, tmp_buf.subarray(0, numVertices))
          pool.freeUint32(tmp_buf)
        }
      } else if(attr[0].length) {
        //Case: native array of arrays
        size = attr[0].length|0
        var ptr = 0
        var tmp_buf = pool.mallocFloat32(size * numVertices)
        for(var i=0; i<numVertices; ++i) {
          var vert = attr[i]
          for(var j=0; j<size; ++j) {
            tmp_buf[ptr++] = vert[j]
          }
        }
        type = gl.FLOAT
        normalized = false
        buffer = createBuffer(gl, tmp_buf.subarray(0, ptr))
        pool.freeFloat32(tmp_buf)
      }
    } else if(attr.shape) {
      if(attr.shape[0] !== numVertices) {
        throw new Error("Invalid shape for attribute " + name)
      }
      //Check if type is compatible
      var packed = true
      type = getGLType(gl, attr.data)
      if(!type) {
        packed = false
        type = gl.FLOAT
      }
      if(stride[0] !== 1 || (shape[1] > 1 && stride[1] !== 1)) {
        packed = false
      }
      //Check if array has to be normalized
      normalized = (type === gl.BYTE || type === gl.UNSIGNED_BYTE)
      size = attr.shape[1]
      if(packed) {
        //Case: packed ndarray, directly blit into buffer
        if(attr.offset === 0 && attr.data.length === size*numVertices) {
          buffer = createBuffer(gl, attr.data)
        } else {
          buffer = createBuffer(gl, attr.data.subarray(0, size*numVertices))
        }
      } else {
        //Case: unpacked ndarray, create new array and blit
        var tmp_buf = createTmpArray(gl, type, size*numVertices)
        var tmp = ndarray(tmp_buf, attr.shape)
        ops.assign(tmp, attr)
        buffer = createBuffer(gl, tmp.data.subarray(0, size*numVertices))
        pool.free(tmp_buf)
      }
    } else {
      throw new Error("Invalid vertex attribute " + name)
    }
    attrNames.push(name)
    attrVals.push(new MeshAttribute(buffer, size, type, normalized))
  }
  return {
    names: attrNames,
    values: attrVals
  }
}

function packAttributesFromNDArray(gl, numVertices, attributes, elements) {
  var n = elements.shape[0]|0
  var d = elements.shape[1]|0
  var numElements = (n*d)|0
  var attrNames, attrVals
  for(var name in attributes) {
    var attr = attributes[name]
    if(typeof attr.length === "number") {
      if(attr[0].length !== numVertices) {
        throw new Error("Invalid attribute size for attribute " + name)
      }
    } else if(attr.shape) {

    } else {
      throw new Error("Invalid attribute " + name)
    }
  }
  return {
    names: attrNames,
    values: attrVals
  }
}

function packAttributesFrom1DArray(gl, numVertices, attributes, elements) {
  var n = elements.length|0
  var buf = pool.mallocUint32(n)
  for(var i=0; i<n; ++i) {
    buf[i] = elements[i]
  }
  var result = packAttributesFromNDArray(gl, numVertices, attributes, ndarray(buf, [n, 1]))
  pool.freeUint32(buf)
  return result
}

function packAttributesFromArray(gl, numVertices, attributes, elements) {
  var n = elements.length|0
  var d = elements[0].length|0
  var ptr = 0
  var buf = pool.mallocUint32(n*d)
  for(var i=0; i<n; ++i) {
    var list = elements[i]
    for(var j=0; j<d; ++j) {
      buf[ptr++] = list[j]
    }
  }
  var result = packAttributesFromNDArray(gl, numVertices, attributes, ndarray(buf, [n, d]))
  pool.freeUint32(buf)
  return result
}

//Builds the actual mesh object, selecting appropriate implementation depending on if vertex attribute objects are supported
function buildMeshObject(gl, mode, numElements, elements, attributes) {
  if(numElements === 0) {
    return new EmptyMesh(gl)
  }
  var vao = createVAO(gl, elements, attributes.values)
  return new Mesh(gl, mode, numElements, vao, elements, attributes.values, attributes.names)
}

//Creates a mesh
function createMesh(gl, elements, attributes) {

  //Special case: handle object with cells/positions/etc. for attributes
  if(arguments.length === 2) {
    if(elements.cells) {
      attributes = {}
      for(var id in elements) {
        if(id === "cells") {
          continue
        }
        attributes[id] = elements[id]
      }
      elements = elements.cells
    }
  }

  //First figure out what mode we are using (POINTS, LINES or TRIANGLES)
  var mode
  if(attributes === undefined) {
    //Special case for point clouds
    attributes = elements
    elements = undefined
    mode = gl.POINTS
  } else if(elements instanceof Array) {
    if(elements.length === 0) {
      //Empty array, return empty mesh
      return buildMeshObject(gl, gl.POINTS, 0, null, [])
    } else if(typeof elements[0] === "number" || elements[0].length === 1) {
      mode = gl.POINTS
    } else if(elements[0].length === 2) {
      mode = gl.LINES
    } else if(elements[0].length === 3) {
      mode = gl.TRIANGLES
    } else {
      throw new Error("Invalid shape for element array")
    }
  } else if(elements.shape) {
    if(elements.shape.length === 1) {
      mode = gl.POINTS
      //Special case: convert to 2d element array for point cloud automatically to simplify things later on
      elements = ndarray(elements.data, [elements.shape[0], 1], [elements.stride[0], 1], elements.offset)
    } else if(elements.shape.length !== 2) {
      throw new Error("Invalid shape for element array")
    } else if(elements.shape[1] === 1) {
      mode = gl.POINTS
    } else if(elements.shape[1] === 2) {
      mode = gl.LINES
    } else if(elements.shape[1] === 3) {
      mode = gl.TRIANGLES
    } else {
      throw new Error("Invalid shape for elment array")
    }
    //Special case for empty meshes
    if(elements.shape[0] === 0) {
      return buildMeshObject(gl, mode, 0, null, [])
    }
  } else {
    throw new Error("Invalid data type for element array")
  }

  //Next figure out how many vertices we are using
  var attr_names = Object.keys(attributes)
  if(attr_names.length < 1) {
    throw new Error("Invalid number of vertex attributes")
  }
  var numVertices, attr0 = attributes[attr_names[0]]
  if(attr0.length) {
    numVertices = attr0.length
  } else if(attr0.shape) {
    numVertices = attr0.shape[0]
  } else {
    throw new Error("Invalid vertex attribute: " + attr_names[0])
  }

  //We now have three basic cases:
  if(elements === undefined) {
    //First special case is a point cloud: this is easy
    return buildMeshObject(gl, gl.POINTS, numVertices, null, packAttributes(gl, numVertices, attributes))

  } else if((numVertices <= 1<<16) && mode !== gl.POINTS) {
    //Indices fit in 16-bit unsigned int, so we can use gl.drawElements

    //First thing is to repackage element buffer
    var element_buffer, element_count
    if(elements instanceof Array) {
    //    1a. elements is array    => coerce to ndarray
      if(typeof elements[0] === "number") {
        //Special case: point cloud
        element_count = elements.length|0
        var point_buf = pool.mallocUint16(element_count)
        for(var i=0; i<element_count; ++i) {
          point_buf[i] = elements[i]
        }
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, point_buf.subarray(0, element_count))
        pool.freeUint16(point_buf)
      } else {
        //Otherwise we pack data into a uint16 array
        var n = elements.length|0
        var d = elements[0].length|0
        var ptr = 0
        element_count = (n*d)|0
        var packed_buf = pool.mallocUint16(element_count)
        for(var i=0; i<n; ++i) {
          var prim = elements[i]
          for(var j=0; j<d; ++j) {
            packed_buf[ptr++] = prim[j]
          }
        }
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, packed_buf.subarray(0, element_count))
        pool.freeUint16(packed_buf)
      }
    } else {
      element_count = elements.shape[0] * elements.shape[1]
    //    1b. elements is ndarray  => check packing:
      if(elements.stride[1] === 1 &&
         elements.stride[0] === elements.shape[1] &&
         elements.data instanceof Uint16Array) {
      //        1b.1  array is packed   => use directly
        if(elements.offset === 0 &&
           elements.data.length === element_count) {
          element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, elements.data)
        } else {
          element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, elements.data.subarray(elements.offset, elements.offset + element_count))
        }
      } else {
      //        1b.2  array not packed  => copy to packed array
        var packed_buf = pool.mallocUint16(element_count)
        var packed_view = ndarray(packed_buf, elements.shape)
        ops.assign(packed_view, elements)
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, packed_buf.subarray(0, element_count))
        pool.freeUint16(packed_buf)
      }
    }

    //Finally we are done
    return buildMeshObject(gl, mode, element_count, element_buffer, packAttributes(gl, numVertices, attributes))

  } else {
    //Otherwise we have to use gl.drawArrays, and so the mesh needs to be repacked
    if(elements instanceof Array) {
      if(typeof elements[0] === "number") {
        return buildMeshObject(gl, mode, elements.length, null, packAttributesFrom1DArray(gl, numVertices, attributes, elements))
      } else {
        return buildMeshObject(gl, mode, elements.length * elements[0].length, null, packAttributesFromArray(gl, numVertices, attributes, elements))
      }
    } else {
      return buildMeshObject(gl, mode, elements.shape[0] * elements.shape[1], null, packAttributesFromNDArray(gl, numVertices, attributes, elements))
    }
  }
  throw new Error("Error building mesh object")
}

module.exports = createMesh<commit_msg>adding support for meshes with > 2^16 vertices<commit_after>"use strict"

var webglew = require("webglew")
var createBuffer = require("gl-buffer")
var createVAO = require("gl-vao")
var ndarray = require("ndarray")
var ops = require("ndarray-ops")
var pool = require("typedarray-pool")

var Mesh = require("./lib/mesh.js")

function EmptyMesh(gl) {
  this.gl = gl
  this.mode = gl.POINTS
  this.numElements = 0
  this.elements = null
  this.attributes = {}
}
EmptyMesh.prototype.dispose = function() {}
EmptyMesh.prototype.bind = function() {}
EmptyMesh.prototype.unbind = function() {}
EmptyMesh.prototype.draw = function() {}

function MeshAttribute(buffer, size, type, normalized) {
  this.buffer = buffer
  this.size = size
  this.type = type
  this.normalized = normalized
}

function getGLType(gl, array) {
  if((array instanceof Uint8Array) ||
     (array instanceof Uint8ClampedArray)) {
    return gl.UNSIGNED_BYTE
  } else if(array instanceof Int8Array) {
    return gl.BYTE
  } else if(array instanceof Uint16Array) {
    return gl.UNSIGNED_SHORT
  } else if(array instanceof Int16Array) {
    return gl.SHORT
  } else if(array instanceof Uint32Array) {
    return gl.UNSIGNED_INT
  } else if(array instanceof Int32Array) {
    return gl.INT
  } else if(array instanceof Float32Array) {
    return gl.FLOAT
  }
  return 0
}

function createTmpArray(gl, type, n) {
  if(type === gl.UNSIGNED_BYTE) {
    return pool.mallocUint8(n)
  } else if(type === gl.BYTE) {
    return pool.mallocInt8(n)
  } else if(type === gl.UNSIGNED_SHORT) {
    return pool.mallocUint16(n)
  } else if(type === gl.SHORT) {
    return pool.mallocInt16(n)
  } else if(type === gl.UNSIGNED_INT) {
    return pool.mallocUint32(n)
  } else if(type === gl.INT) {
    return pool.mallocInt32(n)
  }
  return pool.mallocFloat32(n)
}

function packAttributes(gl, numVertices, attributes) {
  var attrNames = []
  var attrVals = []
  for(var name in attributes) {
    var attr = attributes[name]
    var buffer, type, normalized, size
    if(typeof attr.length === "number") {
      if(attr.length !== numVertices) {
        throw new Error("Incorrect vertex count for attribute " + name)
      }
      if(typeof attr[0] === "number") {
        var gltype = getGLType(attr)
        if(gltype) {
          //Case: typed array
          size = 1
          type = gltype
          normalized = (gltype === gl.BYTE || gltype === gl.UNSIGNED_BYTE)
          buffer = createBuffer(gl, attr)
        } else {
          //Case: native array of numbers
          var tmp_buf = pool.mallocFloat32(numVertices)
          for(var i=0; i<numVertices; ++i) {
            tmp_buf[i] = attr[i]
          }
          size = 1
          type = gl.FLOAT
          normalized = false
          buffer = createBuffer(gl, tmp_buf.subarray(0, numVertices))
          pool.freeUint32(tmp_buf)
        }
      } else if(attr[0].length) {
        //Case: native array of arrays
        size = attr[0].length|0
        var ptr = 0
        var tmp_buf = pool.mallocFloat32(size * numVertices)
        for(var i=0; i<numVertices; ++i) {
          var vert = attr[i]
          for(var j=0; j<size; ++j) {
            tmp_buf[ptr++] = vert[j]
          }
        }
        type = gl.FLOAT
        normalized = false
        buffer = createBuffer(gl, tmp_buf.subarray(0, ptr))
        pool.freeFloat32(tmp_buf)
      }
    } else if(attr.shape) {
      if(attr.shape[0] !== numVertices) {
        throw new Error("Invalid shape for attribute " + name)
      }
      //Convert 1D array to 2D
      if(attr.shape.length === 1) {
        attr = ndarray(attr.data, [attr.shape[0], 1], [attr.stride[0], 1], attr.offset)
      }
      //Check if type is compatible
      var packed = true
      type = getGLType(gl, attr.data)
      if(!type) {
        packed = false
        type = gl.FLOAT
      }
      if(stride[0] !== 1 || (shape[1] > 1 && stride[1] !== 1)) {
        packed = false
      }
      //Check if array has to be normalized
      normalized = (type === gl.BYTE || type === gl.UNSIGNED_BYTE)
      size = attr.shape[1]
      if(packed) {
        //Case: packed ndarray, directly blit into buffer
        if(attr.offset === 0 && attr.data.length === size*numVertices) {
          buffer = createBuffer(gl, attr.data)
        } else {
          buffer = createBuffer(gl, attr.data.subarray(0, size*numVertices))
        }
      } else {
        //Case: unpacked ndarray, create new array and blit
        var tmp_buf = createTmpArray(gl, type, size*numVertices)
        var tmp = ndarray(tmp_buf, attr.shape)
        ops.assign(tmp, attr)
        buffer = createBuffer(gl, tmp.data.subarray(0, size*numVertices))
        pool.free(tmp_buf)
      }
    } else {
      throw new Error("Invalid vertex attribute " + name)
    }
    attrNames.push(name)
    attrVals.push(new MeshAttribute(buffer, size, type, normalized))
  }
  return {
    names: attrNames,
    values: attrVals
  }
}

function packAttributesFromNDArray(gl, numVertices, attributes, elements) {
  var n = elements.shape[0]|0
  var d = elements.shape[1]|0
  var numElements = (n*d)|0
  var attrNames, attrVals
  for(var name in attributes) {
    var attr = attributes[name]
    var type, size, normalized, buffer
    if(typeof attr.length === "number") {
      if(attr[0].length !== numVertices) {
        throw new Error("Invalid attribute size for attribute " + name)
      }
      if(typeof attr[0] === "number") {
        //Case: 1D array attribute
        size = 1
        type = getGLType(gl, attr)
        var pack_buf
        if(!type) {
          type = gl.FLOAT
        }
        normalized = (type === gl.BYTE || gl.UNSIGNED_BYTE)
        pack_buf = createTmpArray(gl, type, numElements)
        var ptr = 0
        for(var i=0; i<n; ++i) {
          for(var j=0; j<d; ++j) {
            pack_buf[ptr++] = attr[elements.get(i,j)]
          }
        }
        buffer = createBuffer(gl, pack_buf.subarray(0, ptr))
        pool.free(pack_buf)
      } else {
        //Case: Array-of-arrays attribute
        size = attr[0].length|0
        if(size < 1 || size > 4) {
          throw new Error("Invalid attribute size for attribute " + name)
        }
        type = gl.FLOAT
        normalized = false
        var pack_buf = pool.mallocFloat32(numElements * size)
        var ptr = 0
        for(var i=0; i<n; ++i) {
          for(var j=0; j<d; ++j) {
            var vert = attr[elements.get(i,j)]
            for(var k=0; k<size; ++k) {
              pack_buf[ptr++] = vert[k]
            }
          }
        }
        buffer = createBuffer(gl, pack_buf.subarray(0, numElements*size))
        pool.freeFloat32(pack_buf)
      }
    } else if(attr.shape) {
      //Case: ndarray attribute
      if(attr.shape[0] !== numVertices) {
        throw new Error("Invalid number of vertices for attribute " + name)
      }
      if(attr.shape.length === 1) {
        //Case: 1D ndarray
        size = 1
        type = getGLType(gl, array.data)
        if(!type) {
          type = gl.FLOAT
        }
        normalized = (type === gl.BYTE || type === gl.UNSIGNED_BYTE)
        var pack_buf = createTmpArray(gl, type, numElements)
        var ptr = 0
        for(var i=0; i<n; ++i) {
          for(var j=0; j<d; ++j) {
            pack_buf[ptr++] = attr.get(elements.get(i,j))
          }
        }
        buffer = createBuffer(gl, pack_buf.subarray(0, ptr))
        pool.free(pack_buf)
      } else if(attr.shape.length === 2) {
        //Case: 2D ndarray
        size = attr.shape[1]|0
        if(size < 1 || size > 4) {
          throw new Error("Invalid attribute size for attribute " + name)
        }
        type = getGLType(gl, array.data)
        if(!type) {
          type = gl.FLOAT
        }
        normalized = (type === gl.BYTE || gl.UNSIGNED_BYTE)
        var pack_buf = createTmpArray(gl, type, numElements * size)
        var ptr = 0
        for(var i=0; i<n; ++i) {
          for(var j=0; j<d; ++j) {
            var vert_num = elements.get(i,j)
            for(var k=0; k<size; ++k) {
              pack_buf[ptr++] = attr.get(vert_num, k)
            }
          }
        }
        buffer = createBuffer(gl, pack_buf.subarray(0, ptr))
        pool.free(pack_buf)
      } else {
        throw new Error("Invalid attribute " + name + ", shape is too big")
      }
    } else {
      throw new Error("Invalid attribute " + name + ", unrecognized type")
    }
    attrNames.push(name)
    attrVals.push(new MeshAttribute(buffer, size, type, normalized))
  }
  return {
    names: attrNames,
    values: attrVals
  }
}

function packAttributesFrom1DArray(gl, numVertices, attributes, elements) {
  var n = elements.length|0
  var buf = pool.mallocUint32(n)
  for(var i=0; i<n; ++i) {
    buf[i] = elements[i]
  }
  var result = packAttributesFromNDArray(gl, numVertices, attributes, ndarray(buf, [n, 1]))
  pool.freeUint32(buf)
  return result
}

function packAttributesFromArray(gl, numVertices, attributes, elements) {
  var n = elements.length|0
  var d = elements[0].length|0
  var ptr = 0
  var buf = pool.mallocUint32(n*d)
  for(var i=0; i<n; ++i) {
    var list = elements[i]
    for(var j=0; j<d; ++j) {
      buf[ptr++] = list[j]
    }
  }
  var result = packAttributesFromNDArray(gl, numVertices, attributes, ndarray(buf, [n, d]))
  pool.freeUint32(buf)
  return result
}

//Builds the actual mesh object, selecting appropriate implementation depending on if vertex attribute objects are supported
function buildMeshObject(gl, mode, numElements, elements, attributes) {
  if(numElements === 0) {
    return new EmptyMesh(gl)
  }
  var vao = createVAO(gl, elements, attributes.values)
  return new Mesh(gl, mode, numElements, vao, elements, attributes.values, attributes.names)
}

//Creates a mesh
function createMesh(gl, elements, attributes) {

  //Special case: handle object with cells/positions/etc. for attributes
  if(arguments.length === 2) {
    if(elements.cells) {
      attributes = {}
      for(var id in elements) {
        if(id === "cells") {
          continue
        }
        attributes[id] = elements[id]
      }
      elements = elements.cells
    }
  }

  //First figure out what mode we are using (POINTS, LINES or TRIANGLES)
  var mode
  if(attributes === undefined) {
    //Special case for point clouds
    attributes = elements
    elements = undefined
    mode = gl.POINTS
  } else if(elements instanceof Array) {
    if(elements.length === 0) {
      //Empty array, return empty mesh
      return buildMeshObject(gl, gl.POINTS, 0, null, [])
    } else if(typeof elements[0] === "number" || elements[0].length === 1) {
      mode = gl.POINTS
    } else if(elements[0].length === 2) {
      mode = gl.LINES
    } else if(elements[0].length === 3) {
      mode = gl.TRIANGLES
    } else {
      throw new Error("Invalid shape for element array")
    }
  } else if(elements.shape) {
    if(elements.shape.length === 1) {
      mode = gl.POINTS
      //Special case: convert to 2d element array for point cloud automatically to simplify things later on
      elements = ndarray(elements.data, [elements.shape[0], 1], [elements.stride[0], 1], elements.offset)
    } else if(elements.shape.length !== 2) {
      throw new Error("Invalid shape for element array")
    } else if(elements.shape[1] === 1) {
      mode = gl.POINTS
    } else if(elements.shape[1] === 2) {
      mode = gl.LINES
    } else if(elements.shape[1] === 3) {
      mode = gl.TRIANGLES
    } else {
      throw new Error("Invalid shape for elment array")
    }
    //Special case for empty meshes
    if(elements.shape[0] === 0) {
      return buildMeshObject(gl, mode, 0, null, [])
    }
  } else {
    throw new Error("Invalid data type for element array")
  }

  //Next figure out how many vertices we are using
  var attr_names = Object.keys(attributes)
  if(attr_names.length < 1) {
    throw new Error("Invalid number of vertex attributes")
  }
  var numVertices, attr0 = attributes[attr_names[0]]
  if(attr0.length) {
    numVertices = attr0.length
  } else if(attr0.shape) {
    numVertices = attr0.shape[0]
  } else {
    throw new Error("Invalid vertex attribute: " + attr_names[0])
  }

  //We now have three basic cases:
  if(elements === undefined) {
    //First special case is a point cloud: this is easy
    return buildMeshObject(gl, gl.POINTS, numVertices, null, packAttributes(gl, numVertices, attributes))

  } else if((numVertices <= 1<<16) && mode !== gl.POINTS) {
    //Indices fit in 16-bit unsigned int, so we can use gl.drawElements

    //First thing is to repackage element buffer
    var element_buffer, element_count
    if(elements instanceof Array) {
    //    1a. elements is array    => coerce to ndarray
      if(typeof elements[0] === "number") {
        //Special case: point cloud
        element_count = elements.length|0
        var point_buf = pool.mallocUint16(element_count)
        for(var i=0; i<element_count; ++i) {
          point_buf[i] = elements[i]
        }
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, point_buf.subarray(0, element_count))
        pool.freeUint16(point_buf)
      } else {
        //Otherwise we pack data into a uint16 array
        var n = elements.length|0
        var d = elements[0].length|0
        var ptr = 0
        element_count = (n*d)|0
        var packed_buf = pool.mallocUint16(element_count)
        for(var i=0; i<n; ++i) {
          var prim = elements[i]
          for(var j=0; j<d; ++j) {
            packed_buf[ptr++] = prim[j]
          }
        }
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, packed_buf.subarray(0, element_count))
        pool.freeUint16(packed_buf)
      }
    } else {
      element_count = elements.shape[0] * elements.shape[1]
    //    1b. elements is ndarray  => check packing:
      if(elements.stride[1] === 1 &&
         elements.stride[0] === elements.shape[1] &&
         elements.data instanceof Uint16Array) {
      //        1b.1  array is packed   => use directly
        if(elements.offset === 0 &&
           elements.data.length === element_count) {
          element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, elements.data)
        } else {
          element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, elements.data.subarray(elements.offset, elements.offset + element_count))
        }
      } else {
      //        1b.2  array not packed  => copy to packed array
        var packed_buf = pool.mallocUint16(element_count)
        var packed_view = ndarray(packed_buf, elements.shape)
        ops.assign(packed_view, elements)
        element_buffer = createBuffer(gl, gl.ELEMENT_ARRAY_BUFFER, packed_buf.subarray(0, element_count))
        pool.freeUint16(packed_buf)
      }
    }

    //Finally we are done
    return buildMeshObject(gl, mode, element_count, element_buffer, packAttributes(gl, numVertices, attributes))

  } else {
    //Otherwise we have to use gl.drawArrays, and so the mesh needs to be repacked
    if(elements instanceof Array) {
      if(typeof elements[0] === "number") {
        return buildMeshObject(gl, mode, elements.length, null, packAttributesFrom1DArray(gl, numVertices, attributes, elements))
      } else {
        return buildMeshObject(gl, mode, elements.length * elements[0].length, null, packAttributesFromArray(gl, numVertices, attributes, elements))
      }
    } else {
      return buildMeshObject(gl, mode, elements.shape[0] * elements.shape[1], null, packAttributesFromNDArray(gl, numVertices, attributes, elements))
    }
  }
  throw new Error("Error building mesh object")
}

module.exports = createMesh<|endoftext|>


<commit_before>/**
 * Отправляет ajax-запросы и обрабатывает результаты.
 *
 * Добавляет события:
 * form-submit		— срабатывает перед отправкой данных формы
 */
$.ajaxSetup( {
	async : false,
	cache :	false,
	headers : {
		'X-Requested-With' : 'XMLHttpRequest'
	}
} );

var ajaxer = {};
ajaxer.id = 1;

ajaxer.httpRequest = function( url, params, headers ) {

	var data = {};
	if( typeof params == 'undefined' || !params ) {
		data.type = 'GET';
	} else {
		data.type = 'POST';
		data.data = 'json=' + encodeURIComponent( JSON.stringify( params ) );
	}
	if( typeof headers != 'undefined' ) {
		data.headers = headers;
	}
	return $.ajax( url, data ).responseText;
};

ajaxer.sendForm = function( form, event ) {

	var data = {
		form: $( form ).serializeArray()
	};
	//var data = $( event.target ).serialize();
	$( form ).find( '.required' ).fadeOut( 'fast' );
	$( form ).find( '.invalid' ).fadeOut( 'fast' );
	$( form ).find( '.status' ).fadeOut( 'fast' );
	$( form ).find( '.problem' ).removeClass( 'problem' );
	ajaxer.process( this.httpRequest( $( form ).attr( 'action' ), data ), form );
};

ajaxer.query = function( url, data ) {

	ajaxer.process( this.httpRequest( url, data ) );
};

ajaxer.process = function( data, form ) {

	try {
		console.info( 'Server said: ' + data );
		var data1 = $.parseJSON( data );
		if( !data1.actions ) {
			throw "data error";
		}
		this.clean( form );
		for( var key in data1.actions ) {
			var action = data1.actions[key];
			switch( action.action ) {
			case 'notify':	// сообщение
				this.notify( action.lang, action.message );
				break;
			case 'require':// не заполнено обязательное поле формы
				this.require( form, action.name );
				break;
			case 'invalid':	// не правильное значение поля формы
				this.invalid( form, action.name, action.message );
				break;
			case 'status': // текстовый статус для поля
				this.status( form, action.name, action.message, action.classname );
				break;
			case 'redirect':// перенаправление
				this.redirect( action.url );
				break;
			case 'display':	// показать окно с пришедшим html
				this.display( action.html );
				break;
			case 'reload': // перезагрузить страницу
				this.reload();
				break;
			case 'close':
				this.close( form );
				break;
			case 'error':	// сообщение об ошибке
				this.error( action.lang, action.message );
				break;
			case 'reset':	// сделать форме reset
				this.reset( form );
				break;
			default:
				console.warn( 'Ajaxer action "' + action.action + '" not implemented' );
			}
		}
	} catch( ex ) {
		this.notify( {close:'OK'}, 'Unknown error.' );
		console.warn( 'Server returned:', data );
	}
};

ajaxer.clean = function( form ) {

	$( form ).find( '.problem' ).removeClass( 'problem' );
};

ajaxer.notify = function( lang, message ) {

	$( 'body' ).append(
		'
' +
			'
' +
			'
' +
			'

' +
			'
' + message + '
' +
			'' + ( lang.close ? lang.close : 'OK' ) + '' +
			'
' +
			'
' +
			'
'
	);
	$( '#ajaxer-' + ajaxer.id ).find( '.overlay-inner' ).fadeIn( 'fast' );
	$( window ).resize();
	ajaxer.id++;
};

ajaxer.error = function( lang, message ) {

	ajaxer.notify( lang, message );
};

ajaxer.require = function( form, name ) {

	var el = $( form ).find( '[name=' + name + ']' );
	if( !el.length || el.attr( 'type' ) == 'hidden' ) {
		ajaxer.error( {}, 'Field "' + name + '" is required.' );
		return;
	}
	var container = el.closest( '.container' );
	if( !container.length ) {
		var cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			el.addClass( 'problem' );
		}
		return;
	}
	var req = container.find( '.required' );
	if( !req.length ) {
		cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			container.addClass( 'problem' );
		}
		return;
	}
	req.fadeIn();
};

ajaxer.invalid = function( form, name, message ) {

	var el = $( form ).find( '[name=' + name + ']' );
	if( !el.length || el.attr( 'type' ) == 'hidden' ) {
		ajaxer.error( {}, 'Invalid value for field "' + name + '".' );
		return;
	}
	var container = el.closest( '.container' );
	if( !container.length ) {
		var cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			el.addClass( 'problem' );
		}
		return;
	}
	var req = container.find( '.invalid' );
	if( !req.length ) {
		cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			container.addClass( 'problem' );
		}
		return;
	}
	if( message ) {
		req.find( '.invalid-text' ).html( message );
	}
	req.fadeIn( 'fast' );
};

ajaxer.status = function( form, name, message, classname ) {

	var status = $( form ).find( '[name=' + name + ']' ).parents( '.container' ).find( '.status' );
	if( status ) {
		status.fadeIn( 'fast' );
		status.attr( 'class', 'status ' + classname );
		status.html( message );
	}
};

ajaxer.redirect = function( url ) {

	if( typeof(switcher) != 'undefined' ) {
		switcher.page( url );
	} else {
		document.location( url );
	}
};

ajaxer.reload = function() {

	window.location.reload();
};

ajaxer.display = function( html ) {

	$( 'body' ).append(
		'
' +
			'
' +
			'
' +
			'

' +
			html +
			'
' +
			'
' +
			'
'
	);
	$( '#ajaxer-' + ajaxer.id ).find( '.overlay-inner' ).fadeIn( 'fast' );
	$( window ).resize();
	ajaxer.id++;
};

ajaxer.close = function( obj ) {

	var el = $( obj ).parents( '.overlay' );
	el.fadeOut( 'fast', function() {
		$( this ).remove();
	} );
};

ajaxer.reset = function( form ) {

	$( form ).get( 0 ).reset();
};

var main = {};
main.httpRequest = ajaxer.httpRequest;

$( document ).delegate( 'form.ajaxer', 'submit', function( event ) {

	var form = $( this );
	var files = form.find( 'input[type=file]' );
	$( document ).triggerHandler( 'form-submit' );
	if( !files.length ) {
		// serialize method
		event.preventDefault();
		ajaxer.sendForm( this, event );
	} else {
		// iframe method
		if( !$( '#ajaxerFrame' ).length ) {
			var frame = $( '' );
			var uuid = '';
			for( var i = 0; i < 32; i++ ) {
				uuid += Math.floor( Math.random() * 16 ).toString( 16 );
			}
			var originalAction = form.attr( 'action' );
			form.attr( 'action', form.attr( 'action' ) + ( originalAction.indexOf( '?' ) == -1 ? '?' : '&' ) + 'X-Progress-ID=' + uuid );
			$( 'body' ).append( frame );
			form.attr( 'target', 'ajaxerFrame' );
			form.append( '<input type="hidden" name="_method" value="iframe"/>' );
			var loading = $( '#loading' );
			if( !loading.length ) {
				$( 'body' ).append( loading = $( '

' ) );
			}
			loading.fadeIn();
			var interval = window.setInterval(
				function() {
					ajaxer.fetchProgress( uuid );
				},
				1000
			);
			frame.load( function() {
				var rawframe = frame.get(0);
				if( rawframe.contentDocument ) {
					var val = rawframe.contentDocument.body.innerHTML;
				} else if( rawframe.contentWindow ) {
					val = rawframe.contentWindow.document.body.innerHTML;
				} else if( rawframe.document ) {
					val = rawframe.document.body.innerHTML;
				}
				form.attr( 'action', originalAction );
				form.find( 'input[name=_method]' ).remove();
				$( 'iframe#ajaxerFrame' ).remove();
				loading.fadeOut( 'fast', function() {
					loading.find( '#upprog' ).remove();
					window.clearTimeout( interval );
				} );
				ajaxer.process( val, form );
			} );
		}
	}
} );

ajaxer.fetchProgress = function( uuid ) {

	var res = ajaxer.httpRequest( '/progress', null, { 'X-Progress-ID': uuid } );
	res = $.parseJSON( res ); // new Object({ 'state' : 'uploading', 'received' : 3486881, 'size' : 6971123 })
	if( res.state == 'uploading' ) {
		var progressbar = $( '#upprog' );
		if( !progressbar.length ) {
			$( '#loading' )
				.css( 'background-image', 'none' )
				.append( '

' );
			autocenter();
			progressbar = $( '#upprog' );
		}
		progressbar.find( '.td1' )
			.css( 'width', Math.ceil( ( progressbar.width() - 20 ) * res.received / res.size ) + 'px' );
	} else if( res.state == 'done' ) {
		progressbar.find( 'td1' )
			.css( 'width', Math.ceil( progressbar.width() - 20 ) + 'px' );
	}
};

$( 'a.ajaxer' ).live( 'click dblclick', function( e ) {
	ajaxer.query( $( this ).attr( 'href' ) );
	e.preventDefault();
} );

$( '.ajaxer input' ).live( 'keypress', function( e ) {
	if( e.which == 13 ) {
		$( this ).parents( 'form' ).submit();
		e.preventDefault();
	}
} );

$( '.submit' ).live( 'click dblclick', function( e ) {
	$( this ).parents( 'form' ).submit();
	e.preventDefault();
});

$( '.reset' ).live( 'click dblclick', function( e ) {
	ajaxer.reset( $( this ).parents( 'form' ) );
	e.preventDefault();
} );

ajaxer.watcher = function() {

	var mc = $.cookie( 'query' );
	if( mc ) {
		mc = $.parseJSON( mc );
		ajaxer.query( mc.url );
		$.cookie( 'query', null, { path: "/", domain: config.mainhost ? '.' + config.mainhost : false } );
	}
	mc = $.cookie( 'notify' );
	if( mc ) {
		mc = $.parseJSON( mc );
		if( mc.type == 'error' ) {
			ajaxer.error( mc.lang, mc.message );
		} else {
			ajaxer.notify( mc.lang, mc.message );
		}
		$.cookie( 'notify', null, { path: "/", domain: config.mainhost ? '.' + config.mainhost : false } );
	}
};

$( document ).ready( ajaxer.watcher );
$( document ).bind( 'construct', ajaxer.watcher );<commit_msg>Исправлен race condition в js-коде upload progress bar'а.<commit_after>/**
 * Отправляет ajax-запросы и обрабатывает результаты.
 *
 * Добавляет события:
 * form-submit		— срабатывает перед отправкой данных формы
 */
$.ajaxSetup( {
	async : false,
	cache :	false,
	headers : {
		'X-Requested-With' : 'XMLHttpRequest'
	}
} );

var ajaxer = {};
ajaxer.id = 1;

ajaxer.httpRequest = function( url, params, headers ) {

	var data = {};
	if( typeof params == 'undefined' || !params ) {
		data.type = 'GET';
	} else {
		data.type = 'POST';
		data.data = 'json=' + encodeURIComponent( JSON.stringify( params ) );
	}
	if( typeof headers != 'undefined' ) {
		data.headers = headers;
	}
	return $.ajax( url, data ).responseText;
};

ajaxer.sendForm = function( form, event ) {

	var data = {
		form: $( form ).serializeArray()
	};
	//var data = $( event.target ).serialize();
	$( form ).find( '.required' ).fadeOut( 'fast' );
	$( form ).find( '.invalid' ).fadeOut( 'fast' );
	$( form ).find( '.status' ).fadeOut( 'fast' );
	$( form ).find( '.problem' ).removeClass( 'problem' );
	ajaxer.process( this.httpRequest( $( form ).attr( 'action' ), data ), form );
};

ajaxer.query = function( url, data ) {

	ajaxer.process( this.httpRequest( url, data ) );
};

ajaxer.process = function( data, form ) {

	try {
		console.info( 'Server said: ' + data );
		var data1 = $.parseJSON( data );
		if( !data1.actions ) {
			throw "data error";
		}
		this.clean( form );
		for( var key in data1.actions ) {
			var action = data1.actions[key];
			switch( action.action ) {
			case 'notify':	// сообщение
				this.notify( action.lang, action.message );
				break;
			case 'require':// не заполнено обязательное поле формы
				this.require( form, action.name );
				break;
			case 'invalid':	// не правильное значение поля формы
				this.invalid( form, action.name, action.message );
				break;
			case 'status': // текстовый статус для поля
				this.status( form, action.name, action.message, action.classname );
				break;
			case 'redirect':// перенаправление
				this.redirect( action.url );
				break;
			case 'display':	// показать окно с пришедшим html
				this.display( action.html );
				break;
			case 'reload': // перезагрузить страницу
				this.reload();
				break;
			case 'close':
				this.close( form );
				break;
			case 'error':	// сообщение об ошибке
				this.error( action.lang, action.message );
				break;
			case 'reset':	// сделать форме reset
				this.reset( form );
				break;
			default:
				console.warn( 'Ajaxer action "' + action.action + '" not implemented' );
			}
		}
	} catch( ex ) {
		this.notify( {close:'OK'}, 'Unknown error.' );
		console.warn( 'Server returned:', data );
	}
};

ajaxer.clean = function( form ) {

	$( form ).find( '.problem' ).removeClass( 'problem' );
};

ajaxer.notify = function( lang, message ) {

	$( 'body' ).append(
		'
' +
			'
' +
			'
' +
			'

' +
			'
' + message + '
' +
			'' + ( lang.close ? lang.close : 'OK' ) + '' +
			'
' +
			'
' +
			'
'
	);
	$( '#ajaxer-' + ajaxer.id ).find( '.overlay-inner' ).fadeIn( 'fast' );
	$( window ).resize();
	ajaxer.id++;
};

ajaxer.error = function( lang, message ) {

	ajaxer.notify( lang, message );
};

ajaxer.require = function( form, name ) {

	var el = $( form ).find( '[name=' + name + ']' );
	if( !el.length || el.attr( 'type' ) == 'hidden' ) {
		ajaxer.error( {}, 'Field "' + name + '" is required.' );
		return;
	}
	var container = el.closest( '.container' );
	if( !container.length ) {
		var cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			el.addClass( 'problem' );
		}
		return;
	}
	var req = container.find( '.required' );
	if( !req.length ) {
		cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			container.addClass( 'problem' );
		}
		return;
	}
	req.fadeIn();
};

ajaxer.invalid = function( form, name, message ) {

	var el = $( form ).find( '[name=' + name + ']' );
	if( !el.length || el.attr( 'type' ) == 'hidden' ) {
		ajaxer.error( {}, 'Invalid value for field "' + name + '".' );
		return;
	}
	var container = el.closest( '.container' );
	if( !container.length ) {
		var cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			el.addClass( 'problem' );
		}
		return;
	}
	var req = container.find( '.invalid' );
	if( !req.length ) {
		cke = $( form ).find( '#cke_' + name );
		if( cke.length ) {
			cke.addClass( 'problem' );
		} else {
			container.addClass( 'problem' );
		}
		return;
	}
	if( message ) {
		req.find( '.invalid-text' ).html( message );
	}
	req.fadeIn( 'fast' );
};

ajaxer.status = function( form, name, message, classname ) {

	var status = $( form ).find( '[name=' + name + ']' ).parents( '.container' ).find( '.status' );
	if( status ) {
		status.fadeIn( 'fast' );
		status.attr( 'class', 'status ' + classname );
		status.html( message );
	}
};

ajaxer.redirect = function( url ) {

	if( typeof(switcher) != 'undefined' ) {
		switcher.page( url );
	} else {
		document.location( url );
	}
};

ajaxer.reload = function() {

	window.location.reload();
};

ajaxer.display = function( html ) {

	$( 'body' ).append(
		'
' +
			'
' +
			'
' +
			'

' +
			html +
			'
' +
			'
' +
			'
'
	);
	$( '#ajaxer-' + ajaxer.id ).find( '.overlay-inner' ).fadeIn( 'fast' );
	$( window ).resize();
	ajaxer.id++;
};

ajaxer.close = function( obj ) {

	var el = $( obj ).parents( '.overlay' );
	el.fadeOut( 'fast', function() {
		$( this ).remove();
	} );
};

ajaxer.reset = function( form ) {

	$( form ).get( 0 ).reset();
};

var main = {};
main.httpRequest = ajaxer.httpRequest;

$( document ).delegate( 'form.ajaxer', 'submit', function( event ) {

	var form = $( this );
	var files = form.find( 'input[type=file]' );
	$( document ).triggerHandler( 'form-submit' );
	if( !files.length ) {
		// serialize method
		event.preventDefault();
		ajaxer.sendForm( this, event );
	} else {
		// iframe method
		if( !$( '#ajaxerFrame' ).length ) {
			var frame = $( '' );
			var uuid = '';
			for( var i = 0; i < 32; i++ ) {
				uuid += Math.floor( Math.random() * 16 ).toString( 16 );
			}
			var originalAction = form.attr( 'action' );
			form.attr( 'action', form.attr( 'action' ) + ( originalAction.indexOf( '?' ) == -1 ? '?' : '&' ) + 'X-Progress-ID=' + uuid );
			$( 'body' ).append( frame );
			form.attr( 'target', 'ajaxerFrame' );
			form.append( '<input type="hidden" name="_method" value="iframe"/>' );
			var loading = $( '#loading' );
			if( !loading.length ) {
				$( 'body' ).append( loading = $( '

' ) );
			}
			loading.fadeIn();
			var interval = window.setInterval(
				function() {
					ajaxer.fetchProgress( uuid );
				},
				1000
			);
			frame.load( function() {
				var rawframe = frame.get(0);
				if( rawframe.contentDocument ) {
					var val = rawframe.contentDocument.body.innerHTML;
				} else if( rawframe.contentWindow ) {
					val = rawframe.contentWindow.document.body.innerHTML;
				} else if( rawframe.document ) {
					val = rawframe.document.body.innerHTML;
				}
				form.attr( 'action', originalAction );
				form.find( 'input[name=_method]' ).remove();
				$( 'iframe#ajaxerFrame' ).remove();
				loading.find( 'td1' ).css( 'width', Math.ceil( $( '#upprog' ).width() - 20 ) + 'px' );
				loading.fadeOut( 'slow', function() {
					window.clearTimeout( interval );
					loading.find( '#upprog' ).remove();
				} );
				ajaxer.process( val, form );
			} );
		}
	}
} );

ajaxer.fetchProgress = function( uuid ) {

	var res = ajaxer.httpRequest( '/progress', null, { 'X-Progress-ID': uuid } );
	res = $.parseJSON( res );
	if( res.state == 'uploading' ) {
		var progressbar = $( '#upprog' );
		if( !progressbar.length ) {
			$( '#loading' )
				.css( 'background-image', 'none' )
				.append( '

' );
			autocenter();
			progressbar = $( '#upprog' );
		}
		progressbar.find( '.td1' )
			.css( 'width', Math.ceil( ( progressbar.width() - 20 ) * res.received / res.size ) + 'px' );
	}
};

$( 'a.ajaxer' ).live( 'click dblclick', function( e ) {
	ajaxer.query( $( this ).attr( 'href' ) );
	e.preventDefault();
} );

$( '.ajaxer input' ).live( 'keypress', function( e ) {
	if( e.which == 13 ) {
		$( this ).parents( 'form' ).submit();
		e.preventDefault();
	}
} );

$( '.submit' ).live( 'click dblclick', function( e ) {
	$( this ).parents( 'form' ).submit();
	e.preventDefault();
});

$( '.reset' ).live( 'click dblclick', function( e ) {
	ajaxer.reset( $( this ).parents( 'form' ) );
	e.preventDefault();
} );

ajaxer.watcher = function() {

	var mc = $.cookie( 'query' );
	if( mc ) {
		mc = $.parseJSON( mc );
		ajaxer.query( mc.url );
		$.cookie( 'query', null, { path: "/", domain: config.mainhost ? '.' + config.mainhost : false } );
	}
	mc = $.cookie( 'notify' );
	if( mc ) {
		mc = $.parseJSON( mc );
		if( mc.type == 'error' ) {
			ajaxer.error( mc.lang, mc.message );
		} else {
			ajaxer.notify( mc.lang, mc.message );
		}
		$.cookie( 'notify', null, { path: "/", domain: config.mainhost ? '.' + config.mainhost : false } );
	}
};

$( document ).ready( ajaxer.watcher );
$( document ).bind( 'construct', ajaxer.watcher );<|endoftext|>