<commit_before>
console.log("defining module");
angular.module('pepper-patrol', ['ngTouch'])
    .controller('map-display', function ($scope, $locale, $timeout, $http) {
        console.log("map-display controller");
        var memory = null;
        var exploManager = null;
        var intervalID = null;
        var mpp = null;
        var size = null;
        var offset = null;
        // step : 0 = list explo, 1 = reloc, 2 = patrol.
        var step = 0;
        var touch = null;

        $scope.addOnClick = function (event) {
            // event.offsetX and event.offsetY
            // compute
            var img = document.getElementById("map_container");
            var pxlX = event.offsetX - img.offsetLeft
            var pxlY = event.offsetY - img.offsetTop
            touch = [pxlX, pxlY];
            if (pxlX > 0 && pxlX < img.width && pxlY > 0 && pxlY < img.height) {
                console.log("click: " + event.offsetX + " " + event.offsetY);
                if (step == 1) {
                    memory.raiseEvent("Patrol/Relocalize", [pxlX, pxlY]);
                    document.getElementById("mode_configure").click();
                } else if (step == 2) {
                    memory.raiseEvent("Patrol/AddWayPoint", [[pxlX, pxlY], ""]);
                }
            }
        };

        $scope.OnModeChanged = function() {
            step = document.querySelector('input[name="mode"]:checked').value
            console.log("onchanged: " + step.toString());
        }

        $scope.OnGoClick = function (event) {
            console.log("go");
            memory.raiseEvent("Patrol/StartPatrol", [])
        }

        $scope.OnResetClick = function(event) {
            memory.raiseEvent("Patrol/Reset", [])
        }

        $scope.setMap = function (tab) {
            var mpp = tab[0];
            var size = tab[1];
            var offset = tab[2];
            var data = tab[3];
            var wrapper = document.getElementById("wrapper");
            wrapper.style = "position:relative; width:"+size+"px; height:"+size+"px;"
            var map_container = document.getElementById('map_container');
            map_container.width = size;
            map_container.height = size;
            angular.element(map_container).css({
            'background-image': 'url(' + data +')',
            'background-size' : 'cover'
            });
            var waypoint_canvas = document.getElementById("waypoints_canvas");
            waypoint_canvas.width = size;
            waypoint_canvas.height = size;
            var places_canvas = document.getElementById("places_canvas");
            places_canvas.width = size;
            places_canvas.height = size;
            step = 1;
            document.getElementById("waiting_ui").style.display = "none";
            document.getElementById("mode_ui").style.visibility = "visible";
            document.getElementById("waypoints_ui").style.visibility = "visible";
        };

        $scope.setRobot = function (tab) {
            console.log("setRobot");
            var centerX = tab[0][0];
            var centerY = tab[0][1];
            var radius = tab[1];
            var canvas = document.getElementById('map_container');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.beginPath();
            context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
            context.fillStyle="#ff0000";
            context.fill();
            context.beginPath();
            context.arc(tab[2][0], tab[2][1], 0.5 * radius, 0, 2 * Math.PI, false);
            context.fillStyle="#ff0000";
            context.fill();
        };

        $scope.setPlaces = function (tab) {
            var canvas = document.getElementById('places_canvas');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            for (i = 0; i < tab.length; ++i) {
                var centerX = tab[i][0][0];
                var centerY = tab[i][0][1];
                var label = tab[i][1];
                var radius = 5;
                context.beginPath();
                context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
                context.fillStyle="#00ff00";
                context.fill();
                context.font = "30px Arial";
                context.fillStyle = "#00ff00";
                context.fillText(label.toString(), centerX + 10, centerY);
            }

        };
        $scope.setWaypoints = function (tab) {
            var canvas = document.getElementById('waypoints_canvas');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.lineWidth = 1.5;
            context.strokeStyle = 'red';
            context.beginPath();
            for (i = 0; i < tab.length; ++i) {
                var centerX = tab[i][0];
                var centerY = tab[i][1];
                var label = i.toString();
                context.lineTo(centerX, centerY);
                context.stroke();
                var radius = 5;
                context.beginPath();
                context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
                context.fillStyle = "red";
                context.fill();
                context.font = "30px Arial";
                context.fillText(label, centerX + 10, centerY);
            }
        };

        $scope.OnExit = function() {
            memory.raiseEvent("Patrol/Exit", [])
        }

        $scope.OnStop = function() {
            memory.raiseEvent("Patrol/StopPatrol", [])
        }

        $scope.onPatrolStarted = function() {
            document.getElementById("patrol_ongoing_ui").style.display = "block";
            document.getElementById("waypoints_ui").style.visibility = "hidden";
            document.getElementById("mode_ui").style.visibility = "hidden";
            document.getElementById("exit_button").style.display = "none";
            document.getElementById("stop_button").style.display = "block";
        }

        $scope.onPatrolFinished = function() {
            document.getElementById("patrol_ongoing_ui").style.display = "none";
            document.getElementById("waypoints_ui").style.visibility = "visible";
            document.getElementById("mode_ui").style.visibility = "visible";
            document.getElementById("exit_button").style.display = "block";
            document.getElementById("stop_button").style.display = "none";
        }

        var onConnected = function (session) {
            session.service("ALMemory").then(function (service) {
                memory = service;
            }, function (error) {
            });
            session.service("ExplorationManager").then(function (service) {
                exploManager = service;
                exploManager.publishMap()
                exploManager.publishLabels()
            }, function (error) {
            });
            RobotUtils.subscribeToALMemoryEvent("ExplorationManager/MetricalMap", $scope.setMap);
            RobotUtils.subscribeToALMemoryEvent("Patrol/RobotPosition", $scope.setRobot);
            RobotUtils.subscribeToALMemoryEvent("ExplorationManager/Places", $scope.setPlaces);
            RobotUtils.subscribeToALMemoryEvent("Patrol/Waypoints", $scope.setWaypoints);
            RobotUtils.subscribeToALMemoryEvent("Patrol/PatrolStarted", $scope.onPatrolStarted);
            RobotUtils.subscribeToALMemoryEvent("Patrol/PatrolFinished", $scope.onPatrolFinished);

        };

        var onDisconnected = function () {
        };

        RobotUtils.connect(onConnected, onDisconnected);

    });

var click = function (x, y) {
    var ev = document.createEvent('TouchEvent');
    var el = document.elementFromPoint(x, y);
    ev.initUIEvent('touchstart', true, true );
    el.dispatchEvent(ev);
}
<commit_msg>WEBPAGE: Display robot in blue.<commit_after>
console.log("defining module");
angular.module('pepper-patrol', ['ngTouch'])
    .controller('map-display', function ($scope, $locale, $timeout, $http) {
        console.log("map-display controller");
        var memory = null;
        var exploManager = null;
        var intervalID = null;
        var mpp = null;
        var size = null;
        var offset = null;
        // step : 0 = list explo, 1 = reloc, 2 = patrol.
        var step = 0;
        var touch = null;

        $scope.addOnClick = function (event) {
            // event.offsetX and event.offsetY
            // compute
            var img = document.getElementById("map_container");
            var pxlX = event.offsetX - img.offsetLeft
            var pxlY = event.offsetY - img.offsetTop
            touch = [pxlX, pxlY];
            if (pxlX > 0 && pxlX < img.width && pxlY > 0 && pxlY < img.height) {
                console.log("click: " + event.offsetX + " " + event.offsetY);
                if (step == 1) {
                    memory.raiseEvent("Patrol/Relocalize", [pxlX, pxlY]);
                    document.getElementById("mode_configure").click();
                } else if (step == 2) {
                    memory.raiseEvent("Patrol/AddWayPoint", [[pxlX, pxlY], ""]);
                }
            }
        };

        $scope.OnModeChanged = function() {
            step = document.querySelector('input[name="mode"]:checked').value
            console.log("onchanged: " + step.toString());
        }

        $scope.OnGoClick = function (event) {
            console.log("go");
            memory.raiseEvent("Patrol/StartPatrol", [])
        }

        $scope.OnResetClick = function(event) {
            memory.raiseEvent("Patrol/Reset", [])
        }

        $scope.setMap = function (tab) {
            var mpp = tab[0];
            var size = tab[1];
            var offset = tab[2];
            var data = tab[3];
            var wrapper = document.getElementById("wrapper");
            wrapper.style = "position:relative; width:"+size+"px; height:"+size+"px;"
            var map_container = document.getElementById('map_container');
            map_container.width = size;
            map_container.height = size;
            angular.element(map_container).css({
            'background-image': 'url(' + data +')',
            'background-size' : 'cover'
            });
            var waypoint_canvas = document.getElementById("waypoints_canvas");
            waypoint_canvas.width = size;
            waypoint_canvas.height = size;
            var places_canvas = document.getElementById("places_canvas");
            places_canvas.width = size;
            places_canvas.height = size;
            step = 1;
            document.getElementById("waiting_ui").style.display = "none";
            document.getElementById("mode_ui").style.visibility = "visible";
            document.getElementById("waypoints_ui").style.visibility = "visible";
        };

        $scope.setRobot = function (tab) {
            console.log("setRobot");
            var centerX = tab[0][0];
            var centerY = tab[0][1];
            var radius = tab[1];
            var canvas = document.getElementById('map_container');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.beginPath();
            context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
            context.fillStyle="blue";
            context.fill();
            context.beginPath();
            context.arc(tab[2][0], tab[2][1], 0.5 * radius, 0, 2 * Math.PI, false);
            context.fillStyle="blue";
            context.fill();
        };

        $scope.setPlaces = function (tab) {
            var canvas = document.getElementById('places_canvas');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            for (i = 0; i < tab.length; ++i) {
                var centerX = tab[i][0][0];
                var centerY = tab[i][0][1];
                var label = tab[i][1];
                var radius = 5;
                context.beginPath();
                context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
                context.fillStyle="#00ff00";
                context.fill();
                context.font = "30px Arial";
                context.fillStyle = "#00ff00";
                context.fillText(label.toString(), centerX + 10, centerY);
            }

        };
        $scope.setWaypoints = function (tab) {
            var canvas = document.getElementById('waypoints_canvas');
            var context = canvas.getContext('2d');
            context.clearRect(0, 0, canvas.width, canvas.height);
            context.lineWidth = 1.5;
            context.strokeStyle = 'red';
            context.beginPath();
            for (i = 0; i < tab.length; ++i) {
                var centerX = tab[i][0];
                var centerY = tab[i][1];
                var label = i.toString();
                context.lineTo(centerX, centerY);
                context.stroke();
                var radius = 5;
                context.beginPath();
                context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
                context.fillStyle = "red";
                context.fill();
                context.font = "30px Arial";
                context.fillText(label, centerX + 10, centerY);
            }
        };

        $scope.OnExit = function() {
            memory.raiseEvent("Patrol/Exit", [])
        }

        $scope.OnStop = function() {
            memory.raiseEvent("Patrol/StopPatrol", [])
        }

        $scope.onPatrolStarted = function() {
            document.getElementById("patrol_ongoing_ui").style.display = "block";
            document.getElementById("waypoints_ui").style.visibility = "hidden";
            document.getElementById("mode_ui").style.visibility = "hidden";
            document.getElementById("exit_button").style.display = "none";
            document.getElementById("stop_button").style.display = "block";
        }

        $scope.onPatrolFinished = function() {
            document.getElementById("patrol_ongoing_ui").style.display = "none";
            document.getElementById("waypoints_ui").style.visibility = "visible";
            document.getElementById("mode_ui").style.visibility = "visible";
            document.getElementById("exit_button").style.display = "block";
            document.getElementById("stop_button").style.display = "none";
        }

        var onConnected = function (session) {
            session.service("ALMemory").then(function (service) {
                memory = service;
            }, function (error) {
            });
            session.service("ExplorationManager").then(function (service) {
                exploManager = service;
                exploManager.publishMap()
                exploManager.publishLabels()
            }, function (error) {
            });
            RobotUtils.subscribeToALMemoryEvent("ExplorationManager/MetricalMap", $scope.setMap);
            RobotUtils.subscribeToALMemoryEvent("Patrol/RobotPosition", $scope.setRobot);
            RobotUtils.subscribeToALMemoryEvent("ExplorationManager/Places", $scope.setPlaces);
            RobotUtils.subscribeToALMemoryEvent("Patrol/Waypoints", $scope.setWaypoints);
            RobotUtils.subscribeToALMemoryEvent("Patrol/PatrolStarted", $scope.onPatrolStarted);
            RobotUtils.subscribeToALMemoryEvent("Patrol/PatrolFinished", $scope.onPatrolFinished);

        };

        var onDisconnected = function () {
        };

        RobotUtils.connect(onConnected, onDisconnected);

    });

var click = function (x, y) {
    var ev = document.createEvent('TouchEvent');
    var el = document.elementFromPoint(x, y);
    ev.initUIEvent('touchstart', true, true );
    el.dispatchEvent(ev);
}
<|endoftext|>


<commit_before>var Promise = require('node-promise'),
	defer = Promise.defer,
	when = Promise.when,
	all = Promise.all,
	_ = require('underscore');

function extractFiles(path) {
	var unzip = require('unzip'),
		deferred = defer();

	var files = {
		'xl/worksheets/sheet1.xml': {
			deferred: defer()
		},
		'xl/sharedStrings.xml': {
			deferred: defer()
		}
	};

    var noop = function () {};

	var srcStream = path instanceof require('stream') ?
		path :
		require('fs').createReadStream(path);

	srcStream
		.pipe(unzip.Parse())
		.on('error', function(err) {
			deferred.reject(err);
		})
		.on('end', function(){
			deferred.resolve();
		})
		.on('entry', function(entry) {
			if (files[entry.path]) {
				var contents = '';
				entry.on('data', function(data) {
					contents += data.toString();
				}).on('end', function() {
					files[entry.path].contents = contents;
					files[entry.path].deferred.resolve();
				});
			} else {
                entry.on('data', noop); // otherwise unzip.Parse() will hang forever on this entry on some xlsx files
            }
		});

	when(all(_.pluck(files, 'deferred')), function() {
		deferred.resolve(files);
	});

	return deferred.promise;
}

function calculateDimensions (cells) {
    var comparator = function (a, b) { return a-b; };
    var allRows = _(cells).map(function (cell) { return cell.row; }).sort(comparator),
        allCols = _(cells).map(function (cell) { return cell.column; }).sort(comparator),
        minRow = allRows[0],
        maxRow = _.last(allRows),
        minCol = allCols[0],
        maxCol = _.last(allCols);

    return [
        {row: minRow, column: minCol},
        {row: maxRow, column: maxCol}
    ];
}

function extractData(files) {
	try{
		var libxmljs = require('libxmljs'),
			sheet = libxmljs.parseXml(files['xl/worksheets/sheet1.xml'].contents),
			strings = libxmljs.parseXml(files['xl/sharedStrings.xml'].contents),
			ns = {a: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'},
			data = [];
	} catch(parseError){
	   return [];
    	}

	var colToInt = function(col) {
		var letters = ["", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
		col = col.trim().split('');

		var n = 0;

		for (var i = 0; i < col.length; i++) {
			n *= 26;
			n += letters.indexOf(col[i]);
		}

		return n;
	};

	var CellCoords = function(cell) {
		cell = cell.split(/([0-9]+)/);
		this.row = parseInt(cell[1]);
		this.column = colToInt(cell[0]);
	};

	var na = { value: function() { return ''; },
        text:  function() { return ''; } };

	var Cell = function(cellNode) {
		var r = cellNode.attr('r').value(),
			type = (cellNode.attr('t') || na).value(),
			value = (cellNode.get('a:v', ns) || na ).text(),
			coords = new CellCoords(r);

		this.column = coords.column;
		this.row = coords.row;
		this.value = value;
		this.type = type;
	};

	var cellNodes = sheet.find('/a:worksheet/a:sheetData/a:row/a:c', ns);
	var cells = _(cellNodes).map(function (node) {
		return new Cell(node);
	});

	var d = sheet.get('//a:dimension/@ref', ns);
	if (d) {
		d = _.map(d.value().split(':'), function(v) { return new CellCoords(v); });
	} else {
        d = calculateDimensions(cells)
	}

	var cols = d[1].column - d[0].column + 1,
		rows = d[1].row - d[0].row + 1;

	_(rows).times(function() {
		var _row = [];
		_(cols).times(function() { _row.push(''); });
		data.push(_row);
	});

	_.each(cells, function(cell) {
		var value = cell.value;

		if (cell.type == 's') value = strings.get('//a:si[' + (parseInt(value) + 1) + ']//a:t', ns).text();

		data[cell.row - d[0].row][cell.column - d[0].column] = value;
	});

	return data;
}

module.exports = function parseXlsx(path, cb) {
	extractFiles(path).then(function(files) {
		cb(null, extractData(files));
	},
	function(err) {
		cb(err);
	});
};
<commit_msg>Support for multiple t nodes in strings<commit_after>var Promise = require('node-promise'),
	defer = Promise.defer,
	when = Promise.when,
	all = Promise.all,
	_ = require('underscore');

function extractFiles(path) {
	var unzip = require('unzip'),
		deferred = defer();

	var files = {
		'xl/worksheets/sheet1.xml': {
			deferred: defer()
		},
		'xl/sharedStrings.xml': {
			deferred: defer()
		}
	};

    var noop = function () {};

	var srcStream = path instanceof require('stream') ?
		path :
		require('fs').createReadStream(path);

	srcStream
		.pipe(unzip.Parse())
		.on('error', function(err) {
			deferred.reject(err);
		})
		.on('end', function(){
			deferred.resolve();
		})
		.on('entry', function(entry) {
			if (files[entry.path]) {
				var contents = '';
				entry.on('data', function(data) {
					contents += data.toString();
				}).on('end', function() {
					files[entry.path].contents = contents;
					files[entry.path].deferred.resolve();
				});
			} else {
                entry.on('data', noop); // otherwise unzip.Parse() will hang forever on this entry on some xlsx files
            }
		});

	when(all(_.pluck(files, 'deferred')), function() {
		deferred.resolve(files);
	});

	return deferred.promise;
}

function calculateDimensions (cells) {
    var comparator = function (a, b) { return a-b; };
    var allRows = _(cells).map(function (cell) { return cell.row; }).sort(comparator),
        allCols = _(cells).map(function (cell) { return cell.column; }).sort(comparator),
        minRow = allRows[0],
        maxRow = _.last(allRows),
        minCol = allCols[0],
        maxCol = _.last(allCols);

    return [
        {row: minRow, column: minCol},
        {row: maxRow, column: maxCol}
    ];
}

function extractData(files) {
	try{
		var libxmljs = require('libxmljs'),
			sheet = libxmljs.parseXml(files['xl/worksheets/sheet1.xml'].contents),
			strings = libxmljs.parseXml(files['xl/sharedStrings.xml'].contents),
			ns = {a: 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'},
			data = [];
	} catch(parseError){
	   return [];
    	}

	var colToInt = function(col) {
		var letters = ["", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
		col = col.trim().split('');

		var n = 0;

		for (var i = 0; i < col.length; i++) {
			n *= 26;
			n += letters.indexOf(col[i]);
		}

		return n;
	};

	var CellCoords = function(cell) {
		cell = cell.split(/([0-9]+)/);
		this.row = parseInt(cell[1]);
		this.column = colToInt(cell[0]);
	};

	var na = { value: function() { return ''; },
        text:  function() { return ''; } };

	var Cell = function(cellNode) {
		var r = cellNode.attr('r').value(),
			type = (cellNode.attr('t') || na).value(),
			value = (cellNode.get('a:v', ns) || na ).text(),
			coords = new CellCoords(r);

		this.column = coords.column;
		this.row = coords.row;
		this.value = value;
		this.type = type;
	};

	var cellNodes = sheet.find('/a:worksheet/a:sheetData/a:row/a:c', ns);
	var cells = _(cellNodes).map(function (node) {
		return new Cell(node);
	});

	var d = sheet.get('//a:dimension/@ref', ns);
	if (d) {
		d = _.map(d.value().split(':'), function(v) { return new CellCoords(v); });
	} else {
        d = calculateDimensions(cells)
	}

	var cols = d[1].column - d[0].column + 1,
		rows = d[1].row - d[0].row + 1;

	_(rows).times(function() {
		var _row = [];
		_(cols).times(function() { _row.push(''); });
		data.push(_row);
	});

	_.each(cells, function(cell) {
		var value = cell.value;

		if (cell.type == 's') {
			values = strings.find('//a:si[' + (parseInt(value) + 1) + ']//a:t', ns)
			value = "";
			for (var i = 0; i < values.length; i++) {
				value += values[i].text();
			}
		}

		data[cell.row - d[0].row][cell.column - d[0].column] = value;
	});

	return data;
}

module.exports = function parseXlsx(path, cb) {
	extractFiles(path).then(function(files) {
		cb(null, extractData(files));
	},
	function(err) {
		cb(err);
	});
};
<|endoftext|>


<commit_before>/*
Expollapser version 0.11.0
*/

(function ($) {

	// Defaults
	var expollapser_defaults = {
		'toggler': 'header',
		'contentElement': 'next',
		'expandHeaderCss': null,
		'expandBodyCss': null,
		'collapseHeaderCss': null,
		'collapseBodyCss': null,
		'headerReplaceHtml': '',
		'open': false,
		'contentHtml': '',
		'expandAnimator': function (header, body, toggler, callback) { $(body).slideDown(200, callback); },
		'collapseAnimator': function (header, body, toggler, callback) { $(body).slideUp(200, callback); },
		'postExpand': function (header, body, toggler) { },
		'preCollapse': function (header, body, toggler) { },
		'postCollapse': function (header, body, toggler) { },
		'togglerSeparation': false
	};

	function expollapser_setDefaults(options) {
		if (options) {
			$.extend(expollapser_defaults, options);
		}
	}

	// Define methods of the expollapser plugin
	var methods = {

		// init : Sets up the plugin on the matched element(s)
		init: function (options) {
			return this.each(function () {
				var $this = $(this);
				var data = $this.data('expollapser');

				// If the plugin hasn't been initialized yet
				if (!data) {
					var settings = $.extend({}, expollapser_defaults); // Clone, shallow copy

					// Merge user options
					if (options) {
						$.extend(settings, options);
					}

					// Process the settings, basically by converting all convenience string settings
					// to underlying functions.
					settings.contentElement = processContentElement(settings.contentElement);
					settings.headerReplaceHtml = processHeaderReplaceHtml(settings.headerReplaceHtml);

					$(this).bind('preExpand', function (e, context) {
						ensureClass(context.header, settings.expandHeaderCss);
						ensureClassRemoved(context.header, settings.collapseHeaderCss);
						ensureClass(context.body, settings.expandBodyCss);
						ensureClassRemoved(context.body, settings.collapseBodyCss);
					});

					$(this).bind('postExpand', function (e, context) {
						settings.headerReplaceHtml(context.header);
					});

					$(this).bind('postCollapse', function (e, context) {
						ensureClassRemoved(context.header, settings.expandHeaderCss);
						ensureClass(context.header, settings.collapseHeaderCss);
						ensureClassRemoved(context.body, settings.expandBodyCss);
						ensureClass(context.body, settings.collapseBodyCss);
						settings.headerReplaceHtml(context.header);
					});

					settings.contentHtml = processContentHtml(settings.contentHtml, settings);

					// Setup data
					$(this).data('expollapser', {
						isopen: settings.open,
						getTogglers: resolveTogglers(settings.toggler, $this),
						contentLoaded: false,
						disabled: false,
						settings: settings
					});

					if (settings.open == true) {
						ensureClass($(this), settings.expandHeaderCss);
						ensureClass(settings.contentElement($(this)), settings.expandBodyCss);
						settings.headerReplaceHtml($(this));
						settings.contentElement($this).show();
					}
					else {
						ensureClass($(this), settings.collapseHeaderCss);
						ensureClass(settings.contentElement($(this)), settings.collapseBodyCss);
						settings.headerReplaceHtml($(this));
						settings.contentElement($this).hide();
					}

					// Setup togglers
					ensureToggleHookup($(this).data('expollapser').getTogglers, $(this));
				}
			});
		},

		// disable: Disables expand/collapse functionality
		disable: function () {
			return this.each(function () {
				$(this).data('expollapser')['disabled'] = true;
				$(this).data('expollapser').getTogglers($(this)).css('cursor', 'auto');
			})
		},

		// enable: Enables expand/collapse functionality
		enable: function () {
			return this.each(function () {
				$(this).data('expollapser')['disabled'] = false;
				$(this).data('expollapser').getTogglers($(this)).css('cursor', 'hand');
			})
		},

		// toggle: Toggles between expanded and collapsed state
		toggle: function (toggler) {
			return this.each(function () {
				var data = $(this).data('expollapser');

				// Handle special case with multiple togglers producing multiple contents
				if (data.isopen == true && data.settings.togglerSeparation && data.expandedBy.get(0) != toggler.get(0)) {
					var $this = $(this);
					$(this).expollapser('collapse', data.expandedBy, function () { $this.expollapser('expand', toggler) });
				}
				else { // Default toggle
					if (data.isopen == false)
						$(this).expollapser('expand', toggler);
					else {
						$(this).expollapser('collapse', toggler);
					}
				}
			});
		},

		// expand: Expands the matched element(s)
		expand: function (toggler) {
			return this.each(function () {
				var $this = $(this);
				var data = $(this).data('expollapser');
				var settings = data.settings;
				if (data.isopen == false && data.disabled == false) {
					if (toggler == null)
						toggler = $(data.getTogglers($this).get(0));
					var bodyElement = settings.contentElement($(this));
					$(this).trigger('preExpand', { header: $this, body: bodyElement, toggler: toggler });

					// Set content and do expand animation
					data.expandedBy = toggler;
					data.isopen = true;
					settings.contentHtml($(this), bodyElement, toggler, function () { });
					settings.expandAnimator($this, bodyElement, toggler, function () {
						$this.trigger('postExpand', { header: $this, body: bodyElement, toggler: toggler });
					});
				}
			});
		},

		collapse: function (toggler, callback) {
			return this.each(function () {
				var $this = $(this);
				var data = $this.data('expollapser');
				var settings = $this.data('expollapser').settings;
				if (data.isopen == true && data.disabled == false) {
					if (toggler == null)
						toggler = data.expandedBy;
					if (toggler == null)
						toggler = $this;
					var bodyElement = settings.contentElement($this);
					settings.preCollapse($this, bodyElement, toggler);

					data.isopen = false;
					settings.collapseAnimator($this, bodyElement, toggler, function () {
						$this.trigger('postCollapse', { header: $this, body: bodyElement, toggler: toggler });
						if (callback)
							callback();
					});
				}
			});
		}
	};

	// Ensures that the supplied togglers function on the supplied header element is setup with click events
	function ensureToggleHookup(togglersFn, headerElement) {
		togglersFn(headerElement).each(function () {
			// Set up click events of togglersFn if they have no click event already
			if (!$.data(this, 'events') || !$.data(this, 'events')['click'] || $.data(this, 'events')['click'].length == 0) {
				$(this).css('cursor', 'hand');
				if (!$(this).data('expollapser'))
					$(this).data('expollapser', { oldHtml: null });
				else
					$.extend($(this).data('expollapser'), { oldHtml: null });

				$(this).bind('click.expollapser', function () {
					headerElement.expollapser('toggle', $(this));
					return false;
				});
			}
		});
	}

	function assertStringOrFunction(subject, name, allowNull) {
		if ((!subject && allowNull) || typeof subject === 'string' || $.isFunction(subject))
			return;

		alert('Expollapser options error: ' + name + ' should be either a string or a function.');
	}

	function insertFn(fn, fnInsert) {
		return function (header, content, toggler) {
			fnInsert(header, content, toggler);
			fn(header, content, toggler);
		};
	}

	function ensureClass(jq, cssClass) {
		if (cssClass && !jq.hasClass(cssClass))
			jq.addClass(cssClass);
	};

	function ensureClassRemoved(jq, cssClass) {
		if (cssClass)
			jq.removeClass(cssClass);
	};

	// Parses contentElement setting and returns a function to get the content element
	function processContentElement(contentSetting) {
		assertStringOrFunction(contentSetting, 'contentElement');
		if (typeof contentSetting === 'string') {
			if (contentSetting == 'next')
				return function (headerElement) { return headerElement.next(); };
			else if (contentSetting == 'prev')
				return function (headerElement) { return headerElement.prev(); };
			else
				return function () { return $(contentSetting); };
		}

		return contentSetting;
	}

	// Parse for convenience settings in togglers
	function resolveTogglers(togglersSetting, $header) {
		assertStringOrFunction(togglersSetting, 'togglers');
		var togglersFunction;
		if (typeof togglersSetting === 'string') {
			if (togglersSetting == 'header') {
				return function () { return $header; };
			}
			else if (togglersSetting == 'headerLinks') {
				return function () { return $('a', $header); };
			}
			else {
				var stringSetting = togglersSetting;
				return function () { return $(stringSetting, $header); };
			}
		}

		return togglersSetting;
	}

	function processHeaderReplaceHtml(setting) {
		assertStringOrFunction(setting, 'headerReplaceHtml');
		if (typeof setting === 'string') {
			var html = setting;
			if (html.indexOf('<-->') > -1) {
				var replaceExpressions = html.split(',');
				return function (header) {
					for (var item in replaceExpressions) {
						var pair = replaceExpressions[item].split('<-->');
						if (header.data('expollapser') && header.data('expollapser').isopen == true) {
							header.html(header.html().replace(pair[0], pair[1]));
						}
						else {
							header.html(header.html().replace(pair[1], pair[0]));
						}
					}
				};
			}

			return function () { };
		}

		return setting;
	}

	// TODO: getUniqueId check om loaded content.
	function processContentHtml(setting, settings) {
		assertStringOrFunction(setting, 'contentHtml', false);
		var processedSetting;
		if (typeof setting === 'string') {
			var stringSetting = setting;
			if (setting == 'togglerHref')
				stringSetting = 'togglerAttr:href';
			if (stringSetting.beginsWith('togglerAttr:')) {
				processedSetting = function (header, content, toggler, callback) {
					$.get(toggler.attr(stringSetting.substring(12)), function (response) {
						content.html(response);
						callback();
					});
				};
				settings.togglerSeparation = true;
			}
			else if (setting.beginsWith('url:'))
				processedSetting = function (header, content, toggler, callback) {
					$.get(stringSetting.substring(4), function (response) {
						content.html(response);
						callback();
					});
				};
			else if (setting.length > 0)
				processedSetting = function (header, content, toggler, callback) {
					content.html(stringSetting);
					callback();
				};
			else
				processedSetting = function (header, content, toggler, callback) { callback(); };
		}
		else {
			processedSetting = setting;
		}

		var finalSetting = function (header, content, toggler, callback) {
			var id = getUniqueId(header, content, toggler);
			if (header.data('expollapser').contentLoaded != id) {
				processedSetting(header, content, toggler, function () {
					ensureToggleHookup(header.data('expollapser').getTogglers, header);
					callback();
				});
			}
			else
				callback();
		};

		return finalSetting;
	}

	function getUniqueId(elem1, elem2, elem3) {
		return $(elem1).attr($.expando) + $(elem2).attr($.expando) + $(elem3).attr($.expando);
	}

	// Core plugin registration point
	$.fn.expollapser = function (method) {

		// Method calling logic
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		}
		else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		}
		else {
			$.error('Method ' + method + ' does not exist on jQuery.expollapser');
		}
	};

	// Prototype extensions for common used string functions
	String.prototype.beginsWith = function (t, i) {
		if (i == false) {
			return (t == this.substring(0, t.length));
		}
		else {
			return (t.toLowerCase() == this.substring(0, t.length).toLowerCase());
		}
	}

	String.prototype.endsWith = function (t, i) {
		if (i == false) {
			return (t == this.substring(this.length - t.length));
		}
		else {
			return (t.toLowerCase() == this.substring(this.length - t.length).toLowerCase());
		}
	}
})(jQuery);

<commit_msg>Minor refactoring to binding syntax.<commit_after>/*
Expollapser version 0.11.0
*/

(function ($) {

	// Defaults
	var expollapser_defaults = {
		'toggler': 'header',
		'contentElement': 'next',
		'expandHeaderCss': null,
		'expandBodyCss': null,
		'collapseHeaderCss': null,
		'collapseBodyCss': null,
		'headerReplaceHtml': '',
		'open': false,
		'contentHtml': '',
		'expandAnimator': function (header, body, toggler, callback) { $(body).slideDown(200, callback); },
		'collapseAnimator': function (header, body, toggler, callback) { $(body).slideUp(200, callback); },
		'togglerSeparation': false
	};

	function expollapser_setDefaults(options) {
		if (options) {
			$.extend(expollapser_defaults, options);
		}
	}

	// Define methods of the expollapser plugin
	var methods = {

		// init : Sets up the plugin on the matched element(s)
		init: function (options) {
			return this.each(function () {
				var $this = $(this);
				var data = $this.data('expollapser');

				// If the plugin hasn't been initialized yet
				if (!data) {
					var settings = $.extend({}, expollapser_defaults); // Clone, shallow copy

					// Merge user options
					if (options) {
						$.extend(settings, options);
					}

					// Process the settings, basically by converting all convenience string settings
					// to underlying functions.
					settings.contentElement = processContentElement(settings.contentElement);
					settings.headerReplaceHtml = processHeaderReplaceHtml(settings.headerReplaceHtml);

					$(this).bind('preExpand', function (e, context) {
						ensureClass(context.header, settings.expandHeaderCss);
						ensureClassRemoved(context.header, settings.collapseHeaderCss);
						ensureClass(context.body, settings.expandBodyCss);
						ensureClassRemoved(context.body, settings.collapseBodyCss);
					});

					$(this).bind('postExpand', function (e, context) {
						settings.headerReplaceHtml(context.header);
					});

					$(this).bind('postCollapse', function (e, context) {
						ensureClassRemoved(context.header, settings.expandHeaderCss);
						ensureClass(context.header, settings.collapseHeaderCss);
						ensureClassRemoved(context.body, settings.expandBodyCss);
						ensureClass(context.body, settings.collapseBodyCss);
						settings.headerReplaceHtml(context.header);
					});

					settings.contentHtml = processContentHtml(settings.contentHtml, settings);

					// Setup data
					$(this).data('expollapser', {
						isopen: settings.open,
						getTogglers: resolveTogglers(settings.toggler, $this),
						contentLoaded: false,
						disabled: false,
						settings: settings
					});

					if (settings.open == true) {
						ensureClass($(this), settings.expandHeaderCss);
						ensureClass(settings.contentElement($(this)), settings.expandBodyCss);
						settings.headerReplaceHtml($(this));
						settings.contentElement($this).show();
					}
					else {
						ensureClass($(this), settings.collapseHeaderCss);
						ensureClass(settings.contentElement($(this)), settings.collapseBodyCss);
						settings.headerReplaceHtml($(this));
						settings.contentElement($this).hide();
					}

					// Setup togglers
					ensureToggleHookup($(this).data('expollapser').getTogglers, $(this));
				}
			});
		},

		// disable: Disables expand/collapse functionality
		disable: function () {
			return this.each(function () {
				$(this).data('expollapser')['disabled'] = true;
				$(this).data('expollapser').getTogglers($(this)).css('cursor', 'auto');
			})
		},

		// enable: Enables expand/collapse functionality
		enable: function () {
			return this.each(function () {
				$(this).data('expollapser')['disabled'] = false;
				$(this).data('expollapser').getTogglers($(this)).css('cursor', 'hand');
			})
		},

		// toggle: Toggles between expanded and collapsed state
		toggle: function (toggler) {
			return this.each(function () {
				var data = $(this).data('expollapser');

				// Handle special case with multiple togglers producing multiple contents
				if (data.isopen == true && data.settings.togglerSeparation && data.expandedBy.get(0) != toggler.get(0)) {
					var $this = $(this);
					$(this).expollapser('collapse', data.expandedBy, function () { $this.expollapser('expand', toggler) });
				}
				else { // Default toggle
					if (data.isopen == false)
						$(this).expollapser('expand', toggler);
					else {
						$(this).expollapser('collapse', toggler);
					}
				}
			});
		},

		// expand: Expands the matched element(s)
		expand: function (toggler) {
			return this.each(function () {
				var $this = $(this);
				var data = $(this).data('expollapser');
				var settings = data.settings;
				if (data.isopen == false && data.disabled == false) {
					if (toggler == null)
						toggler = $(data.getTogglers($this).get(0));
					var bodyElement = settings.contentElement($(this));
					$(this).trigger('preExpand', { header: $this, body: bodyElement, toggler: toggler });

					// Set content and do expand animation
					data.expandedBy = toggler;
					data.isopen = true;
					settings.contentHtml($(this), bodyElement, toggler, function () { });
					settings.expandAnimator($this, bodyElement, toggler, function () {
						$this.trigger('postExpand', { header: $this, body: bodyElement, toggler: toggler });
					});
				}
			});
		},

		collapse: function (toggler, callback) {
			return this.each(function () {
				var $this = $(this);
				var data = $this.data('expollapser');
				var settings = $this.data('expollapser').settings;
				if (data.isopen == true && data.disabled == false) {
					if (toggler == null)
						toggler = data.expandedBy;
					if (toggler == null)
						toggler = $this;
					var bodyElement = settings.contentElement($this);
					$(this).trigger('preCollapse', { header: $this, body: bodyElement, toggler: toggler });

					data.isopen = false;
					settings.collapseAnimator($this, bodyElement, toggler, function () {
						$this.trigger('postCollapse', { header: $this, body: bodyElement, toggler: toggler });
						if (callback)
							callback();
					});
				}
			});
		}
	};

	// Ensures that the supplied togglers function on the supplied header element is setup with click events
	function ensureToggleHookup(togglersFn, headerElement) {
		togglersFn(headerElement).each(function () {
			// Set up click events of togglersFn if they have no click event already
			if (!$.data(this, 'events') || !$.data(this, 'events')['click'] || $.data(this, 'events')['click'].length == 0) {
				$(this).css('cursor', 'hand');
				if (!$(this).data('expollapser'))
					$(this).data('expollapser', { oldHtml: null });
				else
					$.extend($(this).data('expollapser'), { oldHtml: null });

				$(this).bind('click.expollapser', function () {
					headerElement.expollapser('toggle', $(this));
					return false;
				});
			}
		});
	}

	function assertStringOrFunction(subject, name, allowNull) {
		if ((!subject && allowNull) || typeof subject === 'string' || $.isFunction(subject))
			return;

		alert('Expollapser options error: ' + name + ' should be either a string or a function.');
	}

	function insertFn(fn, fnInsert) {
		return function (header, content, toggler) {
			fnInsert(header, content, toggler);
			fn(header, content, toggler);
		};
	}

	function ensureClass(jq, cssClass) {
		if (cssClass && !jq.hasClass(cssClass))
			jq.addClass(cssClass);
	};

	function ensureClassRemoved(jq, cssClass) {
		if (cssClass)
			jq.removeClass(cssClass);
	};

	// Parses contentElement setting and returns a function to get the content element
	function processContentElement(contentSetting) {
		assertStringOrFunction(contentSetting, 'contentElement');
		if (typeof contentSetting === 'string') {
			if (contentSetting == 'next')
				return function (headerElement) { return headerElement.next(); };
			else if (contentSetting == 'prev')
				return function (headerElement) { return headerElement.prev(); };
			else
				return function () { return $(contentSetting); };
		}

		return contentSetting;
	}

	// Parse for convenience settings in togglers
	function resolveTogglers(togglersSetting, $header) {
		assertStringOrFunction(togglersSetting, 'togglers');
		var togglersFunction;
		if (typeof togglersSetting === 'string') {
			if (togglersSetting == 'header') {
				return function () { return $header; };
			}
			else if (togglersSetting == 'headerLinks') {
				return function () { return $('a', $header); };
			}
			else {
				var stringSetting = togglersSetting;
				return function () { return $(stringSetting, $header); };
			}
		}

		return togglersSetting;
	}

	function processHeaderReplaceHtml(setting) {
		assertStringOrFunction(setting, 'headerReplaceHtml');
		if (typeof setting === 'string') {
			var html = setting;
			if (html.indexOf('<-->') > -1) {
				var replaceExpressions = html.split(',');
				return function (header) {
					for (var item in replaceExpressions) {
						var pair = replaceExpressions[item].split('<-->');
						if (header.data('expollapser') && header.data('expollapser').isopen == true) {
							header.html(header.html().replace(pair[0], pair[1]));
						}
						else {
							header.html(header.html().replace(pair[1], pair[0]));
						}
					}
				};
			}

			return function () { };
		}

		return setting;
	}

	// TODO: getUniqueId check om loaded content.
	function processContentHtml(setting, settings) {
		assertStringOrFunction(setting, 'contentHtml', false);
		var processedSetting;
		if (typeof setting === 'string') {
			var stringSetting = setting;
			if (setting == 'togglerHref')
				stringSetting = 'togglerAttr:href';
			if (stringSetting.beginsWith('togglerAttr:')) {
				processedSetting = function (header, content, toggler, callback) {
					$.get(toggler.attr(stringSetting.substring(12)), function (response) {
						content.html(response);
						callback();
					});
				};
				settings.togglerSeparation = true;
			}
			else if (setting.beginsWith('url:'))
				processedSetting = function (header, content, toggler, callback) {
					$.get(stringSetting.substring(4), function (response) {
						content.html(response);
						callback();
					});
				};
			else if (setting.length > 0)
				processedSetting = function (header, content, toggler, callback) {
					content.html(stringSetting);
					callback();
				};
			else
				processedSetting = function (header, content, toggler, callback) { callback(); };
		}
		else {
			processedSetting = setting;
		}

		var finalSetting = function (header, content, toggler, callback) {
			var id = getUniqueId(header, content, toggler);
			if (header.data('expollapser').contentLoaded != id) {
				processedSetting(header, content, toggler, function () {
					ensureToggleHookup(header.data('expollapser').getTogglers, header);
					callback();
				});
			}
			else
				callback();
		};

		return finalSetting;
	}

	function getUniqueId(elem1, elem2, elem3) {
		return $(elem1).attr($.expando) + $(elem2).attr($.expando) + $(elem3).attr($.expando);
	}

	// Core plugin registration point
	$.fn.expollapser = function (method) {

		// Method calling logic
		if (methods[method]) {
			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
		}
		else if (typeof method === 'object' || !method) {
			return methods.init.apply(this, arguments);
		}
		else {
			$.error('Method ' + method + ' does not exist on jQuery.expollapser');
		}
	};

	// Prototype extensions for common used string functions
	String.prototype.beginsWith = function (t, i) {
		if (i == false) {
			return (t == this.substring(0, t.length));
		}
		else {
			return (t.toLowerCase() == this.substring(0, t.length).toLowerCase());
		}
	}

	String.prototype.endsWith = function (t, i) {
		if (i == false) {
			return (t == this.substring(this.length - t.length));
		}
		else {
			return (t.toLowerCase() == this.substring(this.length - t.length).toLowerCase());
		}
	}
})(jQuery);

<|endoftext|>


<commit_before>import { Quaternion } from '../math/Quaternion';
import { Vector3 } from '../math/Vector3';
import { Matrix4 } from '../math/Matrix4';
import { EventDispatcher } from './EventDispatcher';
import { Euler } from '../math/Euler';
import { Layers } from './Layers';
import { Matrix3 } from '../math/Matrix3';
import { _Math } from '../math/Math';

/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author elephantatwork / www.elephantatwork.ch
 */

var object3DId = 0;

function Object3D() {

	Object.defineProperty( this, 'id', { value: object3DId ++ } );

	this.uuid = _Math.generateUUID();

	this.name = '';
	this.type = 'Object3D';

	this.parent = null;
	this.children = [];

	this.up = Object3D.DefaultUp.clone();

	var position = new Vector3();
	var rotation = new Euler();
	var quaternion = new Quaternion();
	var scale = new Vector3( 1, 1, 1 );

	function onRotationChange() {

		quaternion.setFromEuler( rotation, false );

	}

	function onQuaternionChange() {

		rotation.setFromQuaternion( quaternion, undefined, false );

	}

	rotation.onChange( onRotationChange );
	quaternion.onChange( onQuaternionChange );

	Object.defineProperties( this, {
		position: {
			enumerable: true,
			value: position
		},
		rotation: {
			enumerable: true,
			value: rotation
		},
		quaternion: {
			enumerable: true,
			value: quaternion
		},
		scale: {
			enumerable: true,
			value: scale
		},
		modelViewMatrix: {
			value: new Matrix4()
		},
		normalMatrix: {
			value: new Matrix3()
		}
	} );

	this.matrix = new Matrix4();
	this.matrixWorld = new Matrix4();

	this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
	this.matrixWorldNeedsUpdate = false;

	this.layers = new Layers();
	this.visible = true;

	this.castShadow = false;
	this.receiveShadow = false;

	this.frustumCulled = true;
	this.renderOrder = 0;

	this.userData = {};

	this.onBeforeRender = function () {};
	this.onAfterRender = function () {};

}

Object3D.DefaultUp = new Vector3( 0, 1, 0 );
Object3D.DefaultMatrixAutoUpdate = true;

Object.assign( Object3D.prototype, EventDispatcher.prototype, {

	isObject3D: true,

	applyMatrix: function ( matrix ) {

		this.matrix.multiplyMatrices( matrix, this.matrix );

		this.matrix.decompose( this.position, this.quaternion, this.scale );

	},

	setRotationFromAxisAngle: function ( axis, angle ) {

		// assumes axis is normalized

		this.quaternion.setFromAxisAngle( axis, angle );

	},

	setRotationFromEuler: function ( euler ) {

		this.quaternion.setFromEuler( euler, true );

	},

	setRotationFromMatrix: function ( m ) {

		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

		this.quaternion.setFromRotationMatrix( m );

	},

	setRotationFromQuaternion: function ( q ) {

		// assumes q is normalized

		this.quaternion.copy( q );

	},

	rotateOnAxis: function () {

		// rotate object on axis in object space
		// axis is assumed to be normalized

		var q1 = new Quaternion();

		return function rotateOnAxis( axis, angle ) {

			q1.setFromAxisAngle( axis, angle );

			this.quaternion.multiply( q1 );

			return this;

		};

	}(),

	rotateX: function () {

		var v1 = new Vector3( 1, 0, 0 );

		return function rotateX( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateY: function () {

		var v1 = new Vector3( 0, 1, 0 );

		return function rotateY( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateZ: function () {

		var v1 = new Vector3( 0, 0, 1 );

		return function rotateZ( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	translateOnAxis: function () {

		// translate object by distance along axis in object space
		// axis is assumed to be normalized

		var v1 = new Vector3();

		return function translateOnAxis( axis, distance ) {

			v1.copy( axis ).applyQuaternion( this.quaternion );

			this.position.add( v1.multiplyScalar( distance ) );

			return this;

		};

	}(),

	translateX: function () {

		var v1 = new Vector3( 1, 0, 0 );

		return function translateX( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	translateY: function () {

		var v1 = new Vector3( 0, 1, 0 );

		return function translateY( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	translateZ: function () {

		var v1 = new Vector3( 0, 0, 1 );

		return function translateZ( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	localToWorld: function ( vector ) {

		return vector.applyMatrix4( this.matrixWorld );

	},

	worldToLocal: function () {

		var m1 = new Matrix4();

		return function worldToLocal( vector ) {

			return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );

		};

	}(),

	lookAt: function () {

		// This routine does not support objects with rotated and/or translated parent(s)

		var m1 = new Matrix4();

		return function lookAt( vector ) {

			if ( this.isCamera ) {

				m1.lookAt( this.position, vector, this.up );

			} else {

				m1.lookAt( vector, this.position, this.up );

			}

			this.quaternion.setFromRotationMatrix( m1 );

		};

	}(),

	add: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.add( arguments[ i ] );

			}

			return this;

		}

		if ( object === this ) {

			console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
			return this;

		}

		if ( ( object && object.isObject3D ) ) {

			if ( object.parent !== null ) {

				object.parent.remove( object );

			}

			object.parent = this;
			object.dispatchEvent( { type: 'added' } );

			this.children.push( object );

		} else {

			console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );

		}

		return this;

	},

	remove: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.remove( arguments[ i ] );

			}

		}

		var index = this.children.indexOf( object );

		if ( index !== - 1 ) {

			object.parent = null;

			object.dispatchEvent( { type: 'removed' } );

			this.children.splice( index, 1 );

		}

	},

	getObjectById: function ( id ) {

		return this.getObjectByProperty( 'id', id );

	},

	getObjectByName: function ( name ) {

		return this.getObjectByProperty( 'name', name );

	},

	getObjectByProperty: function ( name, value ) {

		if ( this[ name ] === value ) return this;

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			var child = this.children[ i ];
			var object = child.getObjectByProperty( name, value );

			if ( object !== undefined ) {

				return object;

			}

		}

		return undefined;

	},

	getWorldPosition: function ( optionalTarget ) {

		var result = optionalTarget || new Vector3();

		this.updateMatrixWorld( true );

		return result.setFromMatrixPosition( this.matrixWorld );

	},

	getWorldQuaternion: function () {

		var position = new Vector3();
		var scale = new Vector3();

		return function getWorldQuaternion( optionalTarget ) {

			var result = optionalTarget || new Quaternion();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, result, scale );

			return result;

		};

	}(),

	getWorldRotation: function () {

		var quaternion = new Quaternion();

		return function getWorldRotation( optionalTarget ) {

			var result = optionalTarget || new Euler();

			this.getWorldQuaternion( quaternion );

			return result.setFromQuaternion( quaternion, this.rotation.order, false );

		};

	}(),

	getWorldScale: function () {

		var position = new Vector3();
		var quaternion = new Quaternion();

		return function getWorldScale( optionalTarget ) {

			var result = optionalTarget || new Vector3();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, quaternion, result );

			return result;

		};

	}(),

	getWorldDirection: function () {

		var quaternion = new Quaternion();

		return function getWorldDirection( optionalTarget ) {

			var result = optionalTarget || new Vector3();

			this.getWorldQuaternion( quaternion );

			return result.set( 0, 0, 1 ).applyQuaternion( quaternion );

		};

	}(),

	raycast: function () {},

	traverse: function ( callback ) {

		callback( this );

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].traverse( callback );

		}

	},

	traverseVisible: function ( callback ) {

		if ( this.visible === false ) return;

		callback( this );

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].traverseVisible( callback );

		}

	},

	traverseAncestors: function ( callback ) {

		var parent = this.parent;

		if ( parent !== null ) {

			callback( parent );

			parent.traverseAncestors( callback );

		}

	},

	updateMatrix: function () {

		this.matrix.compose( this.position, this.quaternion, this.scale );

		this.matrixWorldNeedsUpdate = true;

	},

	updateMatrixWorld: function ( force ) {

		if ( this.matrixAutoUpdate ) this.updateMatrix();

		if ( this.matrixWorldNeedsUpdate || force ) {

			if ( this.parent === null ) {

				this.matrixWorld.copy( this.matrix );

			} else {

				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );

			}

			this.matrixWorldNeedsUpdate = false;

			force = true;

		}

		// update children

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].updateMatrixWorld( force );

		}

	},

	toJSON: function ( meta ) {

		// meta is '' when called from JSON.stringify
		var isRootObject = ( meta === undefined || meta === '' );

		var output = {};

		// meta is a hash used to collect geometries, materials.
		// not providing it implies that this is the root object
		// being serialized.
		if ( isRootObject ) {

			// initialize meta obj
			meta = {
				geometries: {},
				materials: {},
				textures: {},
				images: {}
			};

			output.metadata = {
				version: 4.5,
				type: 'Object',
				generator: 'Object3D.toJSON'
			};

		}

		// standard Object3D serialization

		var object = {};

		object.uuid = this.uuid;
		object.type = this.type;

		if ( this.name !== '' ) object.name = this.name;
		if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
		if ( this.castShadow === true ) object.castShadow = true;
		if ( this.receiveShadow === true ) object.receiveShadow = true;
		if ( this.visible === false ) object.visible = false;

		object.matrix = this.matrix.toArray();

		//

		function serialize( library, element ) {

			if ( library[ element.uuid ] === undefined ) {

				library[ element.uuid ] = element.toJSON( meta );

			}

			return element.uuid;

		}

		if ( this.geometry !== undefined ) {

			object.geometry = serialize( meta.geometries, this.geometry );

		}

		if ( this.material !== undefined ) {

			if ( Array.isArray( this.material ) ) {

				var uuids = [];

				for ( var i = 0, l = this.material.length; i < l; i ++ ) {

					uuids.push( serialize( meta.materials, this.material[ i ] ) );

				}

				object.material = uuids;

			} else {

				object.material = serialize( meta.materials, this.material );

			}

		}

		//

		if ( this.children.length > 0 ) {

			object.children = [];

			for ( var i = 0; i < this.children.length; i ++ ) {

				object.children.push( this.children[ i ].toJSON( meta ).object );

			}

		}

		if ( isRootObject ) {

			var geometries = extractFromCache( meta.geometries );
			var materials = extractFromCache( meta.materials );
			var textures = extractFromCache( meta.textures );
			var images = extractFromCache( meta.images );

			if ( geometries.length > 0 ) output.geometries = geometries;
			if ( materials.length > 0 ) output.materials = materials;
			if ( textures.length > 0 ) output.textures = textures;
			if ( images.length > 0 ) output.images = images;

		}

		output.object = object;

		return output;

		// extract data from the cache hash
		// remove metadata on each item
		// and return as array
		function extractFromCache( cache ) {

			var values = [];
			for ( var key in cache ) {

				var data = cache[ key ];
				delete data.metadata;
				values.push( data );

			}
			return values;

		}

	},

	clone: function ( recursive ) {

		return new this.constructor().copy( this, recursive );

	},

	copy: function ( source, recursive ) {

		if ( recursive === undefined ) recursive = true;

		this.name = source.name;

		this.up.copy( source.up );

		this.position.copy( source.position );
		this.quaternion.copy( source.quaternion );
		this.scale.copy( source.scale );

		this.matrix.copy( source.matrix );
		this.matrixWorld.copy( source.matrixWorld );

		this.matrixAutoUpdate = source.matrixAutoUpdate;
		this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

		this.layers.mask = source.layers.mask;
		this.visible = source.visible;

		this.castShadow = source.castShadow;
		this.receiveShadow = source.receiveShadow;

		this.frustumCulled = source.frustumCulled;
		this.renderOrder = source.renderOrder;

		this.userData = JSON.parse( JSON.stringify( source.userData ) );

		if ( recursive === true ) {

			for ( var i = 0; i < source.children.length; i ++ ) {

				var child = source.children[ i ];
				this.add( child.clone() );

			}

		}

		return this;

	}

} );

export { Object3D };
<commit_msg>Move the default onBeforeRender/onAfterRender empty functions from each instance to the prototype, for constructor speed and retained memory improvement.<commit_after>import { Quaternion } from '../math/Quaternion';
import { Vector3 } from '../math/Vector3';
import { Matrix4 } from '../math/Matrix4';
import { EventDispatcher } from './EventDispatcher';
import { Euler } from '../math/Euler';
import { Layers } from './Layers';
import { Matrix3 } from '../math/Matrix3';
import { _Math } from '../math/Math';

/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 * @author WestLangley / http://github.com/WestLangley
 * @author elephantatwork / www.elephantatwork.ch
 */

var object3DId = 0;

function Object3D() {

	Object.defineProperty( this, 'id', { value: object3DId ++ } );

	this.uuid = _Math.generateUUID();

	this.name = '';
	this.type = 'Object3D';

	this.parent = null;
	this.children = [];

	this.up = Object3D.DefaultUp.clone();

	var position = new Vector3();
	var rotation = new Euler();
	var quaternion = new Quaternion();
	var scale = new Vector3( 1, 1, 1 );

	function onRotationChange() {

		quaternion.setFromEuler( rotation, false );

	}

	function onQuaternionChange() {

		rotation.setFromQuaternion( quaternion, undefined, false );

	}

	rotation.onChange( onRotationChange );
	quaternion.onChange( onQuaternionChange );

	Object.defineProperties( this, {
		position: {
			enumerable: true,
			value: position
		},
		rotation: {
			enumerable: true,
			value: rotation
		},
		quaternion: {
			enumerable: true,
			value: quaternion
		},
		scale: {
			enumerable: true,
			value: scale
		},
		modelViewMatrix: {
			value: new Matrix4()
		},
		normalMatrix: {
			value: new Matrix3()
		}
	} );

	this.matrix = new Matrix4();
	this.matrixWorld = new Matrix4();

	this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
	this.matrixWorldNeedsUpdate = false;

	this.layers = new Layers();
	this.visible = true;

	this.castShadow = false;
	this.receiveShadow = false;

	this.frustumCulled = true;
	this.renderOrder = 0;

	this.userData = {};
}

Object3D.DefaultUp = new Vector3( 0, 1, 0 );
Object3D.DefaultMatrixAutoUpdate = true;

Object.assign( Object3D.prototype, EventDispatcher.prototype, {

	isObject3D: true,

	onBeforeRender: function () {},
	onAfterRender: function () {},

	applyMatrix: function ( matrix ) {

		this.matrix.multiplyMatrices( matrix, this.matrix );

		this.matrix.decompose( this.position, this.quaternion, this.scale );

	},

	setRotationFromAxisAngle: function ( axis, angle ) {

		// assumes axis is normalized

		this.quaternion.setFromAxisAngle( axis, angle );

	},

	setRotationFromEuler: function ( euler ) {

		this.quaternion.setFromEuler( euler, true );

	},

	setRotationFromMatrix: function ( m ) {

		// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)

		this.quaternion.setFromRotationMatrix( m );

	},

	setRotationFromQuaternion: function ( q ) {

		// assumes q is normalized

		this.quaternion.copy( q );

	},

	rotateOnAxis: function () {

		// rotate object on axis in object space
		// axis is assumed to be normalized

		var q1 = new Quaternion();

		return function rotateOnAxis( axis, angle ) {

			q1.setFromAxisAngle( axis, angle );

			this.quaternion.multiply( q1 );

			return this;

		};

	}(),

	rotateX: function () {

		var v1 = new Vector3( 1, 0, 0 );

		return function rotateX( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateY: function () {

		var v1 = new Vector3( 0, 1, 0 );

		return function rotateY( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	rotateZ: function () {

		var v1 = new Vector3( 0, 0, 1 );

		return function rotateZ( angle ) {

			return this.rotateOnAxis( v1, angle );

		};

	}(),

	translateOnAxis: function () {

		// translate object by distance along axis in object space
		// axis is assumed to be normalized

		var v1 = new Vector3();

		return function translateOnAxis( axis, distance ) {

			v1.copy( axis ).applyQuaternion( this.quaternion );

			this.position.add( v1.multiplyScalar( distance ) );

			return this;

		};

	}(),

	translateX: function () {

		var v1 = new Vector3( 1, 0, 0 );

		return function translateX( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	translateY: function () {

		var v1 = new Vector3( 0, 1, 0 );

		return function translateY( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	translateZ: function () {

		var v1 = new Vector3( 0, 0, 1 );

		return function translateZ( distance ) {

			return this.translateOnAxis( v1, distance );

		};

	}(),

	localToWorld: function ( vector ) {

		return vector.applyMatrix4( this.matrixWorld );

	},

	worldToLocal: function () {

		var m1 = new Matrix4();

		return function worldToLocal( vector ) {

			return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) );

		};

	}(),

	lookAt: function () {

		// This routine does not support objects with rotated and/or translated parent(s)

		var m1 = new Matrix4();

		return function lookAt( vector ) {

			if ( this.isCamera ) {

				m1.lookAt( this.position, vector, this.up );

			} else {

				m1.lookAt( vector, this.position, this.up );

			}

			this.quaternion.setFromRotationMatrix( m1 );

		};

	}(),

	add: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.add( arguments[ i ] );

			}

			return this;

		}

		if ( object === this ) {

			console.error( "THREE.Object3D.add: object can't be added as a child of itself.", object );
			return this;

		}

		if ( ( object && object.isObject3D ) ) {

			if ( object.parent !== null ) {

				object.parent.remove( object );

			}

			object.parent = this;
			object.dispatchEvent( { type: 'added' } );

			this.children.push( object );

		} else {

			console.error( "THREE.Object3D.add: object not an instance of THREE.Object3D.", object );

		}

		return this;

	},

	remove: function ( object ) {

		if ( arguments.length > 1 ) {

			for ( var i = 0; i < arguments.length; i ++ ) {

				this.remove( arguments[ i ] );

			}

		}

		var index = this.children.indexOf( object );

		if ( index !== - 1 ) {

			object.parent = null;

			object.dispatchEvent( { type: 'removed' } );

			this.children.splice( index, 1 );

		}

	},

	getObjectById: function ( id ) {

		return this.getObjectByProperty( 'id', id );

	},

	getObjectByName: function ( name ) {

		return this.getObjectByProperty( 'name', name );

	},

	getObjectByProperty: function ( name, value ) {

		if ( this[ name ] === value ) return this;

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			var child = this.children[ i ];
			var object = child.getObjectByProperty( name, value );

			if ( object !== undefined ) {

				return object;

			}

		}

		return undefined;

	},

	getWorldPosition: function ( optionalTarget ) {

		var result = optionalTarget || new Vector3();

		this.updateMatrixWorld( true );

		return result.setFromMatrixPosition( this.matrixWorld );

	},

	getWorldQuaternion: function () {

		var position = new Vector3();
		var scale = new Vector3();

		return function getWorldQuaternion( optionalTarget ) {

			var result = optionalTarget || new Quaternion();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, result, scale );

			return result;

		};

	}(),

	getWorldRotation: function () {

		var quaternion = new Quaternion();

		return function getWorldRotation( optionalTarget ) {

			var result = optionalTarget || new Euler();

			this.getWorldQuaternion( quaternion );

			return result.setFromQuaternion( quaternion, this.rotation.order, false );

		};

	}(),

	getWorldScale: function () {

		var position = new Vector3();
		var quaternion = new Quaternion();

		return function getWorldScale( optionalTarget ) {

			var result = optionalTarget || new Vector3();

			this.updateMatrixWorld( true );

			this.matrixWorld.decompose( position, quaternion, result );

			return result;

		};

	}(),

	getWorldDirection: function () {

		var quaternion = new Quaternion();

		return function getWorldDirection( optionalTarget ) {

			var result = optionalTarget || new Vector3();

			this.getWorldQuaternion( quaternion );

			return result.set( 0, 0, 1 ).applyQuaternion( quaternion );

		};

	}(),

	raycast: function () {},

	traverse: function ( callback ) {

		callback( this );

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].traverse( callback );

		}

	},

	traverseVisible: function ( callback ) {

		if ( this.visible === false ) return;

		callback( this );

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].traverseVisible( callback );

		}

	},

	traverseAncestors: function ( callback ) {

		var parent = this.parent;

		if ( parent !== null ) {

			callback( parent );

			parent.traverseAncestors( callback );

		}

	},

	updateMatrix: function () {

		this.matrix.compose( this.position, this.quaternion, this.scale );

		this.matrixWorldNeedsUpdate = true;

	},

	updateMatrixWorld: function ( force ) {

		if ( this.matrixAutoUpdate ) this.updateMatrix();

		if ( this.matrixWorldNeedsUpdate || force ) {

			if ( this.parent === null ) {

				this.matrixWorld.copy( this.matrix );

			} else {

				this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );

			}

			this.matrixWorldNeedsUpdate = false;

			force = true;

		}

		// update children

		var children = this.children;

		for ( var i = 0, l = children.length; i < l; i ++ ) {

			children[ i ].updateMatrixWorld( force );

		}

	},

	toJSON: function ( meta ) {

		// meta is '' when called from JSON.stringify
		var isRootObject = ( meta === undefined || meta === '' );

		var output = {};

		// meta is a hash used to collect geometries, materials.
		// not providing it implies that this is the root object
		// being serialized.
		if ( isRootObject ) {

			// initialize meta obj
			meta = {
				geometries: {},
				materials: {},
				textures: {},
				images: {}
			};

			output.metadata = {
				version: 4.5,
				type: 'Object',
				generator: 'Object3D.toJSON'
			};

		}

		// standard Object3D serialization

		var object = {};

		object.uuid = this.uuid;
		object.type = this.type;

		if ( this.name !== '' ) object.name = this.name;
		if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData;
		if ( this.castShadow === true ) object.castShadow = true;
		if ( this.receiveShadow === true ) object.receiveShadow = true;
		if ( this.visible === false ) object.visible = false;

		object.matrix = this.matrix.toArray();

		//

		function serialize( library, element ) {

			if ( library[ element.uuid ] === undefined ) {

				library[ element.uuid ] = element.toJSON( meta );

			}

			return element.uuid;

		}

		if ( this.geometry !== undefined ) {

			object.geometry = serialize( meta.geometries, this.geometry );

		}

		if ( this.material !== undefined ) {

			if ( Array.isArray( this.material ) ) {

				var uuids = [];

				for ( var i = 0, l = this.material.length; i < l; i ++ ) {

					uuids.push( serialize( meta.materials, this.material[ i ] ) );

				}

				object.material = uuids;

			} else {

				object.material = serialize( meta.materials, this.material );

			}

		}

		//

		if ( this.children.length > 0 ) {

			object.children = [];

			for ( var i = 0; i < this.children.length; i ++ ) {

				object.children.push( this.children[ i ].toJSON( meta ).object );

			}

		}

		if ( isRootObject ) {

			var geometries = extractFromCache( meta.geometries );
			var materials = extractFromCache( meta.materials );
			var textures = extractFromCache( meta.textures );
			var images = extractFromCache( meta.images );

			if ( geometries.length > 0 ) output.geometries = geometries;
			if ( materials.length > 0 ) output.materials = materials;
			if ( textures.length > 0 ) output.textures = textures;
			if ( images.length > 0 ) output.images = images;

		}

		output.object = object;

		return output;

		// extract data from the cache hash
		// remove metadata on each item
		// and return as array
		function extractFromCache( cache ) {

			var values = [];
			for ( var key in cache ) {

				var data = cache[ key ];
				delete data.metadata;
				values.push( data );

			}
			return values;

		}

	},

	clone: function ( recursive ) {

		return new this.constructor().copy( this, recursive );

	},

	copy: function ( source, recursive ) {

		if ( recursive === undefined ) recursive = true;

		this.name = source.name;

		this.up.copy( source.up );

		this.position.copy( source.position );
		this.quaternion.copy( source.quaternion );
		this.scale.copy( source.scale );

		this.matrix.copy( source.matrix );
		this.matrixWorld.copy( source.matrixWorld );

		this.matrixAutoUpdate = source.matrixAutoUpdate;
		this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;

		this.layers.mask = source.layers.mask;
		this.visible = source.visible;

		this.castShadow = source.castShadow;
		this.receiveShadow = source.receiveShadow;

		this.frustumCulled = source.frustumCulled;
		this.renderOrder = source.renderOrder;

		this.userData = JSON.parse( JSON.stringify( source.userData ) );

		if ( recursive === true ) {

			for ( var i = 0; i < source.children.length; i ++ ) {

				var child = source.children[ i ];
				this.add( child.clone() );

			}

		}

		return this;

	}

} );

export { Object3D };
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Object3D = function () {

	this.id = THREE.Object3DCount ++;

	this.name = '';
	this.properties = {};

	this.parent = undefined;
	this.children = [];

	this.up = new THREE.Vector3( 0, 1, 0 );

	this.position = new THREE.Vector3();
	this.rotation = new THREE.Vector3();
	this.eulerOrder = 'XYZ';
	this.scale = new THREE.Vector3( 1, 1, 1 );

	this.renderDepth = null;

	this.rotationAutoUpdate = true;

	this.matrix = new THREE.Matrix4();
	this.matrixWorld = new THREE.Matrix4();
	this.matrixRotationWorld = new THREE.Matrix4();

	this.matrixAutoUpdate = true;
	this.matrixWorldNeedsUpdate = true;

	this.quaternion = new THREE.Quaternion();
	this.useQuaternion = false;

	this.boundRadius = 0.0;
	this.boundRadiusScale = 1.0;

	this.visible = true;

	this.castShadow = false;
	this.receiveShadow = false;

	this.frustumCulled = true;

	this._vector = new THREE.Vector3();

};

THREE.Object3D.prototype = {

	constructor: THREE.Object3D,

	applyMatrix: function ( matrix ) {

		this.matrix.multiply( matrix, this.matrix );

		this.scale.getScaleFromMatrix( this.matrix );

		var mat = new THREE.Matrix4().extractRotation( this.matrix );
		this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder );

		this.position.getPositionFromMatrix( this.matrix );

	},

	translate: function ( distance, axis ) {

		this.matrix.rotateAxis( axis );
		this.position.addSelf( axis.multiplyScalar( distance ) );

	},

	translateX: function ( distance ) {

		this.translate( distance, this._vector.set( 1, 0, 0 ) );

	},

	translateY: function ( distance ) {

		this.translate( distance, this._vector.set( 0, 1, 0 ) );

	},

	translateZ: function ( distance ) {

		this.translate( distance, this._vector.set( 0, 0, 1 ) );

	},

	lookAt: function ( vector ) {

		// TODO: Add hierarchy support.

		this.matrix.lookAt( vector, this.position, this.up );

		if ( this.rotationAutoUpdate ) {

			this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );

		}

	},

	add: function ( object ) {

		if ( object === this ) {

			console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
			return;

		}

		if ( object instanceof THREE.Object3D ) {

			if ( object.parent !== undefined ) {

				object.parent.remove( object );

			}

			object.parent = this;
			this.children.push( object );

			// add to scene

			var scene = this;

			while ( scene.parent !== undefined ) {

				scene = scene.parent;

			}

			if ( scene !== undefined && scene instanceof THREE.Scene )  {

				scene.__addObject( object );

			}

		}

	},

	remove: function ( object ) {

		var index = this.children.indexOf( object );

		if ( index !== - 1 ) {

			object.parent = undefined;
			this.children.splice( index, 1 );

			// remove from scene

			var scene = this;

			while ( scene.parent !== undefined ) {

				scene = scene.parent;

			}

			if ( scene !== undefined && scene instanceof THREE.Scene ) {

				scene.__removeObject( object );

			}

		}

	},

	getChildByName: function ( name, recursive ) {

		var c, cl, child;

		for ( c = 0, cl = this.children.length; c < cl; c ++ ) {

			child = this.children[ c ];

			if ( child.name === name ) {

				return child;

			}

			if ( recursive ) {

				child = child.getChildByName( name, recursive );

				if ( child !== undefined ) {

					return child;

				}

			}

		}

		return undefined;

	},

	updateMatrix: function () {

		this.matrix.setPosition( this.position );

		if ( this.useQuaternion === true )  {

			this.matrix.setRotationFromQuaternion( this.quaternion );

		} else {

			this.matrix.setRotationFromEuler( this.rotation, this.eulerOrder );

		}

		if ( this.scale.x !== 1 || this.scale.y !== 1 || this.scale.z !== 1 ) {

			this.matrix.scale( this.scale );
			this.boundRadiusScale = Math.max( this.scale.x, Math.max( this.scale.y, this.scale.z ) );

		}

		this.matrixWorldNeedsUpdate = true;

	},

	updateMatrixWorld: function ( force ) {

		if ( this.matrixAutoUpdate === true ) this.updateMatrix();

		if ( this.matrixWorldNeedsUpdate === true || force === true ) {

			if ( this.parent !== undefined ) {

				this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );

			} else {

				this.matrixWorld.copy( this.matrix );

			}

			this.matrixWorldNeedsUpdate = false;

			force = true;

		}

		// update children

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			this.children[ i ].updateMatrixWorld( force );

		}

	},

	worldToLocal: function ( vector ) {

		return THREE.Object3D.__m1.getInverse( this.matrixWorld ).multiplyVector3( vector );

	},

	localToWorld: function ( vector ) {

		return this.matrixWorld.multiplyVector3( vector );

	},

	clone: function () {

		// TODO

	}

};

THREE.Object3D.__m1 = new THREE.Matrix4();

THREE.Object3DCount = 0;
<commit_msg>add getDescendants to Object3D<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 * @author mikael emtinger / http://gomo.se/
 * @author alteredq / http://alteredqualia.com/
 */

THREE.Object3D = function () {

	this.id = THREE.Object3DCount ++;

	this.name = '';
	this.properties = {};

	this.parent = undefined;
	this.children = [];

	this.up = new THREE.Vector3( 0, 1, 0 );

	this.position = new THREE.Vector3();
	this.rotation = new THREE.Vector3();
	this.eulerOrder = 'XYZ';
	this.scale = new THREE.Vector3( 1, 1, 1 );

	this.renderDepth = null;

	this.rotationAutoUpdate = true;

	this.matrix = new THREE.Matrix4();
	this.matrixWorld = new THREE.Matrix4();
	this.matrixRotationWorld = new THREE.Matrix4();

	this.matrixAutoUpdate = true;
	this.matrixWorldNeedsUpdate = true;

	this.quaternion = new THREE.Quaternion();
	this.useQuaternion = false;

	this.boundRadius = 0.0;
	this.boundRadiusScale = 1.0;

	this.visible = true;

	this.castShadow = false;
	this.receiveShadow = false;

	this.frustumCulled = true;

	this._vector = new THREE.Vector3();

};

THREE.Object3D.prototype = {

	constructor: THREE.Object3D,

	applyMatrix: function ( matrix ) {

		this.matrix.multiply( matrix, this.matrix );

		this.scale.getScaleFromMatrix( this.matrix );

		var mat = new THREE.Matrix4().extractRotation( this.matrix );
		this.rotation.setEulerFromRotationMatrix( mat, this.eulerOrder );

		this.position.getPositionFromMatrix( this.matrix );

	},

	translate: function ( distance, axis ) {

		this.matrix.rotateAxis( axis );
		this.position.addSelf( axis.multiplyScalar( distance ) );

	},

	translateX: function ( distance ) {

		this.translate( distance, this._vector.set( 1, 0, 0 ) );

	},

	translateY: function ( distance ) {

		this.translate( distance, this._vector.set( 0, 1, 0 ) );

	},

	translateZ: function ( distance ) {

		this.translate( distance, this._vector.set( 0, 0, 1 ) );

	},

	lookAt: function ( vector ) {

		// TODO: Add hierarchy support.

		this.matrix.lookAt( vector, this.position, this.up );

		if ( this.rotationAutoUpdate ) {

			this.rotation.setEulerFromRotationMatrix( this.matrix, this.eulerOrder );

		}

	},

	add: function ( object ) {

		if ( object === this ) {

			console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' );
			return;

		}

		if ( object instanceof THREE.Object3D ) {

			if ( object.parent !== undefined ) {

				object.parent.remove( object );

			}

			object.parent = this;
			this.children.push( object );

			// add to scene

			var scene = this;

			while ( scene.parent !== undefined ) {

				scene = scene.parent;

			}

			if ( scene !== undefined && scene instanceof THREE.Scene )  {

				scene.__addObject( object );

			}

		}

	},

	remove: function ( object ) {

		var index = this.children.indexOf( object );

		if ( index !== - 1 ) {

			object.parent = undefined;
			this.children.splice( index, 1 );

			// remove from scene

			var scene = this;

			while ( scene.parent !== undefined ) {

				scene = scene.parent;

			}

			if ( scene !== undefined && scene instanceof THREE.Scene ) {

				scene.__removeObject( object );

			}

		}

	},

	getChildByName: function ( name, recursive ) {

		var c, cl, child;

		for ( c = 0, cl = this.children.length; c < cl; c ++ ) {

			child = this.children[ c ];

			if ( child.name === name ) {

				return child;

			}

			if ( recursive ) {

				child = child.getChildByName( name, recursive );

				if ( child !== undefined ) {

					return child;

				}

			}

		}

		return undefined;

	},

	getDescendants: function (returnValue) {
		var children = this.children,l = children.length,child;

		if (returnValue === undefined){
			returnValue = [];
		}

		for (var i = 0; i < l ; i++){
			child = children[i];
			returnValue.push(child);
			child.getDescendants(returnValue);
		};

		return returnValue;

	},

	updateMatrix: function () {

		this.matrix.setPosition( this.position );

		if ( this.useQuaternion === true )  {

			this.matrix.setRotationFromQuaternion( this.quaternion );

		} else {

			this.matrix.setRotationFromEuler( this.rotation, this.eulerOrder );

		}

		if ( this.scale.x !== 1 || this.scale.y !== 1 || this.scale.z !== 1 ) {

			this.matrix.scale( this.scale );
			this.boundRadiusScale = Math.max( this.scale.x, Math.max( this.scale.y, this.scale.z ) );

		}

		this.matrixWorldNeedsUpdate = true;

	},

	updateMatrixWorld: function ( force ) {

		if ( this.matrixAutoUpdate === true ) this.updateMatrix();

		if ( this.matrixWorldNeedsUpdate === true || force === true ) {

			if ( this.parent !== undefined ) {

				this.matrixWorld.multiply( this.parent.matrixWorld, this.matrix );

			} else {

				this.matrixWorld.copy( this.matrix );

			}

			this.matrixWorldNeedsUpdate = false;

			force = true;

		}

		// update children

		for ( var i = 0, l = this.children.length; i < l; i ++ ) {

			this.children[ i ].updateMatrixWorld( force );

		}

	},

	worldToLocal: function ( vector ) {

		return THREE.Object3D.__m1.getInverse( this.matrixWorld ).multiplyVector3( vector );

	},

	localToWorld: function ( vector ) {

		return this.matrixWorld.multiplyVector3( vector );

	},

	clone: function () {

		// TODO

	}

};

THREE.Object3D.__m1 = new THREE.Matrix4();

THREE.Object3DCount = 0;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import PureCropperPreview, { getTransformations } from '../preview';

export default class PureCropper extends Component {
  static propTypes = {
    // URL or data-url of image to be cropped
    originalImage: PropTypes.string.isRequired,
    // Area in real pixels which is desired to be cropped
    cropArea: PropTypes.object,
    // Visual selection position and size
    selectionPosition: PropTypes.object,

    aspectRatio: PropTypes.number.isRequired,

    style: PropTypes.shape({
      width: PropTypes.number.isRequired,
      height: PropTypes.number.isRequired
    }).isRequired,

    onZoom: PropTypes.func,
    onDrag: PropTypes.func
  }

  static defaultProps = {
    onZoom: () => undefined,
    onDrag: () => undefined
  }

  countSelectionArea() {
    const { aspectRatio } = this.props;
    const holderSize = this.props.style;
    const holderAspectRatio = holderSize.width / holderSize.height;

    function gatherAreaSize(containerSize, ratio) {
      const width = containerSize.width * 0.6;
      const left = (containerSize.width - width) / 2;
      const height = width / ratio;
      const top = (containerSize.height - height) / 2;
      return {
        width,
        height,
        left,
        top
      };
    }

    if (aspectRatio >= holderAspectRatio) {
      return gatherAreaSize(holderSize, aspectRatio);
    }

    const countedArea = gatherAreaSize({
      width: holderSize.height,
      height: holderSize.width
    }, 1 / aspectRatio);

    return {
      top: countedArea.left,
      left: countedArea.top,
      width: countedArea.height,
      height: countedArea.width
    };
  }

  handleMouseWheel(event) {
    event.preventDefault();
    const { deltaX, deltaY } = event;
    const significantDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY;

    this.props.onZoom(significantDelta);
  }

  handleMouseDown(event) {
    this.dragging = true;
    this.mouseCoords = {
      x: event.pageX,
      y: event.pageY
    };
  }

  handleMouseUp() {
    this.dragging = false;
    this.mouseCoords = {};
  }

  handleMouseMove(event) {
    if (this.dragging) {
      this.props.onDrag({
        diffX: event.pageX - this.mouseCoords.x,
        diffY: event.pageY - this.mouseCoords.y,
      });

      this.mouseCoords = {
        x: event.pageX,
        y: event.pageY
      };
    }
  }

  handleMouseLeave() {
    this.dragging = false;
    this.mouseCoords = {};
  }

  render() {
    const {
      cropArea,
      originalImage,
      style
    } = this.props;

    const holderStyle = {
      ...style,
      background: 'cadetblue',
      position: 'relative',
      overflow: 'hidden'
    };

    const previewStyle = {
      ...this.countSelectionArea(),
      position: 'absolute',
      top: '50%',
      left: '50%',
      transform: `translate(-50%, -50%)`,
      borderRadius: '50%',
      border: '1px solid black'
    };

    const {
      originX,
      originY,
      scale
    } = getTransformations(cropArea, previewStyle);

    const backgroundStyle = {
      pointerEvents: 'none',
      transformOrigin: `${originX}px ${originY}px`,
      transform: `
        translate(
          ${ holderStyle.width / 2 - originX }px,
          ${ holderStyle.height / 2 - originY }px
        )
        scale(${scale})
      `
    };

    const overlayStyle = {
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      background: 'black',
      opacity: 0.3
    };

    return (

        <PureCropperPreview
          cropArea={ cropArea }
          originalURL={ originalImage }
          style={ previewStyle }
        />

    );
  }
}
<commit_msg>Prevent more default browser actions on img<commit_after>import React, { Component, PropTypes } from 'react';
import PureCropperPreview, { getTransformations } from '../preview';

export default class PureCropper extends Component {
  static propTypes = {
    // URL or data-url of image to be cropped
    originalImage: PropTypes.string.isRequired,
    // Area in real pixels which is desired to be cropped
    cropArea: PropTypes.object,
    // Visual selection position and size
    selectionPosition: PropTypes.object,

    aspectRatio: PropTypes.number.isRequired,

    style: PropTypes.shape({
      width: PropTypes.number.isRequired,
      height: PropTypes.number.isRequired
    }).isRequired,

    onZoom: PropTypes.func,
    onDrag: PropTypes.func
  }

  static defaultProps = {
    onZoom: () => undefined,
    onDrag: () => undefined
  }

  countSelectionArea() {
    const { aspectRatio } = this.props;
    const holderSize = this.props.style;
    const holderAspectRatio = holderSize.width / holderSize.height;

    function gatherAreaSize(containerSize, ratio) {
      const width = containerSize.width * 0.6;
      const left = (containerSize.width - width) / 2;
      const height = width / ratio;
      const top = (containerSize.height - height) / 2;
      return {
        width,
        height,
        left,
        top
      };
    }

    if (aspectRatio >= holderAspectRatio) {
      return gatherAreaSize(holderSize, aspectRatio);
    }

    const countedArea = gatherAreaSize({
      width: holderSize.height,
      height: holderSize.width
    }, 1 / aspectRatio);

    return {
      top: countedArea.left,
      left: countedArea.top,
      width: countedArea.height,
      height: countedArea.width
    };
  }

  handleMouseWheel(event) {
    event.preventDefault();
    const { deltaX, deltaY } = event;
    const significantDelta = Math.abs(deltaX) > Math.abs(deltaY) ? deltaX : deltaY;

    this.props.onZoom(significantDelta);
  }

  handleMouseDown(event) {
    this.dragging = true;
    this.mouseCoords = {
      x: event.pageX,
      y: event.pageY
    };
  }

  handleMouseUp() {
    this.dragging = false;
    this.mouseCoords = {};
  }

  handleMouseMove(event) {
    if (this.dragging) {
      event.preventDefault();
      this.props.onDrag({
        diffX: event.pageX - this.mouseCoords.x,
        diffY: event.pageY - this.mouseCoords.y,
      });

      this.mouseCoords = {
        x: event.pageX,
        y: event.pageY
      };
    }
  }

  handleMouseLeave() {
    this.dragging = false;
    this.mouseCoords = {};
  }

  render() {
    const {
      cropArea,
      originalImage,
      style
    } = this.props;

    const noSelectStyle = {
      '-webkit-user-select': 'none',
      '-khtml-user-select': 'none',
      '-moz-user-select': 'none',
      '-o-user-select': 'none',
      'user-select': 'none'
    };

    const holderStyle = {
      ...style,
      background: 'cadetblue',
      position: 'relative',
      overflow: 'hidden'
    };

    const previewStyle = {
      ...this.countSelectionArea(),
      position: 'absolute',
      top: '50%',
      left: '50%',
      transform: `translate(-50%, -50%)`,
      borderRadius: '50%',
      border: '1px solid black'
    };

    const {
      originX,
      originY,
      scale
    } = getTransformations(cropArea, previewStyle);

    const backgroundStyle = {
      ...noSelectStyle,
      pointerEvents: 'none',
      transformOrigin: `${originX}px ${originY}px`,
      transform: `
        translate(
          ${ holderStyle.width / 2 - originX }px,
          ${ holderStyle.height / 2 - originY }px
        )
        scale(${scale})
      `
    };

    const overlayStyle = {
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      background: 'black',
      opacity: 0.3,
      pointerEvents: 'none'
    };

    return (

        <PureCropperPreview
          cropArea={ cropArea }
          originalURL={ originalImage }
          style={ previewStyle }
        />

    );
  }
}
<|endoftext|>