From 2f9473b3d7ff8579fb64ac93ace4347219554f99 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 14:02:27 -0700 Subject: [PATCH 01/53] Linting should use an exit error code on failure --- gulpfile.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gulpfile.js b/gulpfile.js index c021e779..39cd0fad 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -43,7 +43,8 @@ gulp.task('js-lint', function() { curly: true, predef: [ 'angular','DB','d3', 'ga', 'GAPI_KEY', 'document' , 'LZString' ] })) - .pipe(jshint.reporter('default')); + .pipe(jshint.reporter('default')) + .pipe(jshint.reporter("fail")); }); gulp.task('json-lint', function() { From 9d3e009013c0966d10f2e4e8ce95e1f99c7d0184 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 15:01:23 -0700 Subject: [PATCH 02/53] Align power plant pct --- app/views/page-outfit.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 6c85b872..83f17870 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -212,7 +212,7 @@ SYS 1 {{fPwr(pp.c.pGen)}} - 100% + 100% From c80e0a51bf9c853fdcace151d1f4f3efc308bc11 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 17:17:42 -0700 Subject: [PATCH 03/53] Use eslint instead of JShint --- .jshintignore | 1 - gulpfile.js | 75 ++++++++++++++++++++++++++++++--------------------- package.json | 2 +- 3 files changed, 45 insertions(+), 33 deletions(-) delete mode 100644 .jshintignore diff --git a/.jshintignore b/.jshintignore deleted file mode 100644 index 4b71d483..00000000 --- a/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -app/js/db.js \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 39cd0fad..deba614b 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,25 +1,28 @@ -var gulp = require('gulp'), - less = require('gulp-less'), - jshint = require('gulp-jshint'), - minifyCSS = require('gulp-minify-css'), +// Build / Built-in dependencies +var gulp = require('gulp'), + exec = require('child_process').exec, + pkg = require('./package.json'); + +// Package.json / Gulp Dependencies +var appCache = require("gulp-manifest"), concat = require('gulp-concat'), - uglify = require('gulp-uglify'), - sourcemaps = require('gulp-sourcemaps'), - templateCache = require('gulp-angular-templatecache'), - htmlmin = require('gulp-htmlmin'), - template = require('gulp-template'), - mainBowerFiles = require('main-bower-files'), del = require('del'), - runSequence = require('run-sequence'), - exec = require('child_process').exec, - RevAll = require('gulp-rev-all'), - gutil = require( 'gulp-util' ), - svgstore = require( 'gulp-svgstore' ), - svgmin = require( 'gulp-svgmin' ), - jsonlint = require("gulp-jsonlint"), - appCache = require("gulp-manifest"), + eslint = require('gulp-eslint'); + gutil = require('gulp-util'), + htmlmin = require('gulp-htmlmin'), jasmine = require('gulp-jasmine'), - pkg = require('./package.json'); + jsonlint = require("gulp-jsonlint"), + less = require('gulp-less'), + mainBowerFiles = require('main-bower-files'), + minifyCSS = require('gulp-minify-css'), + revAll = require('gulp-rev-all'), + runSequence = require('run-sequence'), + sourcemaps = require('gulp-sourcemaps'), + svgstore = require('gulp-svgstore'), + svgmin = require('gulp-svgmin'), + template = require('gulp-template'), + templateCache = require('gulp-angular-templatecache'), + uglify = require('gulp-uglify'); var cdnHostStr = ''; @@ -36,21 +39,31 @@ gulp.task('less', function() { }); gulp.task('js-lint', function() { - return gulp.src('app/js/**/*.js') - .pipe(jshint({ - undef: true, - unused: true, - curly: true, - predef: [ 'angular','DB','d3', 'ga', 'GAPI_KEY', 'document' , 'LZString' ] + return gulp.src(['app/js/**/*.js', '!app/js/template_cache.js', '!app/js/db.js']) + .pipe(eslint({ + globals: { angular:1, DB:1, d3:1, ga:1, GAPI_KEY:1, LZString: 1 }, + rules: { + quotes: [2, 'single'], + strict: 'global', + eqeqeq: 'smart', + 'space-after-keywords': [2, 'always'], + 'no-use-before-define': 'no-func', + 'space-before-function-paren': [2, 'never'], + 'space-before-blocks': [2, 'always'], + 'object-curly-spacing': [2, "always"], + 'brace-style': [2, '1tbs', { allowSingleLine: true }] + }, + envs: ['browser'] })) - .pipe(jshint.reporter('default')) - .pipe(jshint.reporter("fail")); + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); }); gulp.task('json-lint', function() { return gulp.src('data/**/*.json') .pipe(jsonlint()) - .pipe(jsonlint.reporter()); + .pipe(jsonlint.reporter()) + .pipe(jsonlint.failAfterError()); }); gulp.task('bower', function(){ @@ -188,11 +201,11 @@ gulp.task('watch', function() { }); gulp.task('cache-bust', function(done) { - var revAll = new RevAll({ prefix: cdnHostStr, dontRenameFile: ['.html','db.json'] }); + var rev_all = new revAll({ prefix: cdnHostStr, dontRenameFile: ['.html','db.json'] }); var stream = gulp.src('build/**') - .pipe(revAll.revision()) + .pipe(rev_all.revision()) .pipe(gulp.dest('build')) - .pipe(revAll.manifestFile()) + .pipe(rev_all.manifestFile()) .pipe(gulp.dest('build')); stream.on('end', function() { diff --git a/package.json b/package.json index e841e408..31414320 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,9 @@ "gulp": "^3.8.11", "gulp-angular-templatecache": "^1.6.0", "gulp-concat": "^2.5.2", + "gulp-eslint": "^0.13.2", "gulp-htmlmin": "^1.1.1", "gulp-jasmine": "^2.0.1", - "gulp-jshint": "^1.10.0", "gulp-jsonlint": "^1.0.2", "gulp-less": "^3.0.2", "gulp-manifest": "0.0.6", From 3f8cf106a1e789313b39d3e701480c7d9d9a0d18 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 17:23:13 -0700 Subject: [PATCH 04/53] Linting fixes --- app/js/app.js | 31 ++--- app/js/config.js | 36 +++--- app/js/controllers/controller-comparison.js | 86 ++++++------- app/js/controllers/controller-delete.js | 6 +- app/js/controllers/controller-error.js | 6 +- app/js/controllers/controller-export.js | 8 +- app/js/controllers/controller-import.js | 10 +- app/js/controllers/controller-link.js | 8 +- app/js/controllers/controller-modal.js | 6 +- app/js/controllers/controller-outfit.js | 36 +++--- app/js/controllers/controller-shipyard.js | 4 +- app/js/directives/directive-area-chart.js | 118 +++++++++--------- app/js/directives/directive-bar-chart.js | 28 ++--- .../directives/directive-comparison-table.js | 24 ++-- .../directives/directive-component-select.js | 28 ++--- app/js/directives/directive-header.js | 26 ++-- app/js/directives/directive-power-bands.js | 57 ++++----- app/js/directives/directive-slider.js | 46 +++---- app/js/directives/directive-slot-hardpoint.js | 10 +- app/js/directives/directive-slot-internal.js | 6 +- app/js/factory-utils.js | 12 +- app/js/service-persist.js | 40 +++--- app/js/service-serializer.js | 59 ++++----- app/js/shipyard/factory-component-set.js | 38 +++--- app/js/shipyard/factory-ship.js | 111 ++++++++-------- app/js/shipyard/module-shipyard.js | 86 ++++++------- app/js/shipyard/service-components.js | 14 +-- 27 files changed, 470 insertions(+), 470 deletions(-) diff --git a/app/js/app.js b/app/js/app.js index c24da083..04e449a6 100755 --- a/app/js/app.js +++ b/app/js/app.js @@ -1,12 +1,13 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', 'shipyard', 'ngLodash', 'app.templates']) -.run(['$rootScope', '$location', '$window', '$document','$state','commonArray','shipPurpose','shipSize','hardPointClass','GroupMap', 'Persist', function ($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hpc, GroupMap, Persist) { +.run(['$rootScope', '$location', '$window', '$document', '$state', 'commonArray', 'shipPurpose', 'shipSize', 'hardPointClass', 'GroupMap', 'Persist', +function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hpc, GroupMap, Persist) { // App is running as a standalone web app on tablet/mobile var isStandAlone = $window.navigator.standalone || ($window.external && $window.external.msIsSiteMode && $window.external.msIsSiteMode()); // Redirect any state transition errors to the error controller/state - $rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error){ + $rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error) { e.preventDefault(); - $state.go('error', error, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL + $state.go('error', error, { location: false, reload: true }); // Go to error state, reload the controller, keep the current URL }); // Track on Google analytics if available @@ -16,12 +17,12 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', if (to.url) { // Only track states that have a URL if ($window.ga) { - ga('send', 'pageview', {page: $location.path()}); + ga('send', 'pageview', { page: $location.path() }); } if (isStandAlone) { // Persist the current state - Persist.setState({name: to.name, params: toParams}); + Persist.setState({ name: to.name, params: toParams }); } } }); @@ -32,12 +33,12 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', $rootScope.SZ = sz; $rootScope.HPC = hpc; $rootScope.GMAP = GroupMap; - $rootScope.STATUS = ['','DISABLED', 'OFF', 'ON']; - $rootScope.STATUS_CLASS = ['','disabled', 'warning', 'secondary-disabled']; + $rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON']; + $rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled']; $rootScope.title = 'Coriolis'; - $rootScope.cName = function (c) { - return c.c? c.c.name? c.c.name : GroupMap[c.c.grp] : null; + $rootScope.cName = function(c) { + return c.c ? c.c.name ? c.c.name : GroupMap[c.c.grp] : null; }; // Formatters @@ -48,21 +49,21 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', $rootScope.fPct = d3.format('.2%'); $rootScope.f1Pct = d3.format('.1%'); $rootScope.fRPct = d3.format('%'); - $rootScope.fTime = function(d) { return Math.floor(d/60) + ":" + ("00" + Math.floor(d%60)).substr(-2,2); }; + $rootScope.fTime = function(d) { return Math.floor(d / 60) + ':' + ('00' + Math.floor(d % 60)).substr(-2, 2); }; if (isStandAlone) { var state = Persist.getState(); // If a previous state has been stored, load that state if (state && state.name && state.params) { - $state.go(state.name, state.params, {location:'replace'}); + $state.go(state.name, state.params, { location: 'replace' }); } else { - $state.go('shipyard', null, {location:'replace'}); // Default to home page + $state.go('shipyard', null, { location: 'replace' }); // Default to home page } } // Global Event Listeners - $doc.bind('keyup', function (e) { - if(e.keyCode == 27) { // Escape Key + $doc.bind('keyup', function(e) { + if (e.keyCode == 27) { // Escape Key $rootScope.$broadcast('close', e); $rootScope.$apply(); } else { @@ -70,7 +71,7 @@ angular.module('app', ['ui.router', 'ct.ui.router.extras.sticky', 'ui.sortable', } }); - $rootScope.bgClicked = function (e) { + $rootScope.bgClicked = function(e) { $rootScope.$broadcast('close', e); }; diff --git a/app/js/config.js b/app/js/config.js index 6da41298..87e1f132 100755 --- a/app/js/config.js +++ b/app/js/config.js @@ -1,9 +1,9 @@ /** * Sets up the routes and handlers before the Angular app is kicked off. */ -angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', '$locationProvider', 'ShipsDB', function ($provide, $stateProvider, $urlRouterProvider, $locationProvider, ships) { +angular.module('app').config(['$provide', '$stateProvider', '$urlRouterProvider', '$locationProvider', 'ShipsDB', function($provide, $stateProvider, $urlRouterProvider, $locationProvider, ships) { // Use HTML5 push and replace state if possible - $locationProvider.html5Mode({enabled: true, requireBase: false}); + $locationProvider.html5Mode({ enabled: true, requireBase: false }); /** * Set up all states and their routes. */ @@ -11,13 +11,13 @@ angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', .state('outfit', { url: '/outfit/:shipId/:code?bn', params: { - shipId: { value: 'sidewinder', squash: false}, // Allow 'shipId' parameter to default to sidewinder - code: { value: null, squash: true } // Allow 'code' parameter to be empty/optional + shipId: { value: 'sidewinder', squash: false }, // Allow 'shipId' parameter to default to sidewinder + code: { value: null, squash: true } // Allow 'code' parameter to be empty/optional }, templateUrl: 'views/page-outfit.html', controller: 'OutfitController', resolve: { - shipId: ['$stateParams',function ($p) { // Ensure ship exists before loading controller + shipId: ['$stateParams', function($p) { // Ensure ship exists before loading controller if (!ships[$p.shipId]) { throw { type: 'no-ship', message: $p.shipId }; } @@ -28,7 +28,7 @@ angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', .state('compare', { url: '/compare/:name', params: { - name: {value: null, squash: true } + name: { value: null, squash: true } }, templateUrl: 'views/page-comparison.html', controller: 'ComparisonController', @@ -41,26 +41,26 @@ angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', sticky: true }) .state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController', sticky: true }) - .state('error', { params: {type:null, message:null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController', sticky: true }) + .state('error', { params: { type: null, message: null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController', sticky: true }) // Modal States and views - .state('modal', { abstract: true, views:{ "modal": { templateUrl: "views/_modal.html", controller: 'ModalController' } } }) - .state('modal.about', { views: { "modal-content": { templateUrl: "views/modal-about.html" } } }) - .state('modal.export', { params: {title:null, data: null, promise: null}, views: { "modal-content": { templateUrl: "views/modal-export.html", controller: 'ExportController' } } }) - .state('modal.import', { params: {obj:null}, views: { "modal-content": { templateUrl: "views/modal-import.html", controller: 'ImportController' } } }) - .state('modal.link', { params: {url:null}, views: { "modal-content": { templateUrl: "views/modal-link.html", controller: 'LinkController' } } }) - .state('modal.delete', { views: { "modal-content": { templateUrl: "views/modal-delete.html", controller: 'DeleteController' } } }); + .state('modal', { abstract: true, views: { 'modal': { templateUrl: 'views/_modal.html', controller: 'ModalController' } } }) + .state('modal.about', { views: { 'modal-content': { templateUrl: 'views/modal-about.html' } } }) + .state('modal.export', { params: { title: null, data: null, promise: null }, views: { 'modal-content': { templateUrl: 'views/modal-export.html', controller: 'ExportController' } } }) + .state('modal.import', { params: { obj: null }, views: { 'modal-content': { templateUrl: 'views/modal-import.html', controller: 'ImportController' } } }) + .state('modal.link', { params: { url: null }, views: { 'modal-content': { templateUrl: 'views/modal-link.html', controller: 'LinkController' } } }) + .state('modal.delete', { views: { 'modal-content': { templateUrl: 'views/modal-delete.html', controller: 'DeleteController' } } }); // Redirects - $urlRouterProvider.when('/outfit','/outfit/sidewinder'); + $urlRouterProvider.when('/outfit', '/outfit/sidewinder'); /** * 404 Handler - Keep current URL/ do not redirect, change to error state. */ - $urlRouterProvider.otherwise(function ($injector, $location) { + $urlRouterProvider.otherwise(function($injector, $location) { // Go to error state, reload the controller, keep the current URL - $injector.get('$state').go('error', { type: 404, message: null, details: null }, {location:false, reload:true}); + $injector.get('$state').go('error', { type: 404, message: null, details: null }, { location: false, reload: true }); return $location.path; }); @@ -69,10 +69,10 @@ angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', * redirects uncaught errors to the error page. * */ - $provide.decorator('$exceptionHandler', ['$delegate', '$injector', function ($delegate, $injector) { + $provide.decorator('$exceptionHandler', ['$delegate', '$injector', function($delegate, $injector) { return function(err, cause) { // Go to error state, reload the controller, keep the current URL - $injector.get('$state').go('error', {type:null, message: err.message, details: err.stack }, {location:false, reload:true}); + $injector.get('$state').go('error', { type: null, message: err.message, details: err.stack }, { location: false, reload: true }); $delegate(err, cause); }; }]); diff --git a/app/js/controllers/controller-comparison.js b/app/js/controllers/controller-comparison.js index 3ac392e9..d9914256 100755 --- a/app/js/controllers/controller-comparison.js +++ b/app/js/controllers/controller-comparison.js @@ -1,48 +1,49 @@ -angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function (_, $rootScope, $filter, $scope, $state, $stateParams, Utils, ShipFacets, Ships, Ship, Persist, Serializer) { +angular.module('app').controller('ComparisonController', ['lodash', '$rootScope', '$filter', '$scope', '$state', '$stateParams', 'Utils', 'ShipFacets', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function(_, $rootScope, $filter, $scope, $state, $stateParams, Utils, ShipFacets, Ships, Ship, Persist, Serializer) { $rootScope.title = 'Coriolis - Compare'; $scope.predicate = 'name'; // Sort by ship name as default $scope.desc = false; - $scope.facetSortOpts = { containment: '#facet-container', orderChanged: function () { $scope.saved = false; } }; + $scope.facetSortOpts = { containment: '#facet-container', orderChanged: function() { $scope.saved = false; } }; $scope.builds = []; $scope.unusedBuilds = []; $scope.name = $stateParams.name; $scope.compareMode = !$stateParams.code; $scope.importObj = {}; // Used for importing comparison builds (from permalinked comparison) - var defaultFacets = [9,6,4,1,3,2]; // Reverse order of Armour, Shields, Speed, Jump Range, Cargo Capacity, Cost + var defaultFacets = [9, 6, 4, 1, 3, 2]; // Reverse order of Armour, Shields, Speed, Jump Range, Cargo Capacity, Cost var facets = $scope.facets = angular.copy(ShipFacets); + var shipId, buildName, comparisonData; /** * Add an existing build to the comparison. The build must be saved locally. - * @param {string} shipId The unique ship key/id - * @param {string} buildName The build name + * @param {string} id The unique ship key/id + * @param {string} name The build name */ - $scope.addBuild = function (shipId, buildName, code) { - var data = Ships[shipId]; // Get ship properties - code = code? code : Persist.builds[shipId][buildName]; // Retrieve build code if not passed - var b = new Ship(shipId, data.properties, data.slots); // Create a new Ship instance + $scope.addBuild = function(id, name, code) { + var data = Ships[id]; // Get ship properties + code = code ? code : Persist.builds[id][name]; // Retrieve build code if not passed + var b = new Ship(id, data.properties, data.slots); // Create a new Ship instance Serializer.toShip(b, code); // Populate components from code // Extend ship instance and add properties below - b.buildName = buildName; + b.buildName = name; b.code = code; b.pctRetracted = b.powerRetracted / b.powerAvailable; b.pctDeployed = b.powerDeployed / b.powerAvailable; $scope.builds.push(b); // Add ship build to comparison $scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc); // Resort - _.remove($scope.unusedBuilds, function (b) { // Remove from unused builds - return b.id == shipId && b.buildName == buildName; + _.remove($scope.unusedBuilds, function(o) { // Remove from unused builds + return o.id == id && o.buildName == name; }); $scope.saved = false; }; /** * Removes a build from the comparison - * @param {string} shipId The unique ship key/id - * @param {string} buildName The build name + * @param {string} id The unique ship key/id + * @param {string} name The build name */ - $scope.removeBuild = function (shipId, buildName) { - _.remove($scope.builds, function (b) { - if (b.id == shipId && b.buildName == buildName) { - $scope.unusedBuilds.push({id: shipId, buildName: buildName, name: b.name}); // Add build back to unused builds + $scope.removeBuild = function(id, name) { + _.remove($scope.builds, function(s) { + if (s.id == id && s.buildName == name) { + $scope.unusedBuilds.push({ id: id, buildName: name, name: s.name }); // Add build back to unused builds return true; } return false; @@ -54,7 +55,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' * Toggles the selected the set of facets used in the comparison * @param {number} i The index of the facet in facets */ - $scope.toggleFacet = function (i) { + $scope.toggleFacet = function(i) { facets[i].active = !facets[i].active; $scope.tblUpdate = !$scope.tblUpdate; // Simple switch to trigger the table to update $scope.saved = false; @@ -64,12 +65,12 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' * Click handler for sorting by facets in the table * @param {object} e Event object */ - $scope.handleClick = function (e) { + $scope.handleClick = function(e) { var elem = angular.element(e.target); - if(elem.attr('prop')) { // Get component ID + if (elem.attr('prop')) { // Get component ID $scope.sort(elem.attr('prop')); - } - else if (elem.attr('del')) { // Delete index + + } else if (elem.attr('del')) { // Delete index $scope.removeBuild(elem.attr('del')); } }; @@ -78,8 +79,8 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' * Sort the comparison array based on the selected facet / ship property * @param {string} key Ship property */ - $scope.sort = function (key) { - $scope.desc = ($scope.predicate == key)? !$scope.desc : $scope.desc; + $scope.sort = function(key) { + $scope.desc = $scope.predicate == key ? !$scope.desc : $scope.desc; $scope.predicate = key; $scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc); }; @@ -94,12 +95,12 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' } var selectedFacets = []; facets.forEach(function(f) { - if(f.active) { + if (f.active) { selectedFacets.unshift(f.index); } }); Persist.saveComparison($scope.name, $scope.builds, selectedFacets); - $state.go('compare', {name: $scope.name}, {location:'replace', notify:false}); + $state.go('compare', { name: $scope.name }, { location: 'replace', notify: false }); $scope.saved = true; }; @@ -108,7 +109,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' */ $scope.delete = function() { Persist.deleteComparison($scope.name); - $state.go('compare', {name: null}, {location:'replace', reload:true}); + $state.go('compare', { name: null }, { location: 'replace', reload: true }); }; /** @@ -134,7 +135,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' */ $scope.permalink = function(e) { e.stopPropagation(); - $state.go('modal.link', {url: genPermalink()}); + $state.go('modal.link', { url: genPermalink() }); }; /** @@ -147,14 +148,14 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' e.stopPropagation(); // Make a request to goo.gl to shorten the URL, returns a promise var promise = Utils.shortenUrl( genPermalink()).then( - function (shortUrl) { + function(shortUrl) { return Utils.comparisonBBCode(facets, $scope.builds, shortUrl); }, - function (e) { - return 'Error - ' + e.statusText; + function(err) { + return 'Error - ' + err.statusText; } ); - $state.go('modal.export', {promise: promise, title:'Forum BBCode'}); + $state.go('modal.export', { promise: promise, title: 'Forum BBCode' }); }; /** @@ -164,7 +165,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' function genPermalink() { var selectedFacets = []; facets.forEach(function(f) { - if(f.active) { + if (f.active) { selectedFacets.unshift(f.index); } }); @@ -175,7 +176,7 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' $scope.predicate, $scope.desc ); - return $state.href('comparison', {code: code}, {absolute:true}); + return $state.href('comparison', { code: code }, { absolute: true }); } /* Event listeners */ @@ -184,7 +185,6 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' }); /* Initialization */ - var shipId, buildName, comparisonData; if ($scope.compareMode) { if ($scope.name == 'all') { for (shipId in Persist.builds) { @@ -195,13 +195,13 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' } else { for (shipId in Persist.builds) { for (buildName in Persist.builds[shipId]) { - $scope.unusedBuilds.push({id: shipId, buildName: buildName, name: Ships[shipId].properties.name}); + $scope.unusedBuilds.push({ id: shipId, buildName: buildName, name: Ships[shipId].properties.name }); } } comparisonData = Persist.getComparison($scope.name); if (comparisonData) { defaultFacets = comparisonData.facets; - comparisonData.builds.forEach(function (b) { + comparisonData.builds.forEach(function(b) { $scope.addBuild(b.shipId, b.buildName); }); $scope.saved = true; @@ -214,9 +214,9 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' $scope.name = comparisonData.n; $scope.predicate = comparisonData.p; $scope.desc = comparisonData.d; - comparisonData.b.forEach(function (build) { + comparisonData.b.forEach(function(build) { $scope.addBuild(build.s, build.n, build.c); - if(!$scope.importObj[build.s]) { + if (!$scope.importObj[build.s]) { $scope.importObj[build.s] = {}; } $scope.importObj[build.s][build.n] = build.c; @@ -226,9 +226,9 @@ angular.module('app').controller('ComparisonController', ['lodash', '$rootScope' } } // Replace fmt with actual format function as defined in rootScope and retain original index - facets.forEach(function(f,i) { f.fmt = $rootScope[f.fmt]; f.index = i; }); + facets.forEach(function(f, i) { f.fmt = $rootScope[f.fmt]; f.index = i; }); // Remove default facets, mark as active, and add them back in selected order - _.pullAt(facets, defaultFacets).forEach(function (f) { f.active = true; facets.unshift(f); }); + _.pullAt(facets, defaultFacets).forEach(function(f) { f.active = true; facets.unshift(f); }); $scope.builds = $filter('orderBy')($scope.builds, $scope.predicate, $scope.desc); -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-delete.js b/app/js/controllers/controller-delete.js index 2d500916..5aec906e 100755 --- a/app/js/controllers/controller-delete.js +++ b/app/js/controllers/controller-delete.js @@ -1,7 +1,7 @@ -angular.module('app').controller('DeleteController', ['$scope', 'Persist', function ($scope, Persist) { - $scope.deleteAll = function () { +angular.module('app').controller('DeleteController', ['$scope', 'Persist', function($scope, Persist) { + $scope.deleteAll = function() { Persist.deleteAll(); $scope.$parent.dismiss(); }; -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-error.js b/app/js/controllers/controller-error.js index 4274c89a..b1f19cf1 100755 --- a/app/js/controllers/controller-error.js +++ b/app/js/controllers/controller-error.js @@ -1,5 +1,5 @@ angular.module('app') -.controller('ErrorController', ['$window','$rootScope','$scope','$stateParams', '$location', function ($window, $rootScope, $scope, $p, $location) { +.controller('ErrorController', ['$window', '$rootScope', '$scope', '$stateParams', '$location', function($window, $rootScope, $scope, $p, $location) { $rootScope.title = 'Error'; $scope.path = $location.path(); $scope.type = $p.type || 'unknown'; @@ -21,9 +21,9 @@ angular.module('app') $scope.details = $p.details; break; default: - $scope.msgPre = "Uh, Jameson, we have a problem.."; + $scope.msgPre = 'Uh, Jameson, we have a problem..'; $scope.errorMessage = $p.message; $scope.details = $p.details; } -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-export.js b/app/js/controllers/controller-export.js index dd9c44f6..bc10c3f3 100755 --- a/app/js/controllers/controller-export.js +++ b/app/js/controllers/controller-export.js @@ -1,18 +1,18 @@ -angular.module('app').controller('ExportController', ['$scope', '$stateParams', function ($scope, $stateParams) { +angular.module('app').controller('ExportController', ['$scope', '$stateParams', function($scope, $stateParams) { $scope.title = $stateParams.title || 'Export'; if ($stateParams.promise) { $scope.export = 'Generating...'; - $stateParams.promise.then(function(data){ + $stateParams.promise.then(function(data) { $scope.export = data; }); } else { $scope.export = angular.toJson($stateParams.data, true); } - $scope.onTextClick = function ($event) { + $scope.onTextClick = function($event) { $event.target.select(); }; -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-import.js b/app/js/controllers/controller-import.js index f1971a7a..88f10620 100755 --- a/app/js/controllers/controller-import.js +++ b/app/js/controllers/controller-import.js @@ -1,4 +1,4 @@ -angular.module('app').controller('ImportController', ['$scope', '$stateParams', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function ($scope, $stateParams, Ships, Ship, Persist, Serializer) { +angular.module('app').controller('ImportController', ['$scope', '$stateParams', 'ShipsDB', 'Ship', 'Persist', 'Serializer', function($scope, $stateParams, Ships, Ship, Persist, Serializer) { $scope.jsonValid = false; $scope.importData = null; $scope.errorMsg = null; @@ -21,7 +21,7 @@ angular.module('app').controller('ImportController', ['$scope', '$stateParams', return; } - if(typeof importObj != 'object') { + if (typeof importObj != 'object') { $scope.errorMsg = 'Must be an object!'; return; } @@ -48,7 +48,7 @@ angular.module('app').controller('ImportController', ['$scope', '$stateParams', } } } else { - $scope.errorMsg = '"' + shipId + '" is not a valid Ship Id!'; + $scope.errorMsg = '"' + shipId + '"" is not a valid Ship Id!'; return; } $scope.builds = importObj.builds; @@ -57,7 +57,7 @@ angular.module('app').controller('ImportController', ['$scope', '$stateParams', $scope.jsonValid = true; }; - $scope.hasBuild = function (shipId, name) { + $scope.hasBuild = function(shipId, name) { return Persist.getBuild(shipId, name) !== null; }; @@ -98,4 +98,4 @@ angular.module('app').controller('ImportController', ['$scope', '$stateParams', } -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-link.js b/app/js/controllers/controller-link.js index 75041907..59c4690c 100755 --- a/app/js/controllers/controller-link.js +++ b/app/js/controllers/controller-link.js @@ -1,16 +1,16 @@ -angular.module('app').controller('LinkController', ['$scope', 'Utils', '$stateParams', function ($scope, Utils, $stateParams) { +angular.module('app').controller('LinkController', ['$scope', 'Utils', '$stateParams', function($scope, Utils, $stateParams) { $scope.url = $stateParams.url; $scope.shortenedUrl = 'Shortening...'; - $scope.onTextClick = function ($event) { + $scope.onTextClick = function($event) { $event.target.select(); }; Utils.shortenUrl($scope.url) .then(function(url) { $scope.shortenedUrl = url; - },function(e) { + }, function(e) { $scope.shortenedUrl = 'Error - ' + e.statusText; }); -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-modal.js b/app/js/controllers/controller-modal.js index 203d6155..c73135ad 100755 --- a/app/js/controllers/controller-modal.js +++ b/app/js/controllers/controller-modal.js @@ -1,9 +1,9 @@ -angular.module('app').controller('ModalController', ['$rootScope','$scope', '$state', function ($rootScope, $scope, $state) { +angular.module('app').controller('ModalController', ['$rootScope', '$scope', '$state', function($rootScope, $scope, $state) { $scope.dismiss = function() { if ($rootScope.prevState) { var state = $rootScope.prevState; - $state.go(state.name, state.params, {location: 'replace', reload: false}); + $state.go(state.name, state.params, { location: 'replace', reload: false }); } else { $state.go('shipyard'); } @@ -11,4 +11,4 @@ angular.module('app').controller('ModalController', ['$rootScope','$scope', '$st $scope.$on('close', $scope.dismiss); -}]); \ No newline at end of file +}]); diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 1159e4a1..41b47479 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -1,4 +1,4 @@ -angular.module('app').controller('OutfitController', ['$window','$rootScope','$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', function ($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist) { +angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist) { var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance var win = angular.element($window); // Angularized window object for event triggering @@ -12,7 +12,7 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s } $scope.buildName = $p.bn; - $rootScope.title = ship.name + ($scope.buildName? ' - ' + $scope.buildName : ''); + $rootScope.title = ship.name + ($scope.buildName ? ' - ' + $scope.buildName : ''); $scope.ship = ship; $scope.pp = ship.common[0]; // Power Plant $scope.th = ship.common[1]; // Thruster @@ -49,11 +49,11 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s $scope.jrChart = { labels: { xAxis: { - title:'Cargo', + title: 'Cargo', unit: 'T' }, yAxis: { - title:'Jump Range', + title: 'Jump Range', unit: 'LY' } }, @@ -90,7 +90,7 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s if (id) { if (id == 'empty') { ship.use(slot, null, null); - } else if(type == 'h') { + } else if (type == 'h') { ship.use(slot, id, Components.hardpoints(id)); } else if (type == 'c') { ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); @@ -142,13 +142,13 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s */ $scope.deleteBuild = function() { Persist.deleteBuild(ship.id, $scope.buildName); - $state.go('outfit', {shipId: ship.id, code: null, bn: null}, {location:'replace', reload:true}); + $state.go('outfit', { shipId: ship.id, code: null, bn: null }, { location: 'replace', reload: true }); }; /** * On build name change, retrieve the existing saved code if there is one */ - $scope.bnChange = function(){ + $scope.bnChange = function() { $scope.savedCode = Persist.getBuild(ship.id, $scope.buildName); }; @@ -165,13 +165,13 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s * @param {[type]} key [description] * @return {[type]} [description] */ - $scope.sortCost = function (key) { - $scope.costDesc = ($scope.costPredicate == key)? !$scope.costDesc : $scope.costDesc; + $scope.sortCost = function(key) { + $scope.costDesc = $scope.costPredicate == key ? !$scope.costDesc : $scope.costDesc; $scope.costPredicate = key; }; - $scope.sortPwr = function (key) { - $scope.pwrDesc = ($scope.pwrPredicate == key)? !$scope.pwrDesc : $scope.pwrDesc; + $scope.sortPwr = function(key) { + $scope.pwrDesc = $scope.pwrPredicate == key ? !$scope.pwrDesc : $scope.pwrDesc; $scope.pwrPredicate = key; }; @@ -185,37 +185,37 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s updateState(); }; - $scope.incPriority = function (c) { + $scope.incPriority = function(c) { if (ship.changePriority(c, c.priority + 1)) { $scope.code = Serializer.fromShip(ship); updateState(); } }; - $scope.decPriority = function (c) { + $scope.decPriority = function(c) { if (ship.changePriority(c, c.priority - 1)) { $scope.code = Serializer.fromShip(ship); updateState(); } }; - $scope.fuelChange = function (fuel) { + $scope.fuelChange = function(fuel) { $scope.fuel = fuel; win.triggerHandler('render'); }; - $scope.statusRetracted = function (slot) { + $scope.statusRetracted = function(slot) { return ship.getSlotStatus(slot, false); }; - $scope.statusDeployed = function (slot) { + $scope.statusDeployed = function(slot) { return ship.getSlotStatus(slot, true); }; // Utilify functions function updateState() { - $state.go('outfit', {shipId: ship.id, code: $scope.code, bn: $scope.buildName}, {location:'replace', notify:false}); + $state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false }); $scope.jrSeries.xMax = ship.cargoCapacity; $scope.jrSeries.yMax = ship.jumpRangeWithMass(ship.unladenMass); $scope.jrSeries.mass = ship.unladenMass; @@ -223,7 +223,7 @@ angular.module('app').controller('OutfitController', ['$window','$rootScope','$s } // Hide any open menu/slot/etc if the background is clicked - $scope.$on('close', function () { + $scope.$on('close', function() { $scope.selectedSlot = null; }); diff --git a/app/js/controllers/controller-shipyard.js b/app/js/controllers/controller-shipyard.js index 78751edc..1cc5477f 100755 --- a/app/js/controllers/controller-shipyard.js +++ b/app/js/controllers/controller-shipyard.js @@ -1,4 +1,4 @@ -angular.module('app').controller('ShipyardController', ['$rootScope', 'ShipsDB', function ($rootScope, ships) { +angular.module('app').controller('ShipyardController', ['$rootScope', 'ShipsDB', function($rootScope, ships) { $rootScope.title = 'Coriolis'; $rootScope.ships = ships; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-area-chart.js b/app/js/directives/directive-area-chart.js index a7222eb7..9c24936b 100755 --- a/app/js/directives/directive-area-chart.js +++ b/app/js/directives/directive-area-chart.js @@ -1,9 +1,7 @@ -angular.module('app').directive('areaChart', ['$window', function ($window) { - - +angular.module('app').directive('areaChart', ['$window', function($window) { return { restrict: 'A', - scope:{ + scope: { config: '=', series: '=' }, @@ -11,64 +9,64 @@ angular.module('app').directive('areaChart', ['$window', function ($window) { var series = scope.series, config = scope.config, labels = config.labels, - margin = {top: 15, right: 15, bottom: 35, left: 60}, + margin = { top: 15, right: 15, bottom: 35, left: 60 }, fmt = d3.format('.3r'), fmtLong = d3.format('.2f'), func = series.func, drag = d3.behavior.drag(), dragging = false, // Define Axes - xAxis = d3.svg.axis().outerTickSize(0).orient("bottom").tickFormat(d3.format('.2r')), - yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient("left").tickFormat(fmt), + xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')), + yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt), x = d3.scale.linear(), y = d3.scale.linear(); // Create chart - var svg = d3.select(element[0]).append("svg"); - var vis = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + var svg = d3.select(element[0]).append('svg'); + var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); // Define Area var area = d3.svg.area(); - var gradient = vis.append("defs") - .append("linearGradient") - .attr("id", "gradient") - .attr("x1", "0%").attr("y1", "0%") - .attr("x2", "100%").attr("y2", "100%") - .attr("spreadMethod", "pad"); - gradient.append("stop") - .attr("offset", "0%") - .attr("stop-color", "#ff8c0d") - .attr("stop-opacity", 1); - gradient.append("stop") - .attr("offset", "100%") - .attr("stop-color", "#ff3b00") - .attr("stop-opacity", 1); + var gradient = vis.append('defs') + .append('linearGradient') + .attr('id', 'gradient') + .attr('x1', '0%').attr('y1', '0%') + .attr('x2', '100%').attr('y2', '100%') + .attr('spreadMethod', 'pad'); + gradient.append('stop') + .attr('offset', '0%') + .attr('stop-color', '#ff8c0d') + .attr('stop-opacity', 1); + gradient.append('stop') + .attr('offset', '100%') + .attr('stop-color', '#ff3b00') + .attr('stop-opacity', 1); // Create Y Axis SVG Elements - var yTxt = vis.append("g").attr("class", "y axis") - .append("text") - .attr("transform", "rotate(-90)") - .attr("y", -50) - .attr("dy", ".1em") - .style("text-anchor", "middle") + var yTxt = vis.append('g').attr('class', 'y axis') + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50) + .attr('dy', '.1em') + .style('text-anchor', 'middle') .text(labels.yAxis.title + ' (' + labels.yAxis.unit + ')'); // Create X Axis SVG Elements - var xLbl = vis.append("g").attr("class", "x axis"); - var xTxt = xLbl.append("text") - .attr("y", 30) - .attr("dy", ".1em") - .style("text-anchor", "middle") + var xLbl = vis.append('g').attr('class', 'x axis'); + var xTxt = xLbl.append('text') + .attr('y', 30) + .attr('dy', '.1em') + .style('text-anchor', 'middle') .text(labels.xAxis.title + ' (' + labels.xAxis.unit + ')'); // Create and Add tooltip - var tip = vis.append("g").style("display", "none"); - tip.append("rect").attr("width","4em").attr("height", "2em").attr("x", "0.5em").attr("y","-1em").attr("class","tip"); - tip.append("circle") - .attr("class", "marker") - .attr("r", 4); - tip.append("text").attr("class", 'label x').attr("y", "-0.25em"); - tip.append("text").attr("class", 'label y').attr("y", '0.85em'); + var tip = vis.append('g').style('display', 'none'); + tip.append('rect').attr('width', '4em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); + tip.append('circle') + .attr('class', 'marker') + .attr('r', 4); + tip.append('text').attr('class', 'label x').attr('y', '-0.25em'); + tip.append('text').attr('class', 'label y').attr('y', '0.85em'); /** * Watch for changes in the series data (mass changes, etc) @@ -87,35 +85,35 @@ angular.module('app').directive('areaChart', ['$window', function ($window) { var yVal = func(series.xMin); data.push([ series.xMin, yVal ]); data.push([ series.xMin, yVal ]); - area.x(function(d,i) { return i * w; }).y0(h).y1(function(d) { return y(d[1]); }); + area.x(function(d, i) { return i * w; }).y0(h).y1(function(d) { return y(d[1]); }); } else { - for (var d = series.xMin; d <= series.xMax; d += 1) { - data.push([ d, func(d) ]); + for (var val = series.xMin; val <= series.xMax; val += 1) { + data.push([ val, func(val) ]); } area.x(function(d) { return x(d[0]); }).y0(h).y1(function(d) { return y(d[1]); }); } // Update Chart Size - svg.attr("width", width).attr("height", height); + svg.attr('width', width).attr('height', height); // Update domain and scale for axes; x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true); xAxis.scale(x); - xLbl.attr("transform", "translate(0," + h + ")"); - xTxt.attr("x", w/2); + xLbl.attr('transform', 'translate(0,' + h + ')'); + xTxt.attr('x', w / 2); y.range([h, 0]).domain([series.yMin, series.yMax]); yAxis.scale(y); - yTxt.attr("x", -h/2); - vis.selectAll(".y.axis").call(yAxis); - vis.selectAll(".x.axis").call(xAxis); + yTxt.attr('x', -h / 2); + vis.selectAll('.y.axis').call(yAxis); + vis.selectAll('.x.axis').call(xAxis); // Remove existing elements vis.selectAll('path.area').remove(); - vis.insert("path",':first-child') // Area/Path to appear behind everything else + vis.insert('path', ':first-child') // Area/Path to appear behind everything else .datum(data) - .attr("class", "area") + .attr('class', 'area') .attr('fill', 'url(#gradient)') - .attr("d", area) + .attr('d', area) .on('mouseover', showTip) .on('mouseout', hideTip) .on('mousemove', moveTip) @@ -127,7 +125,7 @@ angular.module('app').directive('areaChart', ['$window', function ($window) { moveTip.call(this); showTip(); }) - .on("dragend", function() { + .on('dragend', function() { dragging = false; hideTip(); }) @@ -135,20 +133,20 @@ angular.module('app').directive('areaChart', ['$window', function ($window) { } function showTip() { - tip.style("display", null); + tip.style('display', null); } function hideTip() { if (!dragging) { - tip.style("display", "none"); + tip.style('display', 'none'); } } function moveTip() { var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.75); - tip.attr("transform", "translate(" + x(x0) + "," + y(y0) + ")"); - tip.selectAll('rect').attr("x", flip? '-4.5em' : "0.5em").style("text-anchor", flip? 'end' : 'start'); - tip.selectAll('text.label').attr("x", flip? "-1em" : "1em").style("text-anchor", flip? 'end' : 'start'); + tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')'); + tip.selectAll('rect').attr('x', flip ? '-4.5em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start'); tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit); tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit); } @@ -159,4 +157,4 @@ angular.module('app').directive('areaChart', ['$window', function ($window) { } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-bar-chart.js b/app/js/directives/directive-bar-chart.js index da5e91a0..eab99af9 100755 --- a/app/js/directives/directive-bar-chart.js +++ b/app/js/directives/directive-bar-chart.js @@ -1,10 +1,10 @@ -angular.module('app').directive('barChart', ['$window', function ($window) { +angular.module('app').directive('barChart', ['$window', function($window) { - function bName (build) { + function bName(build) { return build.buildName + '\n' + build.name; } - var insertLinebreaks = function (d) { + function insertLinebreaks(d) { var el = d3.select(this); var words = d.split('\n'); el.text('').attr('y', -6); @@ -14,11 +14,11 @@ angular.module('app').directive('barChart', ['$window', function ($window) { tspan.attr('x', -9).attr('dy', 12); } } - }; + } return { restrict: 'A', - scope:{ + scope: { data: '=', facet: '=' }, @@ -28,7 +28,7 @@ angular.module('app').directive('barChart', ['$window', function ($window) { fmt = scope.facet.fmt, properties = scope.facet.props, unit = scope.facet.unit, - margin = {top: 10, right: 20, bottom: 35, left: 150}, + margin = { top: 10, right: 20, bottom: 35, left: 150 }, y0 = d3.scale.ordinal(), y1 = d3.scale.ordinal(), x = d3.scale.linear(), @@ -43,7 +43,7 @@ angular.module('app').directive('barChart', ['$window', function ($window) { var tip = d3.tip() .attr('class', 'd3-tip') .html(function(property, propertyIndex) { - return (labels? (labels[propertyIndex] + ': ') : '') + fmt(property.value) + ' ' + unit; + return (labels ? (labels[propertyIndex] + ': ') : '') + fmt(property.value) + ' ' + unit; }); vis.call(tip); @@ -52,13 +52,13 @@ angular.module('app').directive('barChart', ['$window', function ($window) { vis.append('g').attr('class', 'y axis'); vis.selectAll('g.y.axis g text').each(insertLinebreaks); // Create X Axis SVG Elements - var xAxisLbl = vis.append('g') + var xAxisLbl = vis.append('g') .attr('class', 'x axis') .append('text') .attr('y', 30) .attr('dy', '.1em') .style('text-anchor', 'middle') - .text(scope.facet.title + (unit? (' (' + unit + ')') : '')); + .text(scope.facet.title + (unit ? (' (' + unit + ')') : '')); /** @@ -84,11 +84,11 @@ angular.module('app').directive('barChart', ['$window', function ($window) { // Update X & Y Axis x.range([0, w]).domain([0, maxVal]); - y0.domain(data.map(bName)).rangeRoundBands([0, h],0.3); + y0.domain(data.map(bName)).rangeRoundBands([0, h], 0.3); y1.domain(properties).rangeRoundBands([0, y0.rangeBand()]); vis.selectAll('.y.axis').call(yAxis); vis.selectAll('.x.axis').attr('transform', 'translate(0,' + h + ')').call(xAxis); - xAxisLbl.attr('x', w/2); + xAxisLbl.attr('x', w / 2); // Update Y-Axis labels vis.selectAll('g.y.axis g text').each(insertLinebreaks); @@ -102,13 +102,13 @@ angular.module('app').directive('barChart', ['$window', function ($window) { .data(function(build) { var o = []; for (var i = 0; i < properties.length; i++) { - o.push({name: properties[i], value:build[properties[i]]}); + o.push({ name: properties[i], value: build[properties[i]] }); } return o; }) .enter().append('rect') .attr('height', y1.rangeBand()) - .attr('x',0) + .attr('x', 0) .attr('y', function(d) {return y1(d.name); }) .attr('width', function(d) { return x(d.value); }) .on('mouseover', tip.show) @@ -124,4 +124,4 @@ angular.module('app').directive('barChart', ['$window', function ($window) { } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-comparison-table.js b/app/js/directives/directive-comparison-table.js index a47550a1..7219b988 100755 --- a/app/js/directives/directive-comparison-table.js +++ b/app/js/directives/directive-comparison-table.js @@ -1,4 +1,4 @@ -angular.module('app').directive('comparisonTable', ['$state', function ($state) { +angular.module('app').directive('comparisonTable', ['$state', function($state) { function tblHeader(facets) { var r1 = ['ShipBuild']; @@ -8,17 +8,17 @@ angular.module('app').directive('comparisonTable', ['$state', function ($state) var f = facets[i]; var p = f.props; var pl = p.length; - r1.push('' , f.lbls[j], ''); + r2.push('', f.lbls[j], ''); } } - r1.push('>', f.title ,''); + r1.push('>', f.title, ''); } } r1.push(''); @@ -30,16 +30,16 @@ angular.module('app').directive('comparisonTable', ['$state', function ($state) function tblBody(facets, builds) { var body = []; - if(builds.length === 0) { + if (builds.length === 0) { return 'No builds added to comparison!'); - var href = $state.href('outfit',{shipId: b.id, code: b.code, bn: b.buildName}); - body.push('', b.name,''); - body.push('', b.buildName,''); + var href = $state.href('outfit', { shipId: b.id, code: b.code, bn: b.buildName }); + body.push('', b.name, ''); + body.push('', b.buildName, ''); for (var j = 0, fl = facets.length; j < fl; j++) { if (facets[j].active) { @@ -59,13 +59,13 @@ angular.module('app').directive('comparisonTable', ['$state', function ($state) return { restrict: 'A', - link: function (scope, element) { + link: function(scope, element) { var header = angular.element(''); var body = angular.element(''); element.append(header); element.append(body); - var updateAll = function (){ + var updateAll = function() { header.html(tblHeader(scope.facets)); body.html(tblBody(scope.facets, scope.builds)); }; @@ -77,4 +77,4 @@ angular.module('app').directive('comparisonTable', ['$state', function ($state) }); } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-component-select.js b/app/js/directives/directive-component-select.js index 2f0b851b..b4070927 100755 --- a/app/js/directives/directive-component-select.js +++ b/app/js/directives/directive-component-select.js @@ -1,4 +1,4 @@ -angular.module('app').directive('componentSelect', function () { +angular.module('app').directive('componentSelect', function() { // Generting the HTML in this manner is MUCH faster than using an angular template. @@ -8,42 +8,42 @@ angular.module('app').directive('componentSelect', function () { var o = opts[i]; var id = o.id || (o.class + o.rating); // Common components' ID is their class and rating - if(i > 0 && opts.length > 3 && o.class != prevClass && (!o.grp || o.rating != prevRating || o.mode)) { + if (i > 0 && opts.length > 3 && o.class != prevClass && (!o.grp || o.rating != prevRating || o.mode)) { list.push('
'); } - list.push('
  • o.maxmass)? ' disabled"' : '" cpid="', id, '">'); + list.push((o.maxmass && mass > o.maxmass) ? ' disabled"' : '" cpid="', id, '">'); - if(o.mode) { - list.push(' '); + if (o.mode) { + list.push(' '); } list.push(o.class, o.rating); - if(o.missile) { + if (o.missile) { list.push('/' + o.missile); } - if(o.name) { + if (o.name) { list.push(' ' + o.name); } list.push('
  • '); prevClass = o.class; - prevRating= o.rating; + prevRating = o.rating; } } return { restrict: 'A', - scope:{ + scope: { opts: '=', // Component Options object groups: '=', // Groups of Component Options mass: '=', // Current ship unladen mass @@ -57,13 +57,13 @@ angular.module('app').directive('componentSelect', function () { var groups = scope.groups; var mass = scope.mass || 0; - if(groups) { + if (groups) { // At present time slots with grouped options (Hardpoints and Internal) can be empty list.push('
    EMPTY
    '); for (var g in groups) { var grp = groups[g]; var grpCode = grp[Object.keys(grp)[0]].grp; // Nasty operation to get the grp property of the first/any single component - list.push('
    ', g, '
      '); + list.push('
      ', g, '
        '); appendGroup(list, grp, cid, mass); list.push('
      '); } @@ -77,9 +77,9 @@ angular.module('app').directive('componentSelect', function () { // If groups are present and a component is already selectd if (groups && component && component.grp) { var groupElement = angular.element(document.getElementById(component.grp)); - var parentElem = element[0].parentElement; + var parentElem = element[0].parentElement; parentElem.scrollTop = groupElement[0].offsetTop; // Scroll to currently selected group } } }; -}); \ No newline at end of file +}); diff --git a/app/js/directives/directive-header.js b/app/js/directives/directive-header.js index 1d61b560..c6beeebe 100755 --- a/app/js/directives/directive-header.js +++ b/app/js/directives/directive-header.js @@ -1,10 +1,10 @@ -angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Persist', 'ShipsDB', function (_, $rootScope, Persist, ships) { +angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Persist', 'ShipsDB', function(_, $rootScope, Persist, ships) { return { restrict: 'E', templateUrl: 'views/_header.html', scope: true, - link: function (scope) { + link: function(scope) { scope.openedMenu = null; scope.ships = ships; scope.allBuilds = Persist.builds; @@ -15,22 +15,22 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers // Insurance options and management here for now. $rootScope.insurance = { opts: [ - { name:'Standard', pct: 0.05 }, - { name:'Alpha', pct: 0.025 }, - { name:'Beta', pct: 0.035 } + { name: 'Standard', pct: 0.05 }, + { name: 'Alpha', pct: 0.025 }, + { name: 'Beta', pct: 0.035 } ] }; var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance()); - $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1? insIndex : 0]; + $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0]; // Close menus if a navigation change event occurs - $rootScope.$on('$stateChangeStart',function(){ + $rootScope.$on('$stateChangeStart', function() { scope.openedMenu = null; }); // Listen to close event to close opened menus or modals - $rootScope.$on('close', function () { + $rootScope.$on('close', function() { scope.openedMenu = null; $rootScope.showAbout = false; }); @@ -38,13 +38,13 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers /** * Save selected insurance option */ - scope.updateInsurance = function(){ + scope.updateInsurance = function() { Persist.setInsurance($rootScope.insurance.current.name); }; - scope.openMenu = function (e, menu) { + scope.openMenu = function(e, menu) { e.stopPropagation(); - if(menu == scope.openedMenu) { + if (menu == scope.openedMenu) { scope.openedMenu = null; return; } @@ -63,7 +63,7 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers $rootScope.showAbout = true; }; - $rootScope.hideAbout = function (){ + $rootScope.hideAbout = function() { $rootScope.showAbout = false; }; @@ -72,4 +72,4 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers }); } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-power-bands.js b/app/js/directives/directive-power-bands.js index 2dd55c70..f680c064 100644 --- a/app/js/directives/directive-power-bands.js +++ b/app/js/directives/directive-power-bands.js @@ -1,12 +1,12 @@ -angular.module('app').directive('powerBands', ['$window', function ($window) { +angular.module('app').directive('powerBands', ['$window', function($window) { return { restrict: 'A', - scope:{ + scope: { bands: '=', available: '=' }, link: function(scope, element) { - var margin = {top: 20, right: 130, bottom: 20, left: 40}, + var margin = { top: 20, right: 130, bottom: 20, left: 40 }, barHeight = 20, innerHeight = (barHeight * 2) + 3, height = innerHeight + margin.top + margin.bottom + 1, @@ -25,11 +25,11 @@ angular.module('app').directive('powerBands', ['$window', function ($window) { // Create Y Axis SVG Elements vis.append('g').attr('class', 'watt axis'); vis.append('g').attr('class', 'pct axis'); - vis.append("text").attr('x', -35).attr('y', 16).attr('class','primary').text('RET'); - vis.append("text").attr('x', -35).attr('y', barHeight + 18).attr('class','primary').text('DEP'); + vis.append('text').attr('x', -35).attr('y', 16).attr('class', 'primary').text('RET'); + vis.append('text').attr('x', -35).attr('y', barHeight + 18).attr('class', 'primary').text('DEP'); - var retLbl = vis.append("text").attr('y', 16); - var depLbl = vis.append("text").attr('y', barHeight + 18); + var retLbl = vis.append('text').attr('y', 16); + var depLbl = vis.append('text').attr('y', barHeight + 18); // Watch for changes to data and events scope.$watchCollection('available', render); @@ -61,40 +61,41 @@ angular.module('app').directive('powerBands', ['$window', function ($window) { retLbl .attr('x', w + 5 ) - .attr('class',maxBand.retractedSum > available? 'warning': 'primary') - .text(wattFmt(Math.max(0,maxBand.retractedSum)) + ' (' + pctFmt(Math.max(0,maxBand.retractedSum / available)) + ')'); + .attr('class', maxBand.retractedSum > available ? 'warning' : 'primary') + .text(wattFmt(Math.max(0, maxBand.retractedSum)) + ' (' + pctFmt(Math.max(0, maxBand.retractedSum / available)) + ')'); + depLbl .attr('x', w + 5 ) - .attr('class',maxBand.deployedSum > available? 'warning': 'primary') - .text(wattFmt(Math.max(0,maxBand.deployedSum)) + ' (' + pctFmt(Math.max(0,maxBand.deployedSum / available)) + ')'); + .attr('class', maxBand.deployedSum > available ? 'warning' : 'primary') + .text(wattFmt(Math.max(0, maxBand.deployedSum)) + ' (' + pctFmt(Math.max(0, maxBand.deployedSum / available)) + ')'); - retracted.selectAll("rect").data(bands).enter().append("rect") - .attr("height", barHeight) - .attr("width", function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) - .attr("x", function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) + retracted.selectAll('rect').data(bands).enter().append('rect') + .attr('height', barHeight) + .attr('width', function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) + .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) .attr('y', 1) - .attr('class',function(d){ return (d.retractedSum > available)? 'warning' :'primary'; }); + .attr('class', function(d) { return (d.retractedSum > available) ? 'warning' : 'primary'; }); - retracted.selectAll("text").data(bands).enter().append("text") + retracted.selectAll('text').data(bands).enter().append('text') .attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted) / 2); }) .attr('y', 15) .style('text-anchor', 'middle') - .attr('class','primary-bg') - .text(function(d,i) { return bandText(d.retracted, i); }); + .attr('class', 'primary-bg') + .text(function(d, i) { return bandText(d.retracted, i); }); - deployed.selectAll("rect").data(bands).enter().append("rect") - .attr("height", barHeight) - .attr("width", function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); }) - .attr("x", function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); }) + deployed.selectAll('rect').data(bands).enter().append('rect') + .attr('height', barHeight) + .attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); }) + .attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); }) .attr('y', barHeight + 2) - .attr('class',function(d){ return (d.deployedSum > available)? 'warning' :'primary'; }); + .attr('class', function(d) { return (d.deployedSum > available) ? 'warning' : 'primary'; }); - deployed.selectAll("text").data(bands).enter().append("text") + deployed.selectAll('text').data(bands).enter().append('text') .attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); }) .attr('y', barHeight + 17) .style('text-anchor', 'middle') - .attr('class','primary-bg') - .text(function(d,i) { return bandText(d.deployed + d.retracted, i); }); + .attr('class', 'primary-bg') + .text(function(d, i) { return bandText(d.deployed + d.retracted, i); }); } @@ -110,4 +111,4 @@ angular.module('app').directive('powerBands', ['$window', function ($window) { }); } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-slider.js b/app/js/directives/directive-slider.js index 4ab39544..e175bdd5 100644 --- a/app/js/directives/directive-slider.js +++ b/app/js/directives/directive-slider.js @@ -1,33 +1,33 @@ -angular.module('app').directive('slider', ['$window', function ($window) { +angular.module('app').directive('slider', ['$window', function($window) { return { restrict: 'A', - scope:{ + scope: { max: '=', unit: '=', change: '&onChange' }, link: function(scope, element) { - var margin = {top: -10, right: 140, bottom: 0, left: 50}, + var margin = { top: -10, right: 140, bottom: 0, left: 50 }, height = 40, // Height is fixed h = height - margin.top - margin.bottom, fmt = d3.format('.2f'), pct = d3.format('.1%'), unit = scope.unit, val = scope.max, - svg = d3.select(element[0]).append("svg"), - vis = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"), - xAxis = vis.append("g").attr("class", "x slider-axis").attr("transform", "translate(0," + h / 2 + ")"), + svg = d3.select(element[0]).append('svg'), + vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'), + xAxis = vis.append('g').attr('class', 'x slider-axis').attr('transform', 'translate(0,' + h / 2 + ')'), x = d3.scale.linear(), - slider = vis.append("g").attr("class", "slider"), - filled = slider.append('path').attr('class', 'filled').attr("transform", "translate(0," + h/2 + ")"), - brush = d3.svg.brush().x(x).extent([scope.max, scope.max]).on("brush", brushed), - handle = slider.append("circle").attr("class", "handle").attr("r", '0.6em'), - lbl = slider.append("g").append("text").attr("y", h/2); + slider = vis.append('g').attr('class', 'slider'), + filled = slider.append('path').attr('class', 'filled').attr('transform', 'translate(0,' + h / 2 + ')'), + brush = d3.svg.brush().x(x).extent([scope.max, scope.max]).on('brush', brushed), + handle = slider.append('circle').attr('class', 'handle').attr('r', '0.6em'), + lbl = slider.append('g').append('text').attr('y', h / 2); slider.call(brush); - slider.select(".background").attr("height", h); - handle.attr("transform", "translate(0," + h / 2 + ")"); + slider.select('.background').attr('height', h); + handle.attr('transform', 'translate(0,' + h / 2 + ')'); /** * Watch for changes in the max, window size @@ -42,21 +42,21 @@ angular.module('app').directive('slider', ['$window', function ($window) { function render() { var width = element[0].offsetWidth, w = width - margin.left - margin.right; - svg.attr("width", width).attr("height", height); + svg.attr('width', width).attr('height', height); x.domain([0, scope.max]).range([0, w]).clamp(true); - handle.attr("cx", x(val)); + handle.attr('cx', x(val)); xAxis .call(d3.svg.axis() .scale(x) - .orient("bottom") + .orient('bottom') .tickFormat(function(d) { return d + unit; }) .tickValues([0, scope.max / 4, scope.max / 2, (3 * scope.max) / 4, scope.max]) .tickSize(0) .tickPadding(12)) - .select(".domain"); + .select('.domain'); lbl.attr('x', w + 20); slider.call(brush.extent([val, val])).call(brush.event); - slider.selectAll(".extent,.resize").remove(); + slider.selectAll('.extent,.resize').remove(); } function brushed() { @@ -65,10 +65,10 @@ angular.module('app').directive('slider', ['$window', function ($window) { val = x.invert(d3.mouse(this)[0]); brush.extent([val, val]); } - lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max)); - scope.change({val: val}); - handle.attr("cx", x(val)); - filled.attr("d", "M0,0V0H" + x(val) + "V0"); + lbl.text(fmt(val) + ' ' + unit + ' ' + pct(val / scope.max)); + scope.change({ val: val }); + handle.attr('cx', x(val)); + filled.attr('d', 'M0,0V0H' + x(val) + 'V0'); } scope.$on('$destroy', function() { @@ -77,4 +77,4 @@ angular.module('app').directive('slider', ['$window', function ($window) { } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-slot-hardpoint.js b/app/js/directives/directive-slot-hardpoint.js index b35a8b35..262cc561 100755 --- a/app/js/directives/directive-slot-hardpoint.js +++ b/app/js/directives/directive-slot-hardpoint.js @@ -1,14 +1,14 @@ -angular.module('app').directive('slotHardpoint', ['$rootScope', function ($r) { +angular.module('app').directive('slotHardpoint', ['$rootScope', function($r) { return { restrict: 'A', - scope:{ + scope: { hp: '=', size: '=', - lbl: '=', + lbl: '=' }, templateUrl: 'views/_slot-hardpoint.html', - link: function (scope) { + link: function(scope) { scope.$r = $r; } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-slot-internal.js b/app/js/directives/directive-slot-internal.js index d6aabb9d..2b67a7e8 100755 --- a/app/js/directives/directive-slot-internal.js +++ b/app/js/directives/directive-slot-internal.js @@ -1,7 +1,7 @@ -angular.module('app').directive('slotInternal', ['$rootScope', function ($r) { +angular.module('app').directive('slotInternal', ['$rootScope', function($r) { return { restrict: 'A', - scope:{ + scope: { c: '=slot', lbl: '=', fuel: '=' @@ -11,4 +11,4 @@ angular.module('app').directive('slotInternal', ['$rootScope', function ($r) { scope.$r = $r; } }; -}]); \ No newline at end of file +}]); diff --git a/app/js/factory-utils.js b/app/js/factory-utils.js index 34c90579..452772a4 100755 --- a/app/js/factory-utils.js +++ b/app/js/factory-utils.js @@ -1,17 +1,17 @@ /** * BBCode Generator functions for embedding in the Elite Dangerous Forums */ -angular.module('app').factory('Utils', ['$window','$state','$http', '$q', function ($window, $state, $http, $q) { +angular.module('app').factory('Utils', ['$window', '$state', '$http', '$q', function($window, $state, $http, $q) { var shortenAPI = 'https://www.googleapis.com/urlshortener/v1/url?key='; function shortenUrl(url) { if ($window.navigator.onLine) { - return $http.post(shortenAPI + GAPI_KEY, {longUrl:url}).then(function(response) { + return $http.post(shortenAPI + GAPI_KEY, { longUrl: url }).then(function(response) { return response.data.id; }); } else { - return $q.reject({statusText: 'Not Online'}); + return $q.reject({ statusText: 'Not Online' }); } } @@ -39,7 +39,7 @@ angular.module('app').factory('Utils', ['$window','$state','$http', '$q', functi for (i = 0; i < builds.length; i++) { b = builds[i]; //var href = $state.href('outfit',{shipId: b.id, code: b.code, bn: b.buildName}, {absolute: true}); - l.push('[tr][td]', b.name,'[/td][td]', b.buildName ,'[/td]'); + l.push('[tr][td]', b.name, '[/td][td]', b.buildName, '[/td]'); for (j = 0, fl = facets.length; j < fl; j++) { if (facets[j].active) { @@ -52,8 +52,8 @@ angular.module('app').factory('Utils', ['$window','$state','$http', '$q', functi } l.push('[/tr]\n'); } - l.push('[tr][td="align: center, colspan:',colCount,'"][size=-3]\n[url=', link,']Interactive Comparison at Coriolis.io[/url][/td][/tr]\n[/size][/table]'); - l.unshift('[table="width:', colCount * 90,',align: center"]\n[tr][th][B][COLOR=#FF8C0D]Ship[/COLOR][/B][/th][th][B][COLOR="#FF8C0D"]Build[/COLOR][/B][/th]'); + l.push('[tr][td="align: center, colspan:', colCount, '"][size=-3]\n[url=', link, ']Interactive Comparison at Coriolis.io[/url][/td][/tr]\n[/size][/table]'); + l.unshift('[table="width:', colCount * 90, ',align: center"]\n[tr][th][B][COLOR=#FF8C0D]Ship[/COLOR][/B][/th][th][B][COLOR="#FF8C0D"]Build[/COLOR][/B][/th]'); return l.join(''); } diff --git a/app/js/service-persist.js b/app/js/service-persist.js index 75ef5e5f..bf7c9e30 100755 --- a/app/js/service-persist.js +++ b/app/js/service-persist.js @@ -1,7 +1,7 @@ /** * [description] */ -angular.module('app').service('Persist', ['$window','lodash', function ($window, _) { +angular.module('app').service('Persist', ['$window', 'lodash', function($window, _) { var LS_KEY_BUILDS = 'builds'; var LS_KEY_COMPARISONS = 'comparisons'; var localStorage = $window.localStorage; @@ -19,8 +19,8 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, this.lsEnabled = false; } - this.builds = buildJson? angular.fromJson(buildJson) : {}; - this.comparisons = comparisonJson? angular.fromJson(comparisonJson) : {}; + this.builds = buildJson ? angular.fromJson(buildJson) : {}; + this.comparisons = comparisonJson ? angular.fromJson(comparisonJson) : {}; var buildCount = Object.keys(this.builds).length; this.state = { @@ -35,7 +35,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * @param {string} name The name of the build * @param {string} code The serialized code */ - this.saveBuild = function (shipId, name, code) { + this.saveBuild = function(shipId, name, code) { if (!this.lsEnabled) { return; } @@ -44,7 +44,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, this.builds[shipId] = {}; } - if(!this.builds[shipId][name]) { + if (!this.builds[shipId][name]) { this.state.buildCount++; this.state.hasBuilds = true; } @@ -62,7 +62,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * @param {string} name The name of the build * @return {string} The serialized build string. */ - this.getBuild = function (shipId, name) { + this.getBuild = function(shipId, name) { if (this.builds[shipId] && this.builds[shipId][name]) { return this.builds[shipId][name]; } @@ -76,8 +76,8 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * @param {string} shipId The unique id for a model of ship * @param {string} name The name of the build */ - this.deleteBuild = function (shipId, name) { - if(this.lsEnabled && this.builds[shipId][name]) { + this.deleteBuild = function(shipId, name) { + if (this.lsEnabled && this.builds[shipId][name]) { delete this.builds[shipId][name]; if (Object.keys(this.builds[shipId]).length === 0) { delete this.builds[shipId]; @@ -90,8 +90,8 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, var comps = this.comparisons; for (var c in comps) { for (var i = 0; i < comps[c].builds.length; i++) { // For all builds in the current comparison - if(comps[c].builds[i].shipId == shipId && comps[c].builds[i].buildName == name) { - comps[c].builds.splice(i,1); + if (comps[c].builds[i].shipId == shipId && comps[c].builds[i].buildName == name) { + comps[c].builds.splice(i, 1); break; // A build is unique ber comparison } } @@ -107,7 +107,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * @param {array} builds Array of builds * @param {array} facets Array of facet indices */ - this.saveComparison = function (name, builds, facets){ + this.saveComparison = function(name, builds, facets) { if (!this.lsEnabled) { return; } @@ -117,7 +117,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, } this.comparisons[name] = { facets: facets, - builds: _.map(builds, function (b) { return {shipId: b.id, buildName: b.buildName }; }) + builds: _.map(builds, function(b) { return { shipId: b.id, buildName: b.buildName }; }) }; localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons)); this.state.hasComparisons = true; @@ -128,7 +128,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * @param {string} name [description] * @return {object} Object containing array of facets and ship id + build names */ - this.getComparison = function (name) { + this.getComparison = function(name) { if (this.comparisons[name]) { return this.comparisons[name]; } @@ -139,7 +139,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * Removes the comparison from localstorage. * @param {string} name Comparison name */ - this.deleteComparison = function (name) { + this.deleteComparison = function(name) { if (this.lsEnabled && this.comparisons[name]) { delete this.comparisons[name]; localStorage.setItem(LS_KEY_COMPARISONS, angular.toJson(this.comparisons)); @@ -166,7 +166,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * Get the saved insurance type * @return {string} The name of the saved insurance type of null */ - this.getInsurance = function () { + this.getInsurance = function() { if (this.lsEnabled) { return localStorage.getItem('insurance'); } @@ -177,7 +177,7 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * Persist selected insurance type * @param {string} name Insurance type name */ - this.setInsurance = function (name) { + this.setInsurance = function(name) { if (this.lsEnabled) { return localStorage.setItem('insurance', name); } @@ -187,9 +187,9 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * Retrieve the last router state from local storage * @param {object} state State object containing state name and params */ - this.getState = function () { + this.getState = function() { if (this.lsEnabled) { - var state = localStorage.getItem('state'); + var state = localStorage.getItem('state'); if (state) { return angular.fromJson(state); } @@ -201,9 +201,9 @@ angular.module('app').service('Persist', ['$window','lodash', function ($window, * Save the current router state to localstorage * @param {object} state State object containing state name and params */ - this.setState = function (state) { + this.setState = function(state) { if (this.lsEnabled) { - localStorage.setItem('state',angular.toJson(state)); + localStorage.setItem('state', angular.toJson(state)); } }; diff --git a/app/js/service-serializer.js b/app/js/service-serializer.js index 17723d5b..a17ffc4d 100755 --- a/app/js/service-serializer.js +++ b/app/js/service-serializer.js @@ -1,7 +1,7 @@ /** * Service managing seralization and deserialization of models for use in URLs and persistene. */ -angular.module('app').service('Serializer', ['lodash', function (_) { +angular.module('app').service('Serializer', ['lodash', function(_) { /** * Serializes the ships selected components for all slots to a URL friendly string. @@ -10,7 +10,7 @@ angular.module('app').service('Serializer', ['lodash', function (_) { */ this.fromShip = function(ship) { var power = { - enabled: [ship.cargoScoop.enabled? 1 : 0], + enabled: [ship.cargoScoop.enabled ? 1 : 0], priorities: [ship.cargoScoop.priority] }; @@ -20,9 +20,9 @@ angular.module('app').service('Serializer', ['lodash', function (_) { _.map(ship.hardpoints, mapGroup, power), _.map(ship.internal, mapGroup, power), '.', - LZString.compressToBase64(power.enabled.join('')).replace(/\//g,'-'), + LZString.compressToBase64(power.enabled.join('')).replace(/\//g, '-'), '.', - LZString.compressToBase64(power.priorities.join('')).replace(/\//g,'-') + LZString.compressToBase64(power.priorities.join('')).replace(/\//g, '-') ]; return _.flatten(data).join(''); @@ -35,11 +35,8 @@ angular.module('app').service('Serializer', ['lodash', function (_) { * @param {Ship} ship The ship instance to be updated * @param {string} code The string to deserialize */ - this.toShip = function (ship, dataString) { - var commonCount = ship.common.length, - hpCount = commonCount + ship.hardpoints.length, - totalCount = hpCount + ship.internal.length, - common = new Array(ship.common.length), + this.toShip = function(ship, dataString) { + var common = new Array(ship.common.length), hardpoints = new Array(ship.hardpoints.length), internal = new Array(ship.internal.length), parts = dataString.split('.'), @@ -47,12 +44,12 @@ angular.module('app').service('Serializer', ['lodash', function (_) { enabled = null, code = parts[0]; - if(parts[1]) { - enabled = LZString.decompressFromBase64(parts[1].replace(/-/g,'/')).split(''); + if (parts[1]) { + enabled = LZString.decompressFromBase64(parts[1].replace(/-/g, '/')).split(''); } - if(parts[2]) { - priorities = LZString.decompressFromBase64(parts[2].replace(/-/g,'/')).split(''); + if (parts[2]) { + priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split(''); } decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, common, 1))); @@ -61,19 +58,23 @@ angular.module('app').service('Serializer', ['lodash', function (_) { // - priorities // - enabled/disabled - ship.buildWith({ - bulkheads: code.charAt(0) * 1, - common: common, - hardpoints: hardpoints, - internal: internal, - }, priorities, enabled); + ship.buildWith( + { + bulkheads: code.charAt(0) * 1, + common: common, + hardpoints: hardpoints, + internal: internal + }, + priorities, + enabled + ); }; - this.fromComparison = function (name, builds, facets, predicate, desc) { + this.fromComparison = function(name, builds, facets, predicate, desc) { var shipBuilds = []; - builds.forEach(function (b) { - shipBuilds.push({s: b.id, n: b.buildName, c: this.fromShip(b)}); + builds.forEach(function(b) { + shipBuilds.push({ s: b.id, n: b.buildName, c: this.fromShip(b) }); }.bind(this)); return LZString.compressToBase64(angular.toJson({ @@ -81,12 +82,12 @@ angular.module('app').service('Serializer', ['lodash', function (_) { b: shipBuilds, f: facets, p: predicate, - d: desc? 1 : 0 - })).replace(/\//g,'-'); + d: desc ? 1 : 0 + })).replace(/\//g, '-'); }; - this.toComparison = function (code) { - return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g,'/'))); + this.toComparison = function(code) { + return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g, '/'))); }; /** @@ -98,14 +99,14 @@ angular.module('app').service('Serializer', ['lodash', function (_) { * @return {string} The id of the selected component or '-' if none selected */ function mapGroup(slot) { - this.enabled.push(slot.enabled? 1 : 0); + this.enabled.push(slot.enabled ? 1 : 0); this.priorities.push(slot.priority); - return (slot.id === null)? '-' : slot.id; + return slot.id === null ? '-' : slot.id; } function decodeToArray(code, arr, codePos) { - for (i = 0; i < arr.length; i++) { + for (var i = 0; i < arr.length; i++) { if (code.charAt(codePos) == '-') { arr[i] = 0; codePos++; diff --git a/app/js/shipyard/factory-component-set.js b/app/js/shipyard/factory-component-set.js index 8ba6bcc6..15aeca64 100755 --- a/app/js/shipyard/factory-component-set.js +++ b/app/js/shipyard/factory-component-set.js @@ -1,4 +1,10 @@ -angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) { +angular.module('shipyard').factory('ComponentSet', ['lodash', function(_) { + + function filter(data, maxClass, minClass, mass) { + return _.filter(data, function(c) { + return c.class <= maxClass && c.class >= minClass && (c.maxmass === undefined || mass <= c.maxmass); + }); + } function ComponentSet(components, mass, maxCommonArr, maxInternal, maxHardPoint) { this.mass = mass; @@ -8,7 +14,7 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) { this.hpClass = {}; this.intClass = {}; - for (var i = 0; i < components.common.length; i ++) { + for (var i = 0; i < components.common.length; i++) { var max = maxCommonArr[i]; switch (i) { // Slots where component class must be equal to slot class @@ -22,21 +28,21 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) { } } - for(var h in components.hardpoints) { + for (var h in components.hardpoints) { this.hardpoints[h] = filter(components.hardpoints[h], maxHardPoint, 0, this.mass); } - for(var g in components.internal) { + for (var g in components.internal) { this.internal[g] = filter(components.internal[g], maxInternal, 0, this.mass); } } ComponentSet.prototype.getHps = function(c) { - if(!this.hpClass[c]) { - var o = this.hpClass[c] = {}; - for(var key in this.hardpoints) { - var data = filter(this.hardpoints[key], c, c? 1 : 0, this.mass); - if(data.length) { // If group is not empty + if (!this.hpClass[c]) { + var o = this.hpClass[c] = {}; + for (var key in this.hardpoints) { + var data = filter(this.hardpoints[key], c, c ? 1 : 0, this.mass); + if (data.length) { // If group is not empty o[key] = data; } } @@ -45,11 +51,11 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) { }; ComponentSet.prototype.getInts = function(c) { - if(!this.intClass[c]) { - var o = this.intClass[c] = {}; - for(var key in this.internal) { + if (!this.intClass[c]) { + var o = this.intClass[c] = {}; + for (var key in this.internal) { var data = filter(this.internal[key], c, 0, this.mass); - if(data.length) { // If group is not empty + if (data.length) { // If group is not empty o[key] = data; } } @@ -57,12 +63,6 @@ angular.module('shipyard').factory('ComponentSet', ['lodash', function (_) { return this.intClass[c]; }; - function filter (data, maxClass, minClass, mass) { - return _.filter(data, function (c) { - return c.class <= maxClass && c.class >= minClass && (c.maxmass === undefined || mass <= c.maxmass); - }); - } - return ComponentSet; }]); diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index d6d026c7..a808b866 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -1,4 +1,4 @@ -angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function (Components, calcShieldStrength, calcJumpRange, _) { +angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, _) { /** * Ship model used to track all ship components and properties. @@ -17,8 +17,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', for (var slotType in slots) { // Initialize all slots var slotGroup = slots[slotType]; var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal) - for(var i = 0; i < slotGroup.length; i++){ - group.push({id: null, c: null, incCost: true, maxClass: slotGroup[i]}); + for (var i = 0; i < slotGroup.length; i++) { + group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); } } this.c = { incCost: true, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components @@ -37,11 +37,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.powerList.unshift(this.common[0]); // Add Power Plant this.priorityBands = [ - {deployed: 0, retracted: 0}, - {deployed: 0, retracted: 0}, - {deployed: 0, retracted: 0}, - {deployed: 0, retracted: 0}, - {deployed: 0, retracted: 0} + { deployed: 0, retracted: 0 }, + { deployed: 0, retracted: 0 }, + { deployed: 0, retracted: 0 }, + { deployed: 0, retracted: 0 }, + { deployed: 0, retracted: 0 } ]; // Cumulative and aggragate stats @@ -64,32 +64,32 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', common = this.common, hps = this.hardpoints, bands = this.priorityBands, - cl = common.length, hl = hps.length, il = internal.length, - i,l; + cl = common.length, + i, l; this.useBulkhead(comps.bulkheads || 0, true); - this.cargoScoop.priority = priorities? priorities[0] * 1 : 0; - this.cargoScoop.enabled = enabled? enabled[0] * 1 : true; + this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0; + this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true; if (this.cargoScoop.enabled) { bands[this.cargoScoop.priority].retracted += this.cargoScoop.c.power; } - for(i = 0; i < cl; i++) { - common[i].enabled = enabled? enabled[i + 1] * 1 : true; - common[i].priority = priorities? priorities[i + 1] * 1 : 0; + for (i = 0; i < cl; i++) { + common[i].enabled = enabled ? enabled[i + 1] * 1 : true; + common[i].priority = priorities ? priorities[i + 1] * 1 : 0; common[i].type = 'SYS'; this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true); } common[1].type = 'ENG'; // Thrusters common[2].type = 'ENG'; // FSD - cl++; // Increase accounting for Cargo Scoop + cl++; // Increase accounts for Cargo Scoop - for(i = 0, l = comps.hardpoints.length; i < l; i++) { - hps[i].enabled = enabled? enabled[cl + i] * 1 : true; - hps[i].priority = priorities? priorities[cl + i] * 1 : 0; - hps[i].type = hps[i].maxClass? 'WEP' : 'SYS'; + for (i = 0, l = hps.length; i < l; i++) { + hps[i].enabled = enabled ? enabled[cl + i] * 1 : true; + hps[i].priority = priorities ? priorities[cl + i] * 1 : 0; + hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; if (comps.hardpoints[i] !== 0) { this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true); @@ -98,9 +98,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } } - for(i = 0, l = comps.internal.length; i < l; i++) { - internal[i].enabled = enabled? enabled[hl + cl + i] * 1 : true; - internal[i].priority = priorities? priorities[hl + cl + i] * 1 : 0; + cl += hps.length; // Increase accounts for hardpoints + + for (i = 0, l = internal.length; i < l; i++) { + internal[i].enabled = enabled ? enabled[cl + i] * 1 : true; + internal[i].priority = priorities ? priorities[cl + i] * 1 : 0; internal[i].type = 'SYS'; if (comps.internal[i] !== 0) { @@ -117,7 +119,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', }; Ship.prototype.useBulkhead = function(index, preventUpdate) { - var oldBulkhead = this.bulkheads.c; + var oldBulkhead = this.bulkheads.c; this.bulkheads.id = index; this.bulkheads.c = Components.bulkheads(this.id, index); this.updateStats(this.bulkheads, this.bulkheads.c, oldBulkhead, preventUpdate); @@ -136,7 +138,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', if (slot.id != id) { // Selecting a different component var slotIndex = this.internal.indexOf(slot); // Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique - if(slotIndex != -1 && component && _.includes(['sg','rf','fs'],component.grp)) { + if (slotIndex != -1 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { // Find another internal slot that already has this type/group installed var similarSlotIndex = this.findInternalByGroup(component.grp); // If another slot has an installed component with of the same type @@ -163,7 +165,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', * @param {number} fuel Fuel available in tons * @return {number} Jump range in Light Years */ - Ship.prototype.jumpRangeWithMass = function (mass, fuel) { + Ship.prototype.jumpRangeWithMass = function(mass, fuel) { return calcJumpRange(mass, this.common[2].c, fuel); }; @@ -173,19 +175,19 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', * @param {string} group Component group/type * @return {number} The index of the slot in ship.internal */ - Ship.prototype.findInternalByGroup = function (group) { - return _.findIndex(this.internal, function (slot) { + Ship.prototype.findInternalByGroup = function(group) { + return _.findIndex(this.internal, function(slot) { return slot.c && slot.c.grp == group; }); }; - Ship.prototype.changePriority = function (slot, newPriority) { - if(newPriority >= 0 && newPriority < this.priorityBands.length) { + Ship.prototype.changePriority = function(slot, newPriority) { + if (newPriority >= 0 && newPriority < this.priorityBands.length) { var oldPriority = slot.priority; slot.priority = newPriority; if (slot.enabled) { - var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1)? 'retracted' : 'deployed'; + var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; this.priorityBands[oldPriority][usage] -= slot.c.power; this.priorityBands[newPriority][usage] += slot.c.power; this.updatePower(); @@ -195,36 +197,33 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', return false; }; - Ship.prototype.setCostIncluded = function (item, included) { + Ship.prototype.setCostIncluded = function(item, included) { if (item.incCost != included && item.c) { - this.totalCost += included? item.c.cost : -item.c.cost; + this.totalCost += included ? item.c.cost : -item.c.cost; } item.incCost = included; }; - Ship.prototype.setSlotEnabled = function (slot, enabled) { + Ship.prototype.setSlotEnabled = function(slot, enabled) { if (slot.enabled != enabled && slot.c) { // Enabled state is changing - var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1)? 'retracted' : 'deployed'; - this.priorityBands[slot.priority][usage] += enabled? slot.c.power : -slot.c.power; + var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; + this.priorityBands[slot.priority][usage] += enabled ? slot.c.power : -slot.c.power; this.updatePower(); } slot.enabled = enabled; }; - Ship.prototype.getSlotStatus = function (slot, deployed) { - if(!slot.c) { // Empty Slot + Ship.prototype.getSlotStatus = function(slot, deployed) { + if (!slot.c) { // Empty Slot return 0; // No Status (Not possible) - } - else if (!slot.enabled) { + } else if (!slot.enabled) { return 1; // Disabled - } - else if (deployed) { - return this.priorityBands[slot.priority].deployedSum > this.powerAvailable? 2 : 3; // Offline : Online - } - else if (this.hardpoints.indexOf(slot) != -1 && !slot.c.passive) { // Active hardpoints have no retracted status + } else if (deployed) { + return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online + } else if (this.hardpoints.indexOf(slot) != -1 && !slot.c.passive) { // Active hardpoints have no retracted status return 0; // No Status (Not possible) } - return this.priorityBands[slot.priority].retractedSum > this.powerAvailable? 2 : 3; // Offline : Online + return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online }; /** @@ -254,8 +253,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.totalCost -= old.cost; } - if(old.power) { - this.priorityBands[slot.priority][(isHardPoint && !old.passive)? 'deployed' : 'retracted'] -= old.power; + if (old.power) { + this.priorityBands[slot.priority][(isHardPoint && !old.passive) ? 'deployed' : 'retracted'] -= old.power; powerChange = true; } this.unladenMass -= old.mass || 0; @@ -285,7 +284,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } if (n.power) { - this.priorityBands[slot.priority][(isHardPoint && !n.passive)? 'deployed' : 'retracted'] += n.power; + this.priorityBands[slot.priority][(isHardPoint && !n.passive) ? 'deployed' : 'retracted'] += n.power; powerChange = true; } this.unladenMass += n.mass || 0; @@ -294,7 +293,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.ladenMass = this.unladenMass + this.cargoCapacity + this.fuelCapacity; this.armourTotal = this.armourAdded + this.armour; - if(!preventUpdate) { + if (!preventUpdate) { if (powerChange) { this.updatePower(); } @@ -307,10 +306,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var bands = this.priorityBands; var prevRetracted = 0, prevDeployed = 0; - for(var i = 0, l = bands.length; i < l; i++) { + for (var i = 0, l = bands.length; i < l; i++) { var band = bands[i]; - prevRetracted = band.retractedSum = prevRetracted + band.retracted; - prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted; + prevRetracted = band.retractedSum = prevRetracted + band.retracted; + prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted; } this.powerAvailable = this.common[0].c.pGen; @@ -320,7 +319,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.updateShieldStrength = function() { var sgSI = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any - this.shieldStrength = sgSI != -1? calcShieldStrength(this.mass, this.shields, this.internal[sgSI].c, this.shieldMultiplier) : 0; + this.shieldStrength = sgSI != -1 ? calcShieldStrength(this.mass, this.shields, this.internal[sgSI].c, this.shieldMultiplier) : 0; }; /** @@ -336,8 +335,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.maxJumpCount = Math.ceil(jumps); // Number of full fuel jumps + final jump to empty tank // Going backwards, start with the last jump using the remaining fuel - this.unladenTotalRange = fuelRemaining > 0? calcJumpRange(this.unladenMass + fuelRemaining, fsd, fuelRemaining): 0; - this.ladenTotalRange = fuelRemaining > 0? calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd, fuelRemaining): 0; + this.unladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + fuelRemaining, fsd, fuelRemaining) : 0; + this.ladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd, fuelRemaining) : 0; // For each max fuel jump, calculate the max jump range based on fuel left in the tank for (var j = 0, l = Math.floor(jumps); j < l; j++) { diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 8702f923..4a91c034 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -22,48 +22,48 @@ angular.module('shipyard', ['ngLodash']) // Map to lookup group labels/names for component grp .value('GroupMap', { // Common - pp:'Power Plant', - t:'Thrusters', - fsd:'Frame Shift Drive', - ls:'Life Support', - pd:'Power Distributor', - s:'Sensors', - ft:'Fuel Tank', + pp: 'Power Plant', + t: 'Thrusters', + fsd: 'Frame Shift Drive', + ls: 'Life Support', + pd: 'Power Distributor', + s: 'Sensors', + ft: 'Fuel Tank', // Internal - fs:'Fuel Scoop', - sc:'Scanners', - am:'Auto Field-Maint. Unit', - cr:'Cargo Racks', - fi:'FSD Interdictor', - hb:'Hatch Breaker Limpet Ctrl', - hr:'Hull Reinforcement Package', - rf:'Refinery', - scb:'Shield Cell Bank', - sg:'Shield Generator', - dc:'Docking Computer', - fx:'Fuel Transfer Limpet Ctrl', - pc:'Prospector Limpet Ctrl', - cc:'Collector Limpet Ctrl', + fs: 'Fuel Scoop', + sc: 'Scanners', + am: 'Auto Field-Maint. Unit', + cr: 'Cargo Racks', + fi: 'FSD Interdictor', + hb: 'Hatch Breaker Limpet Ctrl', + hr: 'Hull Reinforcement Package', + rf: 'Refinery', + scb: 'Shield Cell Bank', + sg: 'Shield Generator', + dc: 'Docking Computer', + fx: 'Fuel Transfer Limpet Ctrl', + pc: 'Prospector Limpet Ctrl', + cc: 'Collector Limpet Ctrl', // Hard Points - bl: "Beam Laser", - ul: "Burst Laser", - c: "Cannon", - cs: "Cargo Scanner", - cm: "Countermeasure", - fc: "Fragment Cannon", - ws: "Frame Shift Wake Scanner", - kw: "Kill Warrant Scanner", - nl: "Mine Launcher", - ml: "Mining Laser", - mr: "Missile Rack", - pa: "Plasma Accelerator", - mc: "Multi-cannon", - pl: "Pulse Laser", - rg: "Rail Gun", - sb: "Shield Booster", - tp: "Torpedo Pylon" + bl: 'Beam Laser', + ul: 'Burst Laser', + c: 'Cannon', + cs: 'Cargo Scanner', + cm: 'Countermeasure', + fc: 'Fragment Cannon', + ws: 'Frame Shift Wake Scanner', + kw: 'Kill Warrant Scanner', + nl: 'Mine Launcher', + ml: 'Mining Laser', + mr: 'Missile Rack', + pa: 'Plasma Accelerator', + mc: 'Multi-cannon', + pl: 'Pulse Laser', + rg: 'Rail Gun', + sb: 'Shield Booster', + tp: 'Torpedo Pylon' }) .value('shipPurpose', { mp: 'Multi Purpose', @@ -77,7 +77,7 @@ angular.module('shipyard', ['ngLodash']) 'Small', 'Medium', 'Large', - 'Capital', + 'Capital' ]) .value('hardPointClass', [ 'Utility', @@ -146,7 +146,7 @@ angular.module('shipyard', ['ngLodash']) }, { // 8 title: 'Power', - props: ['powerRetracted','powerDeployed','powerAvailable'], + props: ['powerRetracted', 'powerDeployed', 'powerAvailable'], lbls: ['Retracted', 'Deployed', 'Available'], unit: 'MW', fmt: 'fPwr' @@ -163,7 +163,7 @@ angular.module('shipyard', ['ngLodash']) lbls: ['Unladen', 'Laden'], unit: 'LY', fmt: 'fRound' - }, + } ]) /** * Calculate the maximum single jump range based on mass and a specific FSD @@ -174,7 +174,7 @@ angular.module('shipyard', ['ngLodash']) * @return {number} Distance in Light Years */ .value('calcJumpRange', function(mass, fsd, fuel) { - return Math.pow(Math.min(fuel === undefined? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; + return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; }) /** * Calculate the a ships shield strength based on mass, shield generator and shield boosters used. @@ -186,7 +186,7 @@ angular.module('shipyard', ['ngLodash']) * @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any) * @return {number} Approximate shield strengh in MJ */ - .value('calcShieldStrength', function (mass, shields, sg, multiplier) { + .value('calcShieldStrength', function(mass, shields, sg, multiplier) { if (!sg) { return 0; } diff --git a/app/js/shipyard/service-components.js b/app/js/shipyard/service-components.js index ac9c1e95..8c023ada 100755 --- a/app/js/shipyard/service-components.js +++ b/app/js/shipyard/service-components.js @@ -1,10 +1,10 @@ -angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', function (_, C, Ships, ComponentSet) { +angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'ShipsDB', 'ComponentSet', function(_, C, Ships, ComponentSet) { this.cargoScoop = function() { - return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6}; + return { name: 'Cargo Hatch', class: 1, rating: 'H', power: 0.6 }; }; - this.common = function (typeIndex, componentId) { + this.common = function(typeIndex, componentId) { return C.common[typeIndex][componentId]; }; @@ -12,7 +12,7 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi for (var n in C.hardpoints) { var group = C.hardpoints[n]; for (var i = 0; i < group.length; i++) { - if (group[i].id == id) { + if (group[i].id === id) { return group[i]; } } @@ -24,7 +24,7 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi for (var n in C.internal) { var group = C.internal[n]; for (var i = 0; i < group.length; i++) { - if (group[i].id == id) { + if (group[i].id === id) { return group[i]; } } @@ -49,9 +49,9 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi * @param {string} shipId Unique ship Id/Key * @return {ComponentSet} The set of components the ship can install */ - this.forShip = function (shipId) { + this.forShip = function(shipId) { var ship = Ships[shipId]; return new ComponentSet(C, ship.properties.mass + 5, ship.slots.common, ship.slots.internal[0], ship.slots.hardpoints[0]); }; -}]); \ No newline at end of file +}]); From cc2d91cc517d5ccaf4d16f09bf7e08aa6031f7fc Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 21:04:52 -0700 Subject: [PATCH 05/53] Adding karma and unit tests to get started --- gulpfile.js | 12 ++++-- package.json | 5 +++ test/karma.conf.js | 34 +++++++++++++++++ test/tests/test-data.js | 66 ++++++++++++++++++++++++++++++++ test/tests/test-factory-ship.js | 35 +++++++++++++++++ tests/test-data.js | 68 --------------------------------- 6 files changed, 148 insertions(+), 72 deletions(-) create mode 100644 test/karma.conf.js create mode 100644 test/tests/test-data.js create mode 100644 test/tests/test-factory-ship.js delete mode 100644 tests/test-data.js diff --git a/gulpfile.js b/gulpfile.js index deba614b..2a16e8b8 100755 --- a/gulpfile.js +++ b/gulpfile.js @@ -10,8 +10,8 @@ var appCache = require("gulp-manifest"), eslint = require('gulp-eslint'); gutil = require('gulp-util'), htmlmin = require('gulp-htmlmin'), - jasmine = require('gulp-jasmine'), jsonlint = require("gulp-jsonlint"), + karma = require('karma').server, less = require('gulp-less'), mainBowerFiles = require('main-bower-files'), minifyCSS = require('gulp-minify-css'), @@ -252,9 +252,13 @@ gulp.task('upload', function(done) { ); }); -gulp.task('test', function () { - return gulp.src('tests/test-*.js') - .pipe(jasmine()); +gulp.task('test', function (done) { + karma.start({ + configFile: __dirname + '/test/karma.conf.js', + singleRun: true + }, function(exitStatus) { + done(exitStatus ? new gutil.PluginError('karma', { message: 'Unit tests failed!' }) : undefined); + }); }); gulp.task('lint', ['js-lint', 'json-lint']); diff --git a/package.json b/package.json index 31414320..a6d27931 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "engine": "node >= 0.12.2", "dependencies": {}, "devDependencies": { + "angular-mocks": "^1.3.16", "async": "^0.9.0", "del": "^1.1.1", "gulp": "^3.8.11", @@ -28,7 +29,11 @@ "gulp-template": "^3.0.0", "gulp-uglify": "^1.2.0", "gulp-util": "^3.0.4", + "jasmine-core": "^2.3.4", "json-concat": "0.0.0", + "karma": "^0.12.36", + "karma-chrome-launcher": "^0.1.12", + "karma-jasmine": "^0.3.5", "main-bower-files": "^2.6.2", "run-sequence": "^1.0.2", "uglify-js": "^2.4.19" diff --git a/test/karma.conf.js b/test/karma.conf.js new file mode 100644 index 00000000..03f3c6cc --- /dev/null +++ b/test/karma.conf.js @@ -0,0 +1,34 @@ +// Karma configuration +// Generated on Thu Jun 11 2015 19:39:40 GMT-0700 (PDT) + +module.exports = function(config) { + config.set({ + basePath: '', + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + // list of files / patterns to load in the browser + files: [ + '../build/lib*.js', + '../node_modules/angular-mocks/angular-mocks.js', + '../build/app*.js', + 'tests/**/*.js' + ], + // list of files to exclude + exclude: [], + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: {}, + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + port: 9876, + colors: true, + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + autoWatch: false, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/test/tests/test-data.js b/test/tests/test-data.js new file mode 100644 index 00000000..3523e70f --- /dev/null +++ b/test/tests/test-data.js @@ -0,0 +1,66 @@ +describe("Database", function() { + + var shipProperties = ["grp", "name", "manufacturer", "class", "cost", "speed", "boost", "agility", "shields", "armour", "fuelcost", "mass"]; + + it("has ships and components", function() { + expect(DB.ships).toBeDefined() + expect(DB.components.common).toBeDefined(); + expect(DB.components.hardpoints).toBeDefined(); + expect(DB.components.internal).toBeDefined(); + expect(DB.components.bulkheads).toBeDefined(); + }); + + it("has unique IDs for every hardpoint", function() { + var ids = {}; + var groups = DB.components.hardpoints; + + for (var g in groups) { + var group = groups[g]; + for (var i = 0; i < group.length; i++) { + var id = group[i].id; + expect(ids[id]).toBeFalsy('ID already exists: ' + id); + expect(group[i].grp).toBeDefined('Hardpoint has no group defined, ID:' + id); + ids[id] = true; + } + } + }); + + it("has valid internal components", function() { + var ids = {}; + var groups = DB.components.internal; + + for (var g in groups) { + var group = groups[g]; + for (var i = 0; i < group.length; i++) { + var id = group[i].id; + expect(ids[id]).toBeFalsy('ID already exists: ' + id); + expect(group[i].grp).toBeDefined('Internal component has no group defined, ID:' + id); + ids[id] = true; + } + } + }); + + it("has data for every ship", function() { + for (var s in DB.ships) { + for (var p = 0; p < shipProperties.length; p++) { + expect(DB.ships[s].properties[shipProperties[p]]).toBeDefined(shipProperties[p] + ' is missing for ' + s); + } + expect(DB.ships[s].slots.common.length).toEqual(7, s + ' is missing common slots'); + expect(DB.ships[s].defaults.common.length).toEqual(7, s + ' is missing common defaults'); + expect(DB.ships[s].slots.hardpoints.length).toEqual(DB.ships[s].defaults.hardpoints.length, s + ' hardpoint slots and defaults dont match'); + expect(DB.ships[s].slots.internal.length).toEqual(DB.ships[s].defaults.internal.length, s + ' hardpoint slots and defaults dont match'); + expect(DB.ships[s].retailCost).toBeGreaterThan(DB.ships[s].properties.cost, s + ' has invalid retail cost'); + expect(DB.components.bulkheads[s]).toBeDefined(s + ' is missing bulkheads'); + } + }); + + it("has components with a group defined", function() { + for (var i = 0; i < DB.components.common.length; i++) { + var group = DB.components.common[i]; + for (var c in group) { + expect(group[c].grp).toBeDefined('Common component has no group defined, Type: ' + i + ', ID: ' + c); + } + } + }); + +}); diff --git a/test/tests/test-factory-ship.js b/test/tests/test-factory-ship.js new file mode 100644 index 00000000..b59c6d5c --- /dev/null +++ b/test/tests/test-factory-ship.js @@ -0,0 +1,35 @@ +describe("Ship Factory", function() { + + var Ship; + + beforeEach(module('shipyard')); + beforeEach(inject(['Ship', function (_Ship_) { + Ship = _Ship_; + }])); + + it("can build all ships", function() { + for (var s in DB.ships) { + var shipData = DB.ships[s]; + var ship = new Ship(s, shipData.properties, shipData.slots); + + for (p in shipData.properties) { + expect(ship[p]).toEqual(shipData.properties[p], s + ' property [' + p + '] does not match when built'); + } + + ship.buildWith(shipData.defaults); + + expect(ship.totalCost).toEqual(shipData.retailCost, s + ' retail cost does not match default build cost'); + expect(ship.priorityBands[0].retracted).toBeGreaterThan(0); + expect(ship.powerAvailable).toBeGreaterThan(0); + expect(ship.unladenRange).toBeGreaterThan(0); + expect(ship.ladenRange).toBeGreaterThan(0); + expect(ship.cargoCapacity).toBeGreaterThan(0); + expect(ship.fuelCapacity).toBeGreaterThan(0); + expect(ship.unladenTotalRange).toBeGreaterThan(0); + expect(ship.ladenTotalRange).toBeGreaterThan(0); + expect(ship.shieldStrength).toBeGreaterThan(0); + expect(ship.armourTotal).toBeGreaterThan(0); + } + }); + +}); \ No newline at end of file diff --git a/tests/test-data.js b/tests/test-data.js deleted file mode 100644 index bf652a8d..00000000 --- a/tests/test-data.js +++ /dev/null @@ -1,68 +0,0 @@ -var data = require('../app/db.json'); - -var shipProperties = ["grp", "name", "manufacturer", "class", "cost", "speed", "boost", "agility", "shields", "armour", "fuelcost", "mass"]; - -describe("Database", function() { - - it("has ships and components", function() { - expect(data.ships).toBeDefined() - expect(data.components.common).toBeDefined(); - expect(data.components.hardpoints).toBeDefined(); - expect(data.components.internal).toBeDefined(); - expect(data.components.bulkheads).toBeDefined(); - }); - - it("has unique IDs for every hardpoint", function() { - var ids = {}; - var groups = data.components.hardpoints; - - for (var g in groups) { - var group = groups[g]; - for (var i = 0; i < group.length; i++) { - var id = group[i].id; - expect(ids[id]).toBeFalsy('ID already exists: ' + id); - expect(group[i].grp).toBeDefined('Hardpoint has no group defined, ID:' + id); - ids[id] = true; - } - } - }); - - it("has valid internal components", function() { - var ids = {}; - var groups = data.components.internal; - - for (var g in groups) { - var group = groups[g]; - for (var i = 0; i < group.length; i++) { - var id = group[i].id; - expect(ids[id]).toBeFalsy('ID already exists: ' + id); - expect(group[i].grp).toBeDefined('Internal component has no group defined, ID:' + id); - ids[id] = true; - } - } - }); - - it("has data for every ship", function() { - for (var s in data.ships) { - for (var p = 0; p < shipProperties.length; p++) { - expect(data.ships[s].properties[shipProperties[p]]).toBeDefined(shipProperties[p] + ' is missing for ' + s); - } - expect(data.ships[s].slots.common.length).toEqual(7, s + ' is missing common slots'); - expect(data.ships[s].defaults.common.length).toEqual(7, s + ' is missing common defaults'); - expect(data.ships[s].slots.hardpoints.length).toEqual(data.ships[s].defaults.hardpoints.length, s + ' hardpoint slots and defaults dont match'); - expect(data.ships[s].slots.internal.length).toEqual(data.ships[s].defaults.internal.length, s + ' hardpoint slots and defaults dont match'); - expect(data.ships[s].retailCost).toBeGreaterThan(data.ships[s].properties.cost, s + ' has invalid retail cost'); - expect(data.components.bulkheads[s]).toBeDefined(s + ' is missing bulkheads'); - } - }); - - it("has components with a group defined", function() { - for (var i = 0; i < data.components.common.length; i++) { - var group = data.components.common[i]; - for (var c in group) { - expect(group[c].grp).toBeDefined('Common component has no group defined, Type: ' + i + ', ID: ' + c); - } - } - }); - -}); From 3b02536cf746ddf93d17c092083437ed426c0be0 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 21:05:39 -0700 Subject: [PATCH 06/53] Fix some power bugs --- app/js/shipyard/factory-ship.js | 26 ++++++++++++++++++-------- app/js/shipyard/service-components.js | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index a808b866..3e97d552 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -71,6 +71,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0; this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true; + for (i = 0, l = this.priorityBands.length; i < l; i++) { + this.priorityBands[i].deployed = 0; + this.priorityBands[i].retracted = 0; + } + if (this.cargoScoop.enabled) { bands[this.cargoScoop.priority].retracted += this.cargoScoop.c.power; } @@ -79,6 +84,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', common[i].enabled = enabled ? enabled[i + 1] * 1 : true; common[i].priority = priorities ? priorities[i + 1] * 1 : 0; common[i].type = 'SYS'; + common[i].c = common[i].id = null; // Resetting 'old' component if there was one this.use(common[i], comps.common[i], Components.common(i, comps.common[i]), true); } @@ -90,11 +96,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', hps[i].enabled = enabled ? enabled[cl + i] * 1 : true; hps[i].priority = priorities ? priorities[cl + i] * 1 : 0; hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; + hps[i].c = hps[i].id = null; // Resetting 'old' component if there was one if (comps.hardpoints[i] !== 0) { this.use(hps[i], comps.hardpoints[i], Components.hardpoints(comps.hardpoints[i]), true); - } else { - hps[i].c = hps[i].id = null; } } @@ -104,11 +109,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', internal[i].enabled = enabled ? enabled[cl + i] * 1 : true; internal[i].priority = priorities ? priorities[cl + i] * 1 : 0; internal[i].type = 'SYS'; + internal[i].id = internal[i].c = null; // Resetting 'old' component if there was one if (comps.internal[i] !== 0) { this.use(internal[i], comps.internal[i], Components.internal(comps.internal[i]), true); - } else { - internal[i].id = internal[i].c = null; } } @@ -181,18 +185,24 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', }); }; + /** + * Will change the priority of the specified slot if the new priority is valid + * @param {object} slot The slot to be updated + * @param {number} newPriority The new priority to be set + * @return {boolean} Returns true if the priority was changed (within range) + */ Ship.prototype.changePriority = function(slot, newPriority) { if (newPriority >= 0 && newPriority < this.priorityBands.length) { var oldPriority = slot.priority; slot.priority = newPriority; - if (slot.enabled) { + if (slot.enabled) { // Only update power if the slot is enabled var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; this.priorityBands[oldPriority][usage] -= slot.c.power; this.priorityBands[newPriority][usage] += slot.c.power; this.updatePower(); - return true; } + return true; } return false; }; @@ -253,7 +263,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.totalCost -= old.cost; } - if (old.power) { + if (old.power && slot.enabled) { this.priorityBands[slot.priority][(isHardPoint && !old.passive) ? 'deployed' : 'retracted'] -= old.power; powerChange = true; } @@ -283,7 +293,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.totalCost += n.cost; } - if (n.power) { + if (n.power && slot.enabled) { this.priorityBands[slot.priority][(isHardPoint && !n.passive) ? 'deployed' : 'retracted'] += n.power; powerChange = true; } diff --git a/app/js/shipyard/service-components.js b/app/js/shipyard/service-components.js index 8c023ada..05a8f202 100755 --- a/app/js/shipyard/service-components.js +++ b/app/js/shipyard/service-components.js @@ -12,7 +12,7 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi for (var n in C.hardpoints) { var group = C.hardpoints[n]; for (var i = 0; i < group.length; i++) { - if (group[i].id === id) { + if (group[i].id == id) { return group[i]; } } @@ -24,7 +24,7 @@ angular.module('shipyard').service('Components', ['lodash', 'ComponentsDB', 'Shi for (var n in C.internal) { var group = C.internal[n]; for (var i = 0; i < group.length; i++) { - if (group[i].id === id) { + if (group[i].id == id) { return group[i]; } } From 2498c0e0b129028d693eada398190287d3e72f64 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 21:10:57 -0700 Subject: [PATCH 07/53] Fix tests to pass build --- test/tests/test-factory-ship.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/test/tests/test-factory-ship.js b/test/tests/test-factory-ship.js index b59c6d5c..084829dc 100644 --- a/test/tests/test-factory-ship.js +++ b/test/tests/test-factory-ship.js @@ -19,16 +19,15 @@ describe("Ship Factory", function() { ship.buildWith(shipData.defaults); expect(ship.totalCost).toEqual(shipData.retailCost, s + ' retail cost does not match default build cost'); - expect(ship.priorityBands[0].retracted).toBeGreaterThan(0); - expect(ship.powerAvailable).toBeGreaterThan(0); - expect(ship.unladenRange).toBeGreaterThan(0); - expect(ship.ladenRange).toBeGreaterThan(0); - expect(ship.cargoCapacity).toBeGreaterThan(0); - expect(ship.fuelCapacity).toBeGreaterThan(0); - expect(ship.unladenTotalRange).toBeGreaterThan(0); - expect(ship.ladenTotalRange).toBeGreaterThan(0); - expect(ship.shieldStrength).toBeGreaterThan(0); - expect(ship.armourTotal).toBeGreaterThan(0); + expect(ship.priorityBands[0].retracted).toBeGreaterThan(0, s + ' cargo'); + expect(ship.powerAvailable).toBeGreaterThan(0, s + ' powerAvailable'); + expect(ship.unladenRange).toBeGreaterThan(0, s + ' unladenRange'); + expect(ship.ladenRange).toBeGreaterThan(0, s + ' ladenRange'); + expect(ship.fuelCapacity).toBeGreaterThan(0, s + ' fuelCapacity'); + expect(ship.unladenTotalRange).toBeGreaterThan(0, s + ' unladenTotalRange'); + expect(ship.ladenTotalRange).toBeGreaterThan(0, s + ' ladenTotalRange'); + expect(ship.shieldStrength).toBeGreaterThan(0, s + ' shieldStrength'); + expect(ship.armourTotal).toBeGreaterThan(0, s + ' armourTotal'); } }); From 31579213b1acb0d8ea70f8742428a7c23ea1249b Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 11 Jun 2015 23:01:14 -0700 Subject: [PATCH 08/53] Responsive build menu improvements, donate button tweak --- app/less/header.less | 34 +++++++++++++++++++++++++++------- app/views/_header.html | 16 +++++++++------- app/views/modal-about.html | 2 +- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/app/less/header.less b/app/less/header.less index 2f30123c..02e919d1 100755 --- a/app/less/header.less +++ b/app/less/header.less @@ -63,7 +63,7 @@ header { .menu-item-label { margin-left: 1em; - .medPhone({ + .largePhone({ display: none; }); } @@ -92,21 +92,41 @@ header { .tablet({ - a { + li, a { padding: 0.3em 0; } }); + } + .dbl { + -webkit-column-count: 2; /* Chrome, Safari, Opera */ + -moz-column-count: 2; /* Firefox */ + column-count: 2; + ul { + min-width: 10em; + } + .smallTablet({ + -webkit-column-count: 3; /* Chrome, Safari, Opera */ + -moz-column-count: 3; /* Firefox */ + column-count: 3; - &.dbl { + ul { + min-width: 20em; + } + }); + + .largePhone({ -webkit-column-count: 2; /* Chrome, Safari, Opera */ -moz-column-count: 2; /* Firefox */ column-count: 2; - ul { - width: 10em; - } - } + }); + + .smallPhone({ + -webkit-column-count: 1; /* Chrome, Safari, Opera */ + -moz-column-count: 1; /* Firefox */ + column-count: 1; + }); } ul { diff --git a/app/views/_header.html b/app/views/_header.html index 162878b7..b7580acc 100755 --- a/app/views/_header.html +++ b/app/views/_header.html @@ -18,13 +18,15 @@ - diff --git a/app/views/modal-about.html b/app/views/modal-about.html index 962f8bfc..85b5c887 100755 --- a/app/views/modal-about.html +++ b/app/views/modal-about.html @@ -16,7 +16,7 @@ Any and all contributions and feedback are welcome. If you encounter any bugs please report them and provide as much detail as possible.

      -
      + From d7415ea44a9016e3713235b23f7e606e9c3cd18b Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Fri, 12 Jun 2015 20:14:56 -0700 Subject: [PATCH 09/53] Updating hull prices for diamondback scout+exp, imperial courier --- data/ships/diamondback.json | 4 ++-- data/ships/diamondback_explorer.json | 4 ++-- data/ships/imperial_courier.json | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/ships/diamondback.json b/data/ships/diamondback.json index 968e80e0..556e7217 100644 --- a/data/ships/diamondback.json +++ b/data/ships/diamondback.json @@ -5,7 +5,7 @@ "name": "Diamondback Scout", "manufacturer": "Lakon", "class": 1, - "cost": 461312, + "cost": 461342, "speed": 283, "boost": 384, "agility": 8, @@ -14,7 +14,7 @@ "fuelcost": 50, "mass": 170 }, - "retailCost": 564300, + "retailCost": 564330, "slots": { "common": [ 4, diff --git a/data/ships/diamondback_explorer.json b/data/ships/diamondback_explorer.json index 0a72c8c9..59c8e132 100644 --- a/data/ships/diamondback_explorer.json +++ b/data/ships/diamondback_explorer.json @@ -5,7 +5,7 @@ "name": "Diamondback Explorer", "manufacturer": "Lakon", "class": 1, - "cost": 1740931, + "cost": 1635691, "speed": 242, "boost": 316, "agility": 5, @@ -14,7 +14,7 @@ "fuelcost": 50, "mass": 298 }, - "retailCost": 2000000, + "retailCost": 1894760, "slots": { "common": [ 4, diff --git a/data/ships/imperial_courier.json b/data/ships/imperial_courier.json index 2da53e54..d288b3bd 100644 --- a/data/ships/imperial_courier.json +++ b/data/ships/imperial_courier.json @@ -5,7 +5,7 @@ "name": "Imperial Courier", "manufacturer": "Gutamaya", "class": 1, - "cost": 2481521, + "cost": 2481552, "speed": 277, "boost": 380, "agility": 6, @@ -14,7 +14,7 @@ "fuelcost": 50, "mass": 35 }, - "retailCost": 2542900, + "retailCost": 2542931, "slots": { "common": [ 4, From 0d09607d301322fbdb1e1b7d913a115be914f396 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Fri, 12 Jun 2015 23:38:33 -0700 Subject: [PATCH 10/53] Ship build, reset bug --- app/js/shipyard/factory-ship.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index 3e97d552..18be47b7 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -10,7 +10,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', function Ship(id, properties, slots) { this.id = id; this.cargoScoop = { c: Components.cargoScoop(), type: 'SYS' }; - this.bulkheads = { incCost: true, maxClass: 8 }; + this.bulkheads = { incCost: true, maxClass: 8, discount: 1 }; for (var p in properties) { this[p] = properties[p]; } // Copy all base properties from shipData @@ -18,10 +18,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var slotGroup = slots[slotType]; var group = this[slotType] = []; // Initialize Slot group (Common, Hardpoints, Internal) for (var i = 0; i < slotGroup.length; i++) { - group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i] }); + group.push({ id: null, c: null, incCost: true, maxClass: slotGroup[i], discount: 1 }); } } - this.c = { incCost: true, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components + this.c = { incCost: true, discount: 1, c: { name: this.name, cost: this.cost } }; // Make a 'Ship' component similar to other components this.costList = _.union(this.internal, this.common, this.hardpoints); this.costList.push(this.bulkheads); // Add The bulkheads @@ -43,16 +43,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', { deployed: 0, retracted: 0 }, { deployed: 0, retracted: 0 } ]; - - // Cumulative and aggragate stats - this.fuelCapacity = 0; - this.cargoCapacity = 0; - this.ladenMass = 0; - this.armourAdded = 0; - this.shieldMultiplier = 1; - this.totalCost = this.cost; - this.unladenMass = this.mass; - this.armourTotal = this.armour; } /** @@ -67,6 +57,17 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', cl = common.length, i, l; + // Reset Cumulative and aggragate stats + this.fuelCapacity = 0; + this.cargoCapacity = 0; + this.ladenMass = 0; + this.armourAdded = 0; + this.shieldMultiplier = 1; + this.totalCost = this.cost; + this.unladenMass = this.mass; + this.armourTotal = this.armour; + + this.bulkheads.c = null; this.useBulkhead(comps.bulkheads || 0, true); this.cargoScoop.priority = priorities ? priorities[0] * 1 : 0; this.cargoScoop.enabled = enabled ? enabled[0] * 1 : true; From 5649dc907934b7ec6c89372afddbe51896504d9c Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Fri, 12 Jun 2015 23:40:32 -0700 Subject: [PATCH 11/53] Adding founders world discount --- app/js/app.js | 2 ++ app/js/directives/directive-header.js | 17 ++++++++--------- app/js/service-persist.js | 21 +++++++++++++++++++++ app/views/_header.html | 4 ++++ app/views/page-outfit.html | 12 ++++++------ 5 files changed, 41 insertions(+), 15 deletions(-) diff --git a/app/js/app.js b/app/js/app.js index 04e449a6..bfa1c99e 100755 --- a/app/js/app.js +++ b/app/js/app.js @@ -33,6 +33,8 @@ function($rootScope, $location, $window, $doc, $state, CArr, shipPurpose, sz, hp $rootScope.SZ = sz; $rootScope.HPC = hpc; $rootScope.GMAP = GroupMap; + $rootScope.insurance = { opts: [{ name: 'Standard', pct: 0.05 }, { name: 'Alpha', pct: 0.025 }, { name: 'Beta', pct: 0.035 }] }; + $rootScope.discounts = { opts: [{ name: 'None', pct: 1 }, { name: 'Founders World - 10%', pct: 0.90 }] }; $rootScope.STATUS = ['', 'DISABLED', 'OFF', 'ON']; $rootScope.STATUS_CLASS = ['', 'disabled', 'warning', 'secondary-disabled']; $rootScope.title = 'Coriolis'; diff --git a/app/js/directives/directive-header.js b/app/js/directives/directive-header.js index c6beeebe..0925089a 100755 --- a/app/js/directives/directive-header.js +++ b/app/js/directives/directive-header.js @@ -12,17 +12,9 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers scope.allComparisons = Persist.comparisons; scope.bs = Persist.state; - // Insurance options and management here for now. - $rootScope.insurance = { - opts: [ - { name: 'Standard', pct: 0.05 }, - { name: 'Alpha', pct: 0.025 }, - { name: 'Beta', pct: 0.035 } - ] - }; - var insIndex = _.findIndex($rootScope.insurance.opts, 'name', Persist.getInsurance()); $rootScope.insurance.current = $rootScope.insurance.opts[insIndex != -1 ? insIndex : 0]; + $rootScope.discounts.current = $rootScope.discounts.opts[Persist.getDiscount() || 0]; // Close menus if a navigation change event occurs $rootScope.$on('$stateChangeStart', function() { @@ -42,6 +34,13 @@ angular.module('app').directive('shipyardHeader', ['lodash', '$rootScope', 'Pers Persist.setInsurance($rootScope.insurance.current.name); }; + /** + * Save selected discount option + */ + scope.updateDiscount = function() { + Persist.setDiscount($rootScope.discounts.opts.indexOf($rootScope.discounts.current)); + }; + scope.openMenu = function(e, menu) { e.stopPropagation(); if (menu == scope.openedMenu) { diff --git a/app/js/service-persist.js b/app/js/service-persist.js index bf7c9e30..6e065377 100755 --- a/app/js/service-persist.js +++ b/app/js/service-persist.js @@ -183,6 +183,27 @@ angular.module('app').service('Persist', ['$window', 'lodash', function($window, } }; + /** + * Persist selected discount + * @param {number} val Discount value/amount + */ + this.setDiscount = function(val) { + if (this.lsEnabled) { + return localStorage.setItem('discount', val); + } + }; + + /** + * Get the saved discount + * @return {number} val Discount value/amount + */ + this.getDiscount = function() { + if (this.lsEnabled) { + return localStorage.getItem('discount'); + } + return null; + }; + /** * Retrieve the last router state from local storage * @param {object} state State object containing state name and params diff --git a/app/views/_header.html b/app/views/_header.html index b7580acc..ce8d926f 100755 --- a/app/views/_header.html +++ b/app/views/_header.html @@ -51,6 +51,10 @@
        Insurance
      • +

      +
        + Discount +

        diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 83f17870..24db3d45 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -242,21 +242,21 @@ - - {{c.c.class}}{{c.c.rating}} - - {{fCrd(c.c.cost)}} CR + + {{c.c.class}}{{c.c.rating}} + + {{fCrd(discounts.current.pct * c.c.cost)}} CR - + - +
        Total{{fCrd(ship.totalCost)}} CR{{fCrd(ship.totalCost * discounts.current.pct)}} CR
        Insurance{{fCrd(ship.totalCost * insurance.current.pct)}} CR{{fCrd(ship.totalCost * discounts.current.pct * insurance.current.pct)}} CR
        From 2106ec0e93432cec7598e25aebf779b2e2973c9c Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sat, 13 Jun 2015 00:43:10 -0700 Subject: [PATCH 12/53] Ship building edge case, plus unit test to cover change --- app/js/shipyard/factory-ship.js | 5 +++-- test/tests/test-factory-ship.js | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index 18be47b7..48eb881c 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -57,7 +57,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', cl = common.length, i, l; - // Reset Cumulative and aggragate stats + // Reset Cumulative stats this.fuelCapacity = 0; this.cargoCapacity = 0; this.ladenMass = 0; @@ -141,7 +141,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', */ Ship.prototype.use = function(slot, id, component, preventUpdate) { if (slot.id != id) { // Selecting a different component - var slotIndex = this.internal.indexOf(slot); + var slotIndex = preventUpdate ? -1 : this.internal.indexOf(slot); // Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique if (slotIndex != -1 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { // Find another internal slot that already has this type/group installed @@ -245,6 +245,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var powerChange = slot == this.common[0]; if (old) { // Old component now being removed + console.log('this shouldn\'t happen', old); switch (old.grp) { case 'ft': this.fuelCapacity -= old.capacity; diff --git a/test/tests/test-factory-ship.js b/test/tests/test-factory-ship.js index 084829dc..f4242270 100644 --- a/test/tests/test-factory-ship.js +++ b/test/tests/test-factory-ship.js @@ -31,4 +31,40 @@ describe("Ship Factory", function() { } }); + it("resets and rebuilds properly", function() { + var id = 'cobra_mk_iii'; + var cobra = DB.ships[id]; + var shipA = new Ship(id, cobra.properties, cobra.slots); + var shipB = new Ship(id, cobra.properties, cobra.slots); + var testShip = new Ship(id, cobra.properties, cobra.slots); + + var buildA = cobra.defaults; + var buildB = { + common:['4A', '4A', '4A', '3D', '3A', '3A', '4C'], + hardpoints: ['0s', '0s', '2d', '2d', 0, '04'], + internal: ['45', '03', '2b', '2o', '27', '53'] + }; + + shipA.buildWith(buildA); // Build A + shipB.buildWith(buildB);// Build B + testShip.buildWith(buildA); + + for(var p in testShip) { + expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); + } + + testShip.buildWith(buildB); + + for(var p in testShip) { + expect(testShip[p]).toEqual(shipB[p], p + ' does not match'); + } + + testShip.buildWith(buildA); + + for(var p in testShip) { + expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); + } + + }); + }); \ No newline at end of file From eb7383b31e947695166d6af70d17caac56bfd572 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sat, 13 Jun 2015 00:44:15 -0700 Subject: [PATCH 13/53] Lint fix --- app/js/shipyard/factory-ship.js | 1 - 1 file changed, 1 deletion(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index 48eb881c..6c550ed7 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -245,7 +245,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', var powerChange = slot == this.common[0]; if (old) { // Old component now being removed - console.log('this shouldn\'t happen', old); switch (old.grp) { case 'ft': this.fuelCapacity -= old.capacity; From a2c32dd9086135a374c4b8dd7c5013dade4c714d Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sat, 13 Jun 2015 00:56:08 -0700 Subject: [PATCH 14/53] Bumping version to 0.11.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a6d27931..23b60ce7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.11.0", + "version": "0.11.1", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From 1a1467435247c587be6e9f885bf6684eae46a8f2 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 17:25:28 -0700 Subject: [PATCH 15/53] Updating License details to comply with Frontier terms and conditions --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3eed4816..1181296c 100755 --- a/README.md +++ b/README.md @@ -28,12 +28,13 @@ See [Data wiki](https://github.com/cmmcleod/coriolis/wiki/Database) for details ## License -The MIT License +All Data and [associated JSON](https://github.com/cmmcleod/coriolis/tree/master/data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their +[terms and conditions](https://www.frontierstore.net/terms-and-conditions/) -Copyright (c) 2015 Coriolis.io, Colin McLeod +The code specificially for Coriolis.io is released under the MIT License. Copyright (c) 2015 Coriolis.io, Colin McLeod Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal +of this software (Javascript, CSS, HTML, and SVG files only), and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is From 8b0f58cb695b860a5d4f17252b924c88b03a18c9 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 17:26:04 -0700 Subject: [PATCH 16/53] Right-click to clear slots feature --- app/js/controllers/controller-outfit.js | 5 +++-- app/js/directives/directive-context-menu.js | 12 ++++++++++++ app/views/page-outfit.html | 6 +++--- 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 app/js/directives/directive-context-menu.js diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 41b47479..1bf54b78 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -83,9 +83,10 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' * @param {[type]} slot The slot object belonging to the ship instance * @param {[type]} e The event object */ - $scope.select = function(type, slot, e) { + $scope.select = function(type, slot, e, id) { + console.log('SELECT:', arguments); e.stopPropagation(); - var id = angular.element(e.target).attr('cpid'); // Get component ID + id = id || angular.element(e.target).attr('cpid'); // Get component ID if (id) { if (id == 'empty') { diff --git a/app/js/directives/directive-context-menu.js b/app/js/directives/directive-context-menu.js new file mode 100644 index 00000000..38cc6358 --- /dev/null +++ b/app/js/directives/directive-context-menu.js @@ -0,0 +1,12 @@ +angular.module('app').directive('contextMenu', ['$parse', function($parse) { + return function(scope, element, attrs) { + var fn = $parse(attrs.contextMenu); + console.log(attrs.contextMenu, fn); + element.bind('contextmenu', function(e) { + scope.$apply(function() { + e.preventDefault(); + fn(scope, { $event:e }); + }); + }); + }; +}]); \ No newline at end of file diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 24db3d45..4bbceeb0 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -165,7 +165,7 @@

        Internal Compartments

        -
        +
        @@ -175,7 +175,7 @@

        HardPoints

        -
        +
        @@ -185,7 +185,7 @@

        Utility Mounts

        -
        +
        From a1506d4f37d5a0f147d79f7f8b98c75be6b63810 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 17:26:21 -0700 Subject: [PATCH 17/53] Selectable power bands, with right click to clear feature --- app/js/directives/directive-power-bands.js | 78 +++++++++++++++++----- app/less/outfit.less | 6 ++ 2 files changed, 68 insertions(+), 16 deletions(-) diff --git a/app/js/directives/directive-power-bands.js b/app/js/directives/directive-power-bands.js index f680c064..b7b6d8f2 100644 --- a/app/js/directives/directive-power-bands.js +++ b/app/js/directives/directive-power-bands.js @@ -8,6 +8,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { link: function(scope, element) { var margin = { top: 20, right: 130, bottom: 20, left: 40 }, barHeight = 20, + bands = null, innerHeight = (barHeight * 2) + 3, height = innerHeight + margin.top + margin.bottom + 1, wattScale = d3.scale.linear(), @@ -19,8 +20,17 @@ angular.module('app').directive('powerBands', ['$window', function($window) { // Create chart svg = d3.select(element[0]).append('svg'), vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'), - deployed = vis.append('g'), - retracted = vis.append('g'); + deployed = vis.append('g').attr('class','power-band'), + retracted = vis.append('g').attr('class','power-band'); + + svg.on('contextmenu', function() { + d3.event.preventDefault(); + for (var i = 0, l = bands.length; i < l; i++) { + bands[i].retSelected = false; + bands[i].depSelected = false; + } + render(); + }); // Create Y Axis SVG Elements vis.append('g').attr('class', 'watt axis'); @@ -36,12 +46,17 @@ angular.module('app').directive('powerBands', ['$window', function($window) { angular.element($window).bind('orientationchange resize pwrchange', render); function render() { - var bands = scope.bands, - available = scope.available, + bands = scope.bands; + + var available = scope.available, width = element[0].offsetWidth, w = width - margin.left - margin.right, maxBand = bands[bands.length - 1], - maxPwr = Math.max(available, maxBand.deployedSum); + deployedSum = 0, + retractedSum = 0, + retBandsSelected = false, + depBandsSelected = false; + maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum); // Update chart size svg.attr('width', width).attr('height', height); @@ -55,32 +70,44 @@ angular.module('app').directive('powerBands', ['$window', function($window) { // Update X & Y Axis wattScale.range([0, w]).domain([0, maxPwr]).clamp(true); pctScale.range([0, w]).domain([0, maxPwr / available]).clamp(true); - vis.selectAll('.watt.axis').call(wattAxis); vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis); - retLbl - .attr('x', w + 5 ) - .attr('class', maxBand.retractedSum > available ? 'warning' : 'primary') - .text(wattFmt(Math.max(0, maxBand.retractedSum)) + ' (' + pctFmt(Math.max(0, maxBand.retractedSum / available)) + ')'); + for (var i = 0, l = bands.length; i < l; i++) { + if (bands[i].retSelected) { + console.log(bands[i]); + retractedSum += bands[i].retracted; + retBandsSelected = true; + } + if (bands[i].depSelected) { + deployedSum += bands[i].deployed + bands[i].retracted; + depBandsSelected = true; + } + } - depLbl - .attr('x', w + 5 ) - .attr('class', maxBand.deployedSum > available ? 'warning' : 'primary') - .text(wattFmt(Math.max(0, maxBand.deployedSum)) + ' (' + pctFmt(Math.max(0, maxBand.deployedSum / available)) + ')'); + updateLabel(retLbl, w, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available); + updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available); retracted.selectAll('rect').data(bands).enter().append('rect') .attr('height', barHeight) .attr('width', function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) .attr('y', 1) - .attr('class', function(d) { return (d.retractedSum > available) ? 'warning' : 'primary'; }); + .on('click', function(d,i) { + d.retSelected = !d.retSelected; + render(); + }) + .attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); }); retracted.selectAll('text').data(bands).enter().append('text') .attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted) / 2); }) .attr('y', 15) .style('text-anchor', 'middle') .attr('class', 'primary-bg') + .on('click', function(d,i) { + d.retSelected = !d.retSelected; + render(); + }) .text(function(d, i) { return bandText(d.retracted, i); }); deployed.selectAll('rect').data(bands).enter().append('rect') @@ -88,17 +115,36 @@ angular.module('app').directive('powerBands', ['$window', function($window) { .attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); }) .attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); }) .attr('y', barHeight + 2) - .attr('class', function(d) { return (d.deployedSum > available) ? 'warning' : 'primary'; }); + .on('click', function(d,i) { + d.depSelected = !d.depSelected; + render(); + }) + .attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available) }); deployed.selectAll('text').data(bands).enter().append('text') .attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); }) .attr('y', barHeight + 17) .style('text-anchor', 'middle') .attr('class', 'primary-bg') + .on('click', function(d,i) { + d.depSelected = !d.depSelected; + render(); + }) .text(function(d, i) { return bandText(d.deployed + d.retracted, i); }); } + function updateLabel(lbl, width, selected, sum, available) { + lbl + .attr('x', width + 5 ) + .attr('class', getClass(selected, sum, available)) + .text(wattFmt(Math.max(0, sum)) + ' (' + pctFmt(Math.max(0, sum / available)) + ')'); + } + + function getClass(selected, sum, available) { + return selected? 'secondary' : (sum > available) ? 'warning' : 'primary'; + } + function bandText(val, index) { if (val > 0 && wattScale(val) > 13) { return index + 1; diff --git a/app/less/outfit.less b/app/less/outfit.less index 2d281c86..23500430 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -169,6 +169,12 @@ table.total { } } +.power-band { + text, rect { + cursor: pointer; + } +} + #componentPriority { .tablet({ text.primary, text.warning, text.primary-bg { From a4a562bd40185336171b7c475dbead15507908ae Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 17:47:16 -0700 Subject: [PATCH 18/53] Linting fixes --- app/js/controllers/controller-outfit.js | 1 - app/js/directives/directive-context-menu.js | 6 ++-- app/js/directives/directive-power-bands.js | 31 ++++++++++----------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 1bf54b78..1e3e71d5 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -84,7 +84,6 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' * @param {[type]} e The event object */ $scope.select = function(type, slot, e, id) { - console.log('SELECT:', arguments); e.stopPropagation(); id = id || angular.element(e.target).attr('cpid'); // Get component ID diff --git a/app/js/directives/directive-context-menu.js b/app/js/directives/directive-context-menu.js index 38cc6358..6430a573 100644 --- a/app/js/directives/directive-context-menu.js +++ b/app/js/directives/directive-context-menu.js @@ -1,12 +1,12 @@ angular.module('app').directive('contextMenu', ['$parse', function($parse) { return function(scope, element, attrs) { var fn = $parse(attrs.contextMenu); - console.log(attrs.contextMenu, fn); + element.bind('contextmenu', function(e) { scope.$apply(function() { e.preventDefault(); - fn(scope, { $event:e }); + fn(scope, { $event: e }); }); }); }; -}]); \ No newline at end of file +}]); diff --git a/app/js/directives/directive-power-bands.js b/app/js/directives/directive-power-bands.js index b7b6d8f2..5a28d2db 100644 --- a/app/js/directives/directive-power-bands.js +++ b/app/js/directives/directive-power-bands.js @@ -20,8 +20,8 @@ angular.module('app').directive('powerBands', ['$window', function($window) { // Create chart svg = d3.select(element[0]).append('svg'), vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'), - deployed = vis.append('g').attr('class','power-band'), - retracted = vis.append('g').attr('class','power-band'); + deployed = vis.append('g').attr('class', 'power-band'), + retracted = vis.append('g').attr('class', 'power-band'); svg.on('contextmenu', function() { d3.event.preventDefault(); @@ -55,7 +55,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { deployedSum = 0, retractedSum = 0, retBandsSelected = false, - depBandsSelected = false; + depBandsSelected = false, maxPwr = Math.max(available, maxBand.retractedSum, maxBand.deployedSum); // Update chart size @@ -73,27 +73,26 @@ angular.module('app').directive('powerBands', ['$window', function($window) { vis.selectAll('.watt.axis').call(wattAxis); vis.selectAll('.pct.axis').attr('transform', 'translate(0,' + innerHeight + ')').call(pctAxis); - for (var i = 0, l = bands.length; i < l; i++) { - if (bands[i].retSelected) { - console.log(bands[i]); - retractedSum += bands[i].retracted; + for (var b = 0, l = bands.length; b < l; b++) { + if (bands[b].retSelected) { + retractedSum += bands[b].retracted; retBandsSelected = true; } - if (bands[i].depSelected) { - deployedSum += bands[i].deployed + bands[i].retracted; + if (bands[b].depSelected) { + deployedSum += bands[b].deployed + bands[b].retracted; depBandsSelected = true; } } updateLabel(retLbl, w, retBandsSelected, retBandsSelected ? retractedSum : maxBand.retractedSum, available); - updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available); + updateLabel(depLbl, w, depBandsSelected, depBandsSelected ? deployedSum : maxBand.deployedSum, available); retracted.selectAll('rect').data(bands).enter().append('rect') .attr('height', barHeight) .attr('width', function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) .attr('y', 1) - .on('click', function(d,i) { + .on('click', function(d) { d.retSelected = !d.retSelected; render(); }) @@ -104,7 +103,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { .attr('y', 15) .style('text-anchor', 'middle') .attr('class', 'primary-bg') - .on('click', function(d,i) { + .on('click', function(d) { d.retSelected = !d.retSelected; render(); }) @@ -115,18 +114,18 @@ angular.module('app').directive('powerBands', ['$window', function($window) { .attr('width', function(d) { return Math.max(wattScale(d.deployed + d.retracted) - 1, 0); }) .attr('x', function(d) { return wattScale(d.deployedSum) - wattScale(d.retracted) - wattScale(d.deployed); }) .attr('y', barHeight + 2) - .on('click', function(d,i) { + .on('click', function(d) { d.depSelected = !d.depSelected; render(); }) - .attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available) }); + .attr('class', function(d) { return getClass(d.depSelected, d.deployedSum, available); }); deployed.selectAll('text').data(bands).enter().append('text') .attr('x', function(d) { return wattScale(d.deployedSum) - ((wattScale(d.retracted) + wattScale(d.deployed)) / 2); }) .attr('y', barHeight + 17) .style('text-anchor', 'middle') .attr('class', 'primary-bg') - .on('click', function(d,i) { + .on('click', function(d) { d.depSelected = !d.depSelected; render(); }) @@ -142,7 +141,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { } function getClass(selected, sum, available) { - return selected? 'secondary' : (sum > available) ? 'warning' : 'primary'; + return selected ? 'secondary' : (sum > available) ? 'warning' : 'primary'; } function bandText(val, index) { From 4b3bb3bcde43964b5dc350bdee183d3d332ea839 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 18:58:05 -0700 Subject: [PATCH 19/53] License readme tweak --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1181296c..bbd9cc69 100755 --- a/README.md +++ b/README.md @@ -29,9 +29,10 @@ See [Data wiki](https://github.com/cmmcleod/coriolis/wiki/Database) for details ## License All Data and [associated JSON](https://github.com/cmmcleod/coriolis/tree/master/data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their -[terms and conditions](https://www.frontierstore.net/terms-and-conditions/) +[terms and conditions](https://www.frontierstore.net/terms-and-conditions/). -The code specificially for Coriolis.io is released under the MIT License. Copyright (c) 2015 Coriolis.io, Colin McLeod +The code specificially for Coriolis.io is released under the MIT License. +Copyright (c) 2015 Coriolis.io, Colin McLeod Permission is hereby granted, free of charge, to any person obtaining a copy of this software (Javascript, CSS, HTML, and SVG files only), and associated documentation files (the "Software"), to deal From 59e400d7b8299f3d371ee7992eaceff354949fe0 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Sun, 14 Jun 2015 18:58:27 -0700 Subject: [PATCH 20/53] Detailed suface scanner power management special case --- app/js/directives/directive-power-bands.js | 10 +-- app/js/shipyard/factory-ship.js | 71 ++++++++++++++-------- data/components/internal/scanners.json | 1 + 3 files changed, 52 insertions(+), 30 deletions(-) diff --git a/app/js/directives/directive-power-bands.js b/app/js/directives/directive-power-bands.js index 5a28d2db..4ab6f28b 100644 --- a/app/js/directives/directive-power-bands.js +++ b/app/js/directives/directive-power-bands.js @@ -75,7 +75,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { for (var b = 0, l = bands.length; b < l; b++) { if (bands[b].retSelected) { - retractedSum += bands[b].retracted; + retractedSum += bands[b].retracted + bands[b].retOnly; retBandsSelected = true; } if (bands[b].depSelected) { @@ -89,8 +89,8 @@ angular.module('app').directive('powerBands', ['$window', function($window) { retracted.selectAll('rect').data(bands).enter().append('rect') .attr('height', barHeight) - .attr('width', function(d) { return Math.max(wattScale(d.retracted) - 1, 0); }) - .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted); }) + .attr('width', function(d) { return Math.max(wattScale(d.retracted + d.retOnly) - 1, 0); }) + .attr('x', function(d) { return wattScale(d.retractedSum) - wattScale(d.retracted + d.retOnly); }) .attr('y', 1) .on('click', function(d) { d.retSelected = !d.retSelected; @@ -99,7 +99,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { .attr('class', function(d) { return getClass(d.retSelected, d.retractedSum, available); }); retracted.selectAll('text').data(bands).enter().append('text') - .attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted) / 2); }) + .attr('x', function(d) { return wattScale(d.retractedSum) - (wattScale(d.retracted + d.retOnly) / 2); }) .attr('y', 15) .style('text-anchor', 'middle') .attr('class', 'primary-bg') @@ -107,7 +107,7 @@ angular.module('app').directive('powerBands', ['$window', function($window) { d.retSelected = !d.retSelected; render(); }) - .text(function(d, i) { return bandText(d.retracted, i); }); + .text(function(d, i) { return bandText(d.retracted + d.retOnly, i); }); deployed.selectAll('rect').data(bands).enter().append('rect') .attr('height', barHeight) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index 6c550ed7..1ded6f25 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -1,5 +1,23 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, _) { + /** + * Returns the power usage type of a slot and it's particular component + * @param {object} slot The Slot + * @param {object} component The component in the slot + * @return {string} The key for the power usage type + */ + function powerUsageType(slot, component) { + if (component) { + if (component.retractedOnly) { + return 'retOnly'; + } + if (component.passive) { + return 'retracted'; + } + } + return slot.cat != 1 ? 'retracted' : 'deployed'; + } + /** * Ship model used to track all ship components and properties. * @@ -37,11 +55,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.powerList.unshift(this.common[0]); // Add Power Plant this.priorityBands = [ - { deployed: 0, retracted: 0 }, - { deployed: 0, retracted: 0 }, - { deployed: 0, retracted: 0 }, - { deployed: 0, retracted: 0 }, - { deployed: 0, retracted: 0 } + { deployed: 0, retracted: 0, retOnly: 0 }, + { deployed: 0, retracted: 0, retOnly: 0 }, + { deployed: 0, retracted: 0, retOnly: 0 }, + { deployed: 0, retracted: 0, retOnly: 0 }, + { deployed: 0, retracted: 0, retOnly: 0 } ]; } @@ -75,6 +93,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', for (i = 0, l = this.priorityBands.length; i < l; i++) { this.priorityBands[i].deployed = 0; this.priorityBands[i].retracted = 0; + this.priorityBands[i].retOnly = 0; } if (this.cargoScoop.enabled) { @@ -82,6 +101,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } for (i = 0; i < cl; i++) { + common[i].cat = 0; common[i].enabled = enabled ? enabled[i + 1] * 1 : true; common[i].priority = priorities ? priorities[i + 1] * 1 : 0; common[i].type = 'SYS'; @@ -94,6 +114,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', cl++; // Increase accounts for Cargo Scoop for (i = 0, l = hps.length; i < l; i++) { + hps[i].cat = 1; hps[i].enabled = enabled ? enabled[cl + i] * 1 : true; hps[i].priority = priorities ? priorities[cl + i] * 1 : 0; hps[i].type = hps[i].maxClass ? 'WEP' : 'SYS'; @@ -107,6 +128,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', cl += hps.length; // Increase accounts for hardpoints for (i = 0, l = internal.length; i < l; i++) { + internal[i].cat = 2; internal[i].enabled = enabled ? enabled[cl + i] * 1 : true; internal[i].priority = priorities ? priorities[cl + i] * 1 : 0; internal[i].type = 'SYS'; @@ -141,18 +163,14 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', */ Ship.prototype.use = function(slot, id, component, preventUpdate) { if (slot.id != id) { // Selecting a different component - var slotIndex = preventUpdate ? -1 : this.internal.indexOf(slot); // Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique - if (slotIndex != -1 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { + if (slot.cat != 2 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { // Find another internal slot that already has this type/group installed - var similarSlotIndex = this.findInternalByGroup(component.grp); + var similarSlot = this.findInternalByGroup(component.grp); // If another slot has an installed component with of the same type - if (similarSlotIndex != -1 && similarSlotIndex != slotIndex) { - // Empty the slot - var similarSlot = this.internal[similarSlotIndex]; + if (similarSlot && similarSlot !== slot) { this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update - similarSlot.id = null; - similarSlot.c = null; + similarSlot.id = similarSlot.c = null; // Empty the slot } } var oldComponent = slot.c; @@ -181,9 +199,13 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', * @return {number} The index of the slot in ship.internal */ Ship.prototype.findInternalByGroup = function(group) { - return _.findIndex(this.internal, function(slot) { + var index = _.findIndex(this.internal, function(slot) { return slot.c && slot.c.grp == group; }); + if (index !== -1) { + return this.internal[index]; + } + return null; }; /** @@ -198,7 +220,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', slot.priority = newPriority; if (slot.enabled) { // Only update power if the slot is enabled - var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; + var usage = powerUsageType(slot, slot.c); this.priorityBands[oldPriority][usage] -= slot.c.power; this.priorityBands[newPriority][usage] += slot.c.power; this.updatePower(); @@ -217,8 +239,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.setSlotEnabled = function(slot, enabled) { if (slot.enabled != enabled && slot.c) { // Enabled state is changing - var usage = (slot.c.passive || this.hardpoints.indexOf(slot) == -1) ? 'retracted' : 'deployed'; - this.priorityBands[slot.priority][usage] += enabled ? slot.c.power : -slot.c.power; + this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power; this.updatePower(); } slot.enabled = enabled; @@ -229,9 +250,10 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', return 0; // No Status (Not possible) } else if (!slot.enabled) { return 1; // Disabled - } else if (deployed) { + } else if (deployed && !slot.c.retractedOnly) { // Certain component (e.g. Detaild Surface scanner) are power only while retracted return this.priorityBands[slot.priority].deployedSum > this.powerAvailable ? 2 : 3; // Offline : Online - } else if (this.hardpoints.indexOf(slot) != -1 && !slot.c.passive) { // Active hardpoints have no retracted status + // Active hardpoints have no retracted status + } else if ((deployed && slot.c.retractedOnly) || (slot.cat === 1 && !slot.c.passive)) { return 0; // No Status (Not possible) } return this.priorityBands[slot.priority].retractedSum > this.powerAvailable ? 2 : 3; // Offline : Online @@ -241,7 +263,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', * Updates the ship's cumulative and aggregated stats based on the component change. */ Ship.prototype.updateStats = function(slot, n, old, preventUpdate) { - var isHardPoint = this.hardpoints.indexOf(slot) != -1; var powerChange = slot == this.common[0]; if (old) { // Old component now being removed @@ -265,7 +286,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } if (old.power && slot.enabled) { - this.priorityBands[slot.priority][(isHardPoint && !old.passive) ? 'deployed' : 'retracted'] -= old.power; + this.priorityBands[slot.priority][powerUsageType(slot, old)] -= old.power; powerChange = true; } this.unladenMass -= old.mass || 0; @@ -295,7 +316,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', } if (n.power && slot.enabled) { - this.priorityBands[slot.priority][(isHardPoint && !n.passive) ? 'deployed' : 'retracted'] += n.power; + this.priorityBands[slot.priority][powerUsageType(slot, n)] += n.power; powerChange = true; } this.unladenMass += n.mass || 0; @@ -319,7 +340,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', for (var i = 0, l = bands.length; i < l; i++) { var band = bands[i]; - prevRetracted = band.retractedSum = prevRetracted + band.retracted; + prevRetracted = band.retractedSum = prevRetracted + band.retracted + band.retOnly; prevDeployed = band.deployedSum = prevDeployed + band.deployed + band.retracted; } @@ -329,8 +350,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', }; Ship.prototype.updateShieldStrength = function() { - var sgSI = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any - this.shieldStrength = sgSI != -1 ? calcShieldStrength(this.mass, this.shields, this.internal[sgSI].c, this.shieldMultiplier) : 0; + var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any + this.shieldStrength = sgSlot ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0; }; /** diff --git a/data/components/internal/scanners.json b/data/components/internal/scanners.json index 94ab2839..fdca28c1 100755 --- a/data/components/internal/scanners.json +++ b/data/components/internal/scanners.json @@ -38,6 +38,7 @@ "grp": "sc", "name": "Detailed Surface Scanner", "class": 1, + "retractedOnly": 1, "rating": "C", "cost": 250000, "mass": 1.3, From abfe1b4a6812b7b641fb68a2ee2d855bb9c8126b Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 09:31:33 -0700 Subject: [PATCH 21/53] Updating base shield strength for Diamondback ships --- data/ships/diamondback.json | 2 +- data/ships/diamondback_explorer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/data/ships/diamondback.json b/data/ships/diamondback.json index 556e7217..9bef9667 100644 --- a/data/ships/diamondback.json +++ b/data/ships/diamondback.json @@ -9,7 +9,7 @@ "speed": 283, "boost": 384, "agility": 8, - "shields": 93, + "shields": 118, "armour": 216, "fuelcost": 50, "mass": 170 diff --git a/data/ships/diamondback_explorer.json b/data/ships/diamondback_explorer.json index 59c8e132..4c845051 100644 --- a/data/ships/diamondback_explorer.json +++ b/data/ships/diamondback_explorer.json @@ -9,7 +9,7 @@ "speed": 242, "boost": 316, "agility": 5, - "shields": 115, + "shields": 146, "armour": 270, "fuelcost": 50, "mass": 298 From 7d28e69b1c2e9a34bbc079a294afaf18c666b436 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 09:32:59 -0700 Subject: [PATCH 22/53] Bumping version to 0.12.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23b60ce7..5de8a2a3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.11.1", + "version": "0.12.0", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From f54620ee24413592887cdf28ec350b0322b34034 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 10:11:12 -0700 Subject: [PATCH 23/53] Imperial Courier shield correction --- data/ships/imperial_courier.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/ships/imperial_courier.json b/data/ships/imperial_courier.json index d288b3bd..74778aad 100644 --- a/data/ships/imperial_courier.json +++ b/data/ships/imperial_courier.json @@ -9,7 +9,7 @@ "speed": 277, "boost": 380, "agility": 6, - "shields": 230, + "shields": 197, "armour": 144, "fuelcost": 50, "mass": 35 From bef741332dcc240883bab23ec424ebe53f17cdf3 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 10:11:34 -0700 Subject: [PATCH 24/53] Bumping version to 0.12.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5de8a2a3..bb198d1d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.12.0", + "version": "0.12.1", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From 1c0b76a8c29c3233b88b7f16e5d8f0f161d87ac2 Mon Sep 17 00:00:00 2001 From: Alex Shearn Date: Mon, 15 Jun 2015 20:07:13 +0100 Subject: [PATCH 25/53] Adding in 'Strip Ship' functionality. This commit adds a simple button next to the save/reload icons that strips the ship to maximum class, D-rated modules, and no optional modules. Still needs a custom icon! May try to add in future things like 'all cargo' or 'fill empty with...' options. --- app/js/controllers/controller-outfit.js | 16 ++++++++++++++++ app/views/page-outfit.html | 3 +++ 2 files changed, 19 insertions(+) diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 1e3e71d5..782a07a2 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -116,6 +116,22 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' } }; + /** + * Strip ship to D-class and no other components. + */ + $scope.stripBuild = function() { + angular.forEach(ship.common, function(slot,i) { + id = slot.maxClass+'D'; + ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); + }); + angular.forEach(ship.hardpoints, function(slot,i) { + ship.use(slot, null, null); + }); + angular.forEach(ship.internal, function(slot,i) { + ship.use(slot, null, null); + }); + }; + /** * Save the current build. Will replace the saved build if there is one * for this ship & with the exact name. diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 4bbceeb0..c86d6bf2 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -3,6 +3,9 @@

        + +
        From ca280673d195b5ca3b3e37511a3b3c64d4003a91 Mon Sep 17 00:00:00 2001 From: Alex Shearn Date: Mon, 15 Jun 2015 22:09:18 +0100 Subject: [PATCH 27/53] Fixing indentation --- app/js/controllers/controller-outfit.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 782a07a2..2bfc05f9 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -120,16 +120,16 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' * Strip ship to D-class and no other components. */ $scope.stripBuild = function() { - angular.forEach(ship.common, function(slot,i) { - id = slot.maxClass+'D'; - ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); - }); - angular.forEach(ship.hardpoints, function(slot,i) { - ship.use(slot, null, null); - }); - angular.forEach(ship.internal, function(slot,i) { - ship.use(slot, null, null); - }); + angular.forEach(ship.common, function(slot,i) { + id = slot.maxClass+'D'; + ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); + }); + angular.forEach(ship.hardpoints, function(slot,i) { + ship.use(slot, null, null); + }); + angular.forEach(ship.internal, function(slot,i) { + ship.use(slot, null, null); + }); }; /** From 94e2b60cd1891024b547add442a0b8c519ba9e7b Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 17:31:27 -0700 Subject: [PATCH 28/53] Changing version link --- app/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/index.html b/app/index.html index 0de22846..f557ff1b 100755 --- a/app/index.html +++ b/app/index.html @@ -63,7 +63,7 @@
        Coriolis Shipyard was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. From ce3818f99ab559f97c118a7b0f0adba3e8ad0439 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 17:32:18 -0700 Subject: [PATCH 29/53] Use Travis CI instead of Codeship --- .travis.yml | 12 ++++++++++++ package.json | 4 +++- test/karma.conf.js | 12 ++---------- 3 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..70968940 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: node_js +node_js: + - "0.12" +before_script: + - npm install -g gulp + - npm install -g bower + - npm install + - bower install +script: + - gulp lint + - gulp build-prod + - gulp test \ No newline at end of file diff --git a/package.json b/package.json index bb198d1d..de5687a4 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,11 @@ "jasmine-core": "^2.3.4", "json-concat": "0.0.0", "karma": "^0.12.36", - "karma-chrome-launcher": "^0.1.12", "karma-jasmine": "^0.3.5", + "karma-mocha-reporter": "^1.0.2", + "karma-phantomjs-launcher": "^0.2.0", "main-bower-files": "^2.6.2", + "phantomjs": "^1.9.17", "run-sequence": "^1.0.2", "uglify-js": "^2.4.19" } diff --git a/test/karma.conf.js b/test/karma.conf.js index 03f3c6cc..c1db9aee 100644 --- a/test/karma.conf.js +++ b/test/karma.conf.js @@ -14,21 +14,13 @@ module.exports = function(config) { '../build/app*.js', 'tests/**/*.js' ], - // list of files to exclude - exclude: [], - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: {}, - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], + reporters: ['mocha'], port: 9876, colors: true, // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG logLevel: config.LOG_INFO, autoWatch: false, - browsers: ['Chrome'], + browsers: ['PhantomJS'], singleRun: false }); }; From 825b678fb0cee81972539641f27cc705668ee05e Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 17:43:28 -0700 Subject: [PATCH 30/53] Total Range chart feature added --- .travis.yml | 3 +- app/js/controllers/controller-outfit.js | 46 +++++++++++++++++-------- app/js/shipyard/factory-ship.js | 21 +++-------- app/js/shipyard/module-shipyard.js | 44 +++++++++++++++++++++++ app/less/outfit.less | 2 +- app/views/page-outfit.html | 14 +++++--- 6 files changed, 94 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70968940..127b3ccd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,11 @@ language: node_js +notifications: + email: false node_js: - "0.12" before_script: - npm install -g gulp - npm install -g bower - - npm install - bower install script: - gulp lint diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 2bfc05f9..824b6ecd 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -1,4 +1,4 @@ -angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist) { +angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist, calcTotalRange) { var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance var win = angular.element($window); // Angularized window object for event triggering @@ -39,8 +39,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' $scope.jrSeries = { xMin: 0, xMax: ship.cargoCapacity, - // Slightly higher than actual based bacuse components are excluded - yMax: ship.jumpRangeWithMass(ship.unladenMass), + yMax: ship.unladenRange, yMin: 0, func: function(cargo) { // X Axis is Cargo return ship.jumpRangeWithMass(ship.unladenMass + $scope.fuel + cargo, $scope.fuel); @@ -60,6 +59,29 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' watch: $scope.fsd }; + $scope.trSeries = { + xMin: 0, + xMax: ship.cargoCapacity, + yMax: ship.unladenTotalRange, + yMin: 0, + func: function(cargo) { // X Axis is Cargo + return calcTotalRange(ship.unladenMass + cargo, $scope.fsd.c, $scope.fuel); + } + }; + $scope.trChart = { + labels: { + xAxis: { + title: 'Cargo', + unit: 'T' + }, + yAxis: { + title: 'Total Range', + unit: 'LY' + } + }, + watch: $scope.fsd + }; + /** * 'Opens' a select for component selection. * @@ -120,16 +142,12 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' * Strip ship to D-class and no other components. */ $scope.stripBuild = function() { - angular.forEach(ship.common, function(slot,i) { - id = slot.maxClass+'D'; + ship.common.forEach(function(slot) { + var id = slot.maxClass + 'D'; ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); }); - angular.forEach(ship.hardpoints, function(slot,i) { - ship.use(slot, null, null); - }); - angular.forEach(ship.internal, function(slot,i) { - ship.use(slot, null, null); - }); + ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); }); + ship.internal.forEach(function(slot) { ship.use(slot, null, null); }); }; /** @@ -232,9 +250,9 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' function updateState() { $state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false }); - $scope.jrSeries.xMax = ship.cargoCapacity; - $scope.jrSeries.yMax = ship.jumpRangeWithMass(ship.unladenMass); - $scope.jrSeries.mass = ship.unladenMass; + $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity; + $scope.jrSeries.yMax = ship.unladenRange; + $scope.trSeries.yMax = ship.unladenTotalRange; win.triggerHandler('pwrchange'); } diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index 1ded6f25..c43ebc31 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -1,4 +1,4 @@ -angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, _) { +angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', 'calcJumpRange', 'calcTotalRange', 'lodash', function(Components, calcShieldStrength, calcJumpRange, calcTotalRange, _) { /** * Returns the power usage type of a slot and it's particular component @@ -358,24 +358,13 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', * Jump Range and total range calculations */ Ship.prototype.updateJumpStats = function() { - var fsd = this.common[2].c; // Frame Shift Drive; - var fuelRemaining = this.fuelCapacity % fsd.maxfuel; // Fuel left after making N max jumps - var jumps = this.fuelCapacity / fsd.maxfuel; + var fsd = this.common[2].c; // Frame Shift Drive; this.unladenRange = calcJumpRange(this.unladenMass + fsd.maxfuel, fsd, this.fuelCapacity); // Include fuel weight for jump this.fullTankRange = calcJumpRange(this.unladenMass + this.fuelCapacity, fsd, this.fuelCapacity); // Full Tanke this.ladenRange = calcJumpRange(this.ladenMass, fsd, this.fuelCapacity); - this.maxJumpCount = Math.ceil(jumps); // Number of full fuel jumps + final jump to empty tank - - // Going backwards, start with the last jump using the remaining fuel - this.unladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + fuelRemaining, fsd, fuelRemaining) : 0; - this.ladenTotalRange = fuelRemaining > 0 ? calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd, fuelRemaining) : 0; - - // For each max fuel jump, calculate the max jump range based on fuel left in the tank - for (var j = 0, l = Math.floor(jumps); j < l; j++) { - fuelRemaining += fsd.maxfuel; - this.unladenTotalRange += calcJumpRange(this.unladenMass + fuelRemaining, fsd); - this.ladenTotalRange += calcJumpRange(this.unladenMass + this.cargoCapacity + fuelRemaining, fsd); - } + this.unladenTotalRange = calcTotalRange(this.unladenMass, fsd, this.fuelCapacity); + this.ladenTotalRange = calcTotalRange(this.unladenMass + this.cargoCapacity, fsd, this.fuelCapacity); + this.maxJumpCount = Math.ceil(this.fuelCapacity / fsd.maxfuel); }; return Ship; diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 4a91c034..7b742c6a 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -175,6 +175,50 @@ angular.module('shipyard', ['ngLodash']) */ .value('calcJumpRange', function(mass, fsd, fuel) { return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; + }) + /** + * Calculate the maximum single jump range based on mass and a specific FSD + * + * @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc + * @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass + * @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump) + * @return {number} Distance in Light Years + */ + .value('calcTotalRangev1', function(mass, fsd, fuel) { + var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps + var jumps = fuel / fsd.maxfuel; + mass += fuelRemaining; + // Going backwards, start with the last jump using the remaining fuel + var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0; + // For each max fuel jump, calculate the max jump range based on fuel left in the tank + for (var j = Math.floor(jumps); j >= 0; j--) { + fuelRemaining += fsd.maxfuel; + totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; + } + return totalRange; + }) + /** + * Calculate the maximum single jump range based on mass and a specific FSD + * + * @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc + * @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass + * @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump) + * @return {number} Distance in Light Years + */ + .value('calcTotalRange', function(mass, fsd, fuel) { + var maxfuel = fsd.maxfuel; + var maxJumpCount = Math.floor(fuel / maxfuel); + var fuelRemaining = fuel % maxfuel; + var jumpCoefficient = Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower); + + mass += fuelRemaining; + + var massCoefficient = (fsd.optmass / maxfuel) * (Math.log(mass + (maxJumpCount * maxfuel)) - Math.log(mass)); + var totalDistance = (jumpCoefficient * massCoefficient); + if (fuelRemaining > 0) { + totalDistance += Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; + } + return totalDistance; }) /** * Calculate the a ships shield strength based on mass, shield generator and shield boosters used. diff --git a/app/less/outfit.less b/app/less/outfit.less index 23500430..4eb5988c 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -177,7 +177,7 @@ table.total { #componentPriority { .tablet({ - text.primary, text.warning, text.primary-bg { + text.primary, text.warning, text.primary-bg, text.secondary { font-size: 0.8em; } diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 0f0a69a3..2961366f 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -266,11 +266,17 @@

        Jump Range

        -
        -
        -
        +
        +
        + +
        +

        Total Range

        +
        +
        + +
        +
        -
        From f459c26bd799f45c6450bdee5a03934c0bfcac87 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 18:03:02 -0700 Subject: [PATCH 31/53] Locking down npm dependencies, add caching to travis --- .travis.yml | 6 ++++++ package.json | 55 ++++++++++++++++++++++++++-------------------------- 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index 127b3ccd..52561dc0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,14 @@ language: node_js notifications: email: false +sudo: false node_js: - "0.12" +cache: + directories: + - node_modules + - bower_components + before_script: - npm install -g gulp - npm install -g bower diff --git a/package.json b/package.json index de5687a4..d24f56e0 100644 --- a/package.json +++ b/package.json @@ -9,35 +9,34 @@ "engine": "node >= 0.12.2", "dependencies": {}, "devDependencies": { - "angular-mocks": "^1.3.16", - "async": "^0.9.0", - "del": "^1.1.1", - "gulp": "^3.8.11", - "gulp-angular-templatecache": "^1.6.0", - "gulp-concat": "^2.5.2", - "gulp-eslint": "^0.13.2", - "gulp-htmlmin": "^1.1.1", - "gulp-jasmine": "^2.0.1", - "gulp-jsonlint": "^1.0.2", - "gulp-less": "^3.0.2", + "angular-mocks": "1.3.x", + "async": "0.9.x", + "del": "1.2.x", + "gulp-angular-templatecache": "1.6.x", + "gulp-concat": "2.5.x", + "gulp-eslint": "0.13.x", + "gulp-htmlmin": "1.1.x", + "gulp-jasmine": "2.0.x", + "gulp-jsonlint": "1.1.x", + "gulp-less": "3.0.x", "gulp-manifest": "0.0.6", - "gulp-minify-css": "^1.0.0", + "gulp-minify-css": "1.1.x", "gulp-rev-all": "0.8.18", - "gulp-sourcemaps": "^1.5.1", - "gulp-svgmin": "^1.1.2", - "gulp-svgstore": "^5.0.1", - "gulp-template": "^3.0.0", - "gulp-uglify": "^1.2.0", - "gulp-util": "^3.0.4", - "jasmine-core": "^2.3.4", - "json-concat": "0.0.0", - "karma": "^0.12.36", - "karma-jasmine": "^0.3.5", - "karma-mocha-reporter": "^1.0.2", - "karma-phantomjs-launcher": "^0.2.0", - "main-bower-files": "^2.6.2", - "phantomjs": "^1.9.17", - "run-sequence": "^1.0.2", - "uglify-js": "^2.4.19" + "gulp-sourcemaps": "1.5.x", + "gulp-svgmin": "1.1.x", + "gulp-svgstore": "5.0.x", + "gulp-template": "3.0.x", + "gulp-uglify": "1.2.x", + "gulp-util": "3.0.x", + "jasmine-core": "2.3.x", + "json-concat": "0.0.x", + "karma": "0.12.x", + "karma-jasmine": "0.3.x", + "karma-mocha-reporter": "1.0.x", + "karma-phantomjs-launcher": "0.2.x", + "main-bower-files": "2.8.x", + "phantomjs": "1.9.x", + "run-sequence": "1.1.x", + "uglify-js": "2.4.x" } } From f1b40eb38c9816594528204a8f7c63b73034a33d Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 18:06:09 -0700 Subject: [PATCH 32/53] Adding gulp back to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index d24f56e0..29e724dd 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "angular-mocks": "1.3.x", "async": "0.9.x", "del": "1.2.x", + "gulp": "3.9.x", "gulp-angular-templatecache": "1.6.x", "gulp-concat": "2.5.x", "gulp-eslint": "0.13.x", From 345b7f5ffe405df501814b82db125b8e1e059642 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 18:08:41 -0700 Subject: [PATCH 33/53] Removing codeship, adding travis build status to readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbd9cc69..e4668f76 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[ ![Codeship Status for cmmcleod/coriolis](https://codeship.com/projects/637858c0-f2a5-0132-7af7-5ed004d44c71/status?branch=master)](https://codeship.com/projects/85232) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis) +[![Build Status](https://travis-ci.org/cmmcleod/coriolis.svg?branch=master)](https://travis-ci.org/cmmcleod/coriolis) [![Tasks in Ready](https://badge.waffle.io/cmmcleod/coriolis.png?label=ready&title=Ready)](https://waffle.io/cmmcleod/coriolis) [![Tasks in Progress](https://badge.waffle.io/cmmcleod/coriolis.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/cmmcleod/coriolis) From bee4f7e6bc3e048cddf7509ab3090b9ad49c2548 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 18:18:27 -0700 Subject: [PATCH 34/53] Fix strip build bug, and update state --- app/js/controllers/controller-outfit.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index 824b6ecd..e174744e 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -142,12 +142,14 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' * Strip ship to D-class and no other components. */ $scope.stripBuild = function() { - ship.common.forEach(function(slot) { - var id = slot.maxClass + 'D'; - ship.use(slot, id, Components.common(ship.common.indexOf(slot), id)); - }); + for (var i = 0, l = ship.common.length - 1; i < l; i++) { // All except Fuel Tank + var id = ship.common[i].maxClass + 'D'; + ship.use(ship.common[i], id, Components.common(i, id)); + } ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); }); ship.internal.forEach(function(slot) { ship.use(slot, null, null); }); + $scope.code = Serializer.fromShip(ship); + updateState(); }; /** From b94e6126cdd879b374b20bb5836486915314a83c Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 21:46:55 -0700 Subject: [PATCH 35/53] Chart performance tweaks, UI tweaks --- app/js/directives/directive-area-chart.js | 65 ++++++++++++----------- app/js/shipyard/module-shipyard.js | 31 ++--------- app/less/charts.less | 29 +++------- app/views/page-outfit.html | 4 +- 4 files changed, 47 insertions(+), 82 deletions(-) diff --git a/app/js/directives/directive-area-chart.js b/app/js/directives/directive-area-chart.js index 9c24936b..c34fc9ba 100755 --- a/app/js/directives/directive-area-chart.js +++ b/app/js/directives/directive-area-chart.js @@ -19,7 +19,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) { xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')), yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt), x = d3.scale.linear(), - y = d3.scale.linear(); + y = d3.scale.linear(), + data = []; // Create chart var svg = d3.select(element[0]).append('svg'); @@ -61,13 +62,35 @@ angular.module('app').directive('areaChart', ['$window', function($window) { // Create and Add tooltip var tip = vis.append('g').style('display', 'none'); - tip.append('rect').attr('width', '4em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); + tip.append('rect').attr('width', '5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); tip.append('circle') .attr('class', 'marker') .attr('r', 4); tip.append('text').attr('class', 'label x').attr('y', '-0.25em'); tip.append('text').attr('class', 'label y').attr('y', '0.85em'); + vis.insert('path', ':first-child') // Area/Path to appear behind everything else + .data([data]) + .attr('class', 'area') + .attr('fill', 'url(#gradient)') + .attr('d', area) + .on('mouseover', showTip) + .on('mouseout', hideTip) + .on('mousemove', moveTip) + .call(drag); + + drag + .on('dragstart', function() { + dragging = true; + moveTip.call(this); + showTip(); + }) + .on('dragend', function() { + dragging = false; + hideTip(); + }) + .on('drag', moveTip); + /** * Watch for changes in the series data (mass changes, etc) */ @@ -78,8 +101,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) { var width = element[0].parentElement.offsetWidth, height = width * 0.5, w = width - margin.left - margin.right, - h = height - margin.top - margin.bottom, - data = []; + h = height - margin.top - margin.bottom; + + data.length = 0; // Reset Data array if (series.xMax == series.xMin) { var yVal = func(series.xMin); @@ -95,7 +119,7 @@ angular.module('app').directive('areaChart', ['$window', function($window) { // Update Chart Size svg.attr('width', width).attr('height', height); - // Update domain and scale for axes; + // Update domain and scale for axes x.range([0, w]).domain([series.xMin, series.xMax]).clamp(true); xAxis.scale(x); xLbl.attr('transform', 'translate(0,' + h + ')'); @@ -106,30 +130,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) { vis.selectAll('.y.axis').call(yAxis); vis.selectAll('.x.axis').call(xAxis); - // Remove existing elements - vis.selectAll('path.area').remove(); - - vis.insert('path', ':first-child') // Area/Path to appear behind everything else - .datum(data) - .attr('class', 'area') - .attr('fill', 'url(#gradient)') - .attr('d', area) - .on('mouseover', showTip) - .on('mouseout', hideTip) - .on('mousemove', moveTip) - .call(drag); - - drag - .on('dragstart', function() { - dragging = true; - moveTip.call(this); - showTip(); - }) - .on('dragend', function() { - dragging = false; - hideTip(); - }) - .on('drag', moveTip); + vis.selectAll('path.area') // Area/Path to appear behind everything else + .data([data]) + .attr('d', area); } function showTip() { @@ -145,8 +148,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) { function moveTip() { var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.75); tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')'); - tip.selectAll('rect').attr('x', flip ? '-4.5em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); - tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('rect').attr('x', flip ? '-6.25em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start'); tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit); tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit); } diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 7b742c6a..3ad68468 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -176,15 +176,15 @@ angular.module('shipyard', ['ngLodash']) .value('calcJumpRange', function(mass, fsd, fuel) { return Math.pow(Math.min(fuel === undefined ? fsd.maxfuel : fuel, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; }) - /** - * Calculate the maximum single jump range based on mass and a specific FSD + /** + * Calculate the total range based on mass and a specific FSD, and all fuel available * * @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc * @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass - * @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump) + * @param {number} fuel The total fuel available * @return {number} Distance in Light Years */ - .value('calcTotalRangev1', function(mass, fsd, fuel) { + .value('calcTotalRange', function(mass, fsd, fuel) { var fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps var jumps = fuel / fsd.maxfuel; mass += fuelRemaining; @@ -196,29 +196,6 @@ angular.module('shipyard', ['ngLodash']) totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; } return totalRange; - }) - /** - * Calculate the maximum single jump range based on mass and a specific FSD - * - * @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc - * @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass - * @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump) - * @return {number} Distance in Light Years - */ - .value('calcTotalRange', function(mass, fsd, fuel) { - var maxfuel = fsd.maxfuel; - var maxJumpCount = Math.floor(fuel / maxfuel); - var fuelRemaining = fuel % maxfuel; - var jumpCoefficient = Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower); - - mass += fuelRemaining; - - var massCoefficient = (fsd.optmass / maxfuel) * (Math.log(mass + (maxJumpCount * maxfuel)) - Math.log(mass)); - var totalDistance = (jumpCoefficient * massCoefficient); - if (fuelRemaining > 0) { - totalDistance += Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; - } - return totalDistance; }) /** * Calculate the a ships shield strength based on mass, shield generator and shield boosters used. diff --git a/app/less/charts.less b/app/less/charts.less index 1c1e77c9..7ac7fff6 100755 --- a/app/less/charts.less +++ b/app/less/charts.less @@ -1,29 +1,14 @@ .chart { - .user-select-none(); - display: inline-block; - margin: 0; - cursor: default; - overflow: hidden; + .medPhone({ + .axis { + font-size: 0.8em; - width: 33%; - box-sizing: border-box; - - .tablet({ - width: 50%; - }); - - .largePhone({ - width: 100%; - }); - - h3 { - text-align: center; - - &[ng-click] { - cursor: pointer; + g.tick:nth-child(2n + 1) text { + display: none; + } } - } + }); } svg { diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 2961366f..95b84b75 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -266,12 +266,12 @@

        Jump Range

        -
        +

        Total Range

        -
        +
        From 389fdc8dfa1ec9633a1e532dadea9dd91a0e7c4a Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Mon, 15 Jun 2015 23:25:42 -0700 Subject: [PATCH 36/53] Removing unused svg icon --- app/icons/cancel-circle.svg | 7 ------- 1 file changed, 7 deletions(-) delete mode 100755 app/icons/cancel-circle.svg diff --git a/app/icons/cancel-circle.svg b/app/icons/cancel-circle.svg deleted file mode 100755 index dfb2f750..00000000 --- a/app/icons/cancel-circle.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - From 45c96dc136a94360fbf3aa48668f6a8c20513581 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:25:25 -0700 Subject: [PATCH 37/53] Icon tweaks, added feather icon --- app/icons/feather.svg | 3 +++ app/icons/spinner11.svg | 5 +---- app/icons/switch.svg | 6 ++---- 3 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 app/icons/feather.svg diff --git a/app/icons/feather.svg b/app/icons/feather.svg new file mode 100644 index 00000000..4d512636 --- /dev/null +++ b/app/icons/feather.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/icons/spinner11.svg b/app/icons/spinner11.svg index 15cb4cdf..b6588c71 100755 --- a/app/icons/spinner11.svg +++ b/app/icons/spinner11.svg @@ -1,6 +1,3 @@ - - - - + diff --git a/app/icons/switch.svg b/app/icons/switch.svg index 4401f3f1..a3949c0d 100755 --- a/app/icons/switch.svg +++ b/app/icons/switch.svg @@ -1,6 +1,4 @@ - - - - + + From 4686f17d1835de9fa302f5deee6d64a92e65dea5 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:26:05 -0700 Subject: [PATCH 38/53] Strip build should reset bulkheads --- app/js/controllers/controller-outfit.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index e174744e..ad4ea372 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -148,6 +148,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' } ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); }); ship.internal.forEach(function(slot) { ship.use(slot, null, null); }); + ship.useBulkhead(0); $scope.code = Serializer.fromShip(ship); updateState(); }; From cb664003a5c4a5ba938be8827e171a5388d0d2a2 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:26:22 -0700 Subject: [PATCH 39/53] Tweak slider --- app/js/directives/directive-slider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/js/directives/directive-slider.js b/app/js/directives/directive-slider.js index e175bdd5..bf88f273 100644 --- a/app/js/directives/directive-slider.js +++ b/app/js/directives/directive-slider.js @@ -8,7 +8,7 @@ angular.module('app').directive('slider', ['$window', function($window) { change: '&onChange' }, link: function(scope, element) { - var margin = { top: -10, right: 140, bottom: 0, left: 50 }, + var margin = { top: -10, right: 145, bottom: 0, left: 50 }, height = 40, // Height is fixed h = height - margin.top - margin.bottom, fmt = d3.format('.2f'), From 0fd4a8395e2207d0cda685c1a3d69a14f121b6bf Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:26:47 -0700 Subject: [PATCH 40/53] Tweak area chart tooltip --- app/js/directives/directive-area-chart.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/js/directives/directive-area-chart.js b/app/js/directives/directive-area-chart.js index c34fc9ba..0ade7b93 100755 --- a/app/js/directives/directive-area-chart.js +++ b/app/js/directives/directive-area-chart.js @@ -62,7 +62,7 @@ angular.module('app').directive('areaChart', ['$window', function($window) { // Create and Add tooltip var tip = vis.append('g').style('display', 'none'); - tip.append('rect').attr('width', '5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); + tip.append('rect').attr('width', '4.5em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); tip.append('circle') .attr('class', 'marker') .attr('r', 4); @@ -146,9 +146,9 @@ angular.module('app').directive('areaChart', ['$window', function($window) { } function moveTip() { - var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.75); + var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.65); tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')'); - tip.selectAll('rect').attr('x', flip ? '-6.25em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('rect').attr('x', flip ? '-5.75em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); tip.selectAll('text.label').attr('x', flip ? '-2em' : '1em').style('text-anchor', flip ? 'end' : 'start'); tip.select('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit); tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit); From f3af0f3a99dc868bf67c53146d334c159205dc46 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:27:41 -0700 Subject: [PATCH 41/53] Toggling shield and boosters updates shield strength --- app/js/shipyard/factory-ship.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index c43ebc31..bbe3c173 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -238,11 +238,22 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', }; Ship.prototype.setSlotEnabled = function(slot, enabled) { - if (slot.enabled != enabled && slot.c) { // Enabled state is changing - this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power; - this.updatePower(); + if (slot.enabled != enabled) { // Enabled state is changing + slot.enabled = enabled; + if (slot.c) { + this.priorityBands[slot.priority][powerUsageType(slot, slot.c)] += enabled ? slot.c.power : -slot.c.power; + + if (slot.c.grp == 'sg') { + this.updateShieldStrength(); + } + else if (slot.c.grp == 'sb') { + this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1); + this.updateShieldStrength(); + } + + this.updatePower(); + } } - slot.enabled = enabled; }; Ship.prototype.getSlotStatus = function(slot, deployed) { @@ -277,7 +288,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.armourAdded -= old.armouradd; break; case 'sb': - this.shieldMultiplier -= old.shieldmul; + this.shieldMultiplier -= slot.enabled ? old.shieldmul : 0; break; } @@ -307,7 +318,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.armourAdded += n.armouradd; break; case 'sb': - this.shieldMultiplier += n.shieldmul; + this.shieldMultiplier += slot.enabled ? n.shieldmul : 0; break; } @@ -351,7 +362,8 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.updateShieldStrength = function() { var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any - this.shieldStrength = sgSlot ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0; + this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0; + console.log(this.shieldStrength); }; /** From bf99b34596e3def0686297ed36d2b801e220a3da Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Tue, 16 Jun 2015 15:28:06 -0700 Subject: [PATCH 42/53] Tweak outfit page charts responsiveness --- app/less/charts.less | 15 --------------- app/less/outfit.less | 20 ++++++++++++++++++-- app/views/page-outfit.html | 8 ++++---- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/app/less/charts.less b/app/less/charts.less index 7ac7fff6..f2aef464 100755 --- a/app/less/charts.less +++ b/app/less/charts.less @@ -1,16 +1,3 @@ - -.chart { - .medPhone({ - .axis { - font-size: 0.8em; - - g.tick:nth-child(2n + 1) text { - display: none; - } - } - }); -} - svg { .axis { @@ -48,5 +35,3 @@ svg { stroke-width: 1px; } } - - diff --git a/app/less/outfit.less b/app/less/outfit.less index 4eb5988c..d98576b6 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -162,8 +162,24 @@ table.total { }); .smallTablet({ - overflow-x: auto; - -webkit-overflow-scrolling: touch; + width: 100% !important; + }); + } + + &.semi { + width: 50%; + + .largePhone({ + .axis { + font-size: 0.8em; + + g.tick:nth-child(2n + 1) text { + display: none; + } + } + }); + + .medPhone({ width: 100% !important; }); } diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 95b84b75..4e2f8f0f 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -17,7 +17,7 @@ Reset
        @@ -56,7 +56,7 @@ {{fRound(ship.speed)}} m/s {{fRound(ship.boost)}} m/s {{ship.armourTotal}} ({{ship.armour}} + {{ship.armourAdded}}) - {{fRound(ship.shieldStrength)}} MJ ({{fRPct(ship.shieldMultiplier)}}) + {{fRound(ship.shieldStrength)}} MJ ({{fRPct(ship.shieldMultiplier)}}) {{fRound(ship.unladenMass)}} T {{fRound(ship.ladenMass)}} T {{fRound(ship.cargoCapacity)}} T @@ -264,12 +264,12 @@
        -
        +

        Jump Range

        -
        +

        Total Range

        From 353396398be17d08e1757c6f57dd0ce542180abc Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Wed, 17 Jun 2015 20:41:11 -0700 Subject: [PATCH 43/53] Linting fix --- app/js/shipyard/factory-ship.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index bbe3c173..a4d2a90e 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -245,8 +245,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', if (slot.c.grp == 'sg') { this.updateShieldStrength(); - } - else if (slot.c.grp == 'sb') { + } else if (slot.c.grp == 'sb') { this.shieldMultiplier += slot.c.shieldmul * (enabled ? 1 : -1); this.updateShieldStrength(); } @@ -318,7 +317,7 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', this.armourAdded += n.armouradd; break; case 'sb': - this.shieldMultiplier += slot.enabled ? n.shieldmul : 0; + this.shieldMultiplier += slot.enabled ? n.shieldmul : 0; break; } @@ -363,7 +362,6 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.updateShieldStrength = function() { var sgSlot = this.findInternalByGroup('sg'); // Find Shield Generator slot Index if any this.shieldStrength = sgSlot && sgSlot.enabled ? calcShieldStrength(this.mass, this.shields, sgSlot.c, this.shieldMultiplier) : 0; - console.log(this.shieldStrength); }; /** From dc8b829d8aae6ffa3c3b03a1f6ca39b707a72672 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Wed, 17 Jun 2015 20:41:54 -0700 Subject: [PATCH 44/53] fix: total range calculation bug --- app/js/shipyard/module-shipyard.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 3ad68468..618118a8 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -191,7 +191,7 @@ angular.module('shipyard', ['ngLodash']) // Going backwards, start with the last jump using the remaining fuel var totalRange = fuelRemaining > 0 ? Math.pow(fuelRemaining / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass : 0; // For each max fuel jump, calculate the max jump range based on fuel left in the tank - for (var j = Math.floor(jumps); j >= 0; j--) { + for (var j = 0, l = Math.floor(jumps); j < l; j++) { fuelRemaining += fsd.maxfuel; totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; } From 3abfcf7c9571c59738d052ea5d518ab64bfef3bc Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Wed, 17 Jun 2015 23:12:27 -0700 Subject: [PATCH 45/53] Tweak chart axis UI --- app/less/outfit.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/less/outfit.less b/app/less/outfit.less index d98576b6..570d81a9 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -169,7 +169,7 @@ table.total { &.semi { width: 50%; - .largePhone({ + .smallTablet({ .axis { font-size: 0.8em; From ae62781d536ce2ac21c03546e93833b3d5093f4c Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Wed, 17 Jun 2015 23:17:15 -0700 Subject: [PATCH 46/53] Bump version to 0.13.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 29e724dd..36dacb90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.12.1", + "version": "0.13.0", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From 806e5453615f2b74eee6ecb53e1f265c077831ce Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Wed, 17 Jun 2015 23:32:56 -0700 Subject: [PATCH 47/53] Fix charts in comparison page --- app/less/charts.less | 37 +++++++++++++++++++++++++++++++++++++ app/views/page-outfit.html | 4 ++-- package.json | 2 +- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/app/less/charts.less b/app/less/charts.less index f2aef464..6264599a 100755 --- a/app/less/charts.less +++ b/app/less/charts.less @@ -1,3 +1,40 @@ +.chart { + .user-select-none(); + display: inline-block; + margin: 0; + cursor: default; + overflow: hidden; + width: 33%; + box-sizing: border-box; + + .tablet({ + width: 50%; + }); + + .largePhone({ + width: 100%; + }); + + .medPhone({ + .axis { + font-size: 0.8em; + + g.tick:nth-child(2n + 1) text { + display: none; + } + } + }); + + h3 { + text-align: center; + + &[ng-click] { + cursor: pointer; + } + + } +} + svg { .axis { diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 4e2f8f0f..67c1e44f 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -266,12 +266,12 @@

        Jump Range

        -
        +

        Total Range

        -
        +
        diff --git a/package.json b/package.json index 36dacb90..5d5c4bb3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.13.0", + "version": "0.13.1", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From f19c786f64d1d54596f157c62cd3afb6dd69707a Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 18 Jun 2015 09:52:18 -0700 Subject: [PATCH 48/53] Update ship armour stats --- data/ships/adder.json | 2 +- data/ships/anaconda.json | 2 +- data/ships/asp.json | 2 +- data/ships/cobra_mk_iii.json | 2 +- data/ships/eagle.json | 2 +- data/ships/federal_dropship.json | 2 +- data/ships/fer_de_lance.json | 2 +- data/ships/hauler.json | 2 +- data/ships/imperial_clipper.json | 2 +- data/ships/orca.json | 2 +- data/ships/python.json | 2 +- data/ships/sidewinder.json | 2 +- data/ships/type_6_transporter.json | 2 +- data/ships/type_7_transport.json | 2 +- data/ships/type_9_heavy.json | 2 +- data/ships/viper.json | 2 +- data/ships/vulture.json | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/data/ships/adder.json b/data/ships/adder.json index fd940684..6488fc59 100755 --- a/data/ships/adder.json +++ b/data/ships/adder.json @@ -10,7 +10,7 @@ "boost": 320, "agility": 8, "shields": 60, - "armour": 90, + "armour": 162, "fuelcost": 50, "mass": 35 }, diff --git a/data/ships/anaconda.json b/data/ships/anaconda.json index 83827db0..985b0b3a 100755 --- a/data/ships/anaconda.json +++ b/data/ships/anaconda.json @@ -10,7 +10,7 @@ "boost": 240, "agility": 2, "shields": 350, - "armour": 525, + "armour": 945, "fuelcost": 50, "mass": 400 }, diff --git a/data/ships/asp.json b/data/ships/asp.json index 966fd5fb..f59261c1 100755 --- a/data/ships/asp.json +++ b/data/ships/asp.json @@ -10,7 +10,7 @@ "boost": 340, "agility": 6, "shields": 140, - "armour": 210, + "armour": 378, "fuelcost": 50, "mass": 280 }, diff --git a/data/ships/cobra_mk_iii.json b/data/ships/cobra_mk_iii.json index 7412ba72..73f945e0 100755 --- a/data/ships/cobra_mk_iii.json +++ b/data/ships/cobra_mk_iii.json @@ -10,7 +10,7 @@ "boost": 400, "agility": 6, "shields": 80, - "armour": 120, + "armour": 216, "fuelcost": 50, "mass": 180 }, diff --git a/data/ships/eagle.json b/data/ships/eagle.json index cc0dfe2a..22c505bb 100755 --- a/data/ships/eagle.json +++ b/data/ships/eagle.json @@ -10,7 +10,7 @@ "boost": 350, "agility": 10, "shields": 60, - "armour": 40, + "armour": 72, "fuelcost": 50, "mass": 50 }, diff --git a/data/ships/federal_dropship.json b/data/ships/federal_dropship.json index bee99fb3..0cce894c 100755 --- a/data/ships/federal_dropship.json +++ b/data/ships/federal_dropship.json @@ -10,7 +10,7 @@ "boost": 300, "agility": 0, "shields": 200, - "armour": 300, + "armour": 540, "fuelcost": 50, "mass": 580 }, diff --git a/data/ships/fer_de_lance.json b/data/ships/fer_de_lance.json index 5e199895..4bb740d9 100755 --- a/data/ships/fer_de_lance.json +++ b/data/ships/fer_de_lance.json @@ -10,7 +10,7 @@ "boost": 350, "agility": 6, "shields": 300, - "armour": 225, + "armour": 405, "fuelcost": 50, "mass": 250 }, diff --git a/data/ships/hauler.json b/data/ships/hauler.json index 55720f20..a1992fa5 100755 --- a/data/ships/hauler.json +++ b/data/ships/hauler.json @@ -10,7 +10,7 @@ "boost": 300, "agility": 6, "shields": 50, - "armour": 50, + "armour": 90, "fuelcost": 50, "mass": 14 }, diff --git a/data/ships/imperial_clipper.json b/data/ships/imperial_clipper.json index a4adf6c0..1894e71e 100755 --- a/data/ships/imperial_clipper.json +++ b/data/ships/imperial_clipper.json @@ -10,7 +10,7 @@ "boost": 380, "agility": 2, "shields": 180, - "armour": 270, + "armour": 486, "fuelcost": 50, "mass": 400 }, diff --git a/data/ships/orca.json b/data/ships/orca.json index a94a028b..f04cb0b8 100755 --- a/data/ships/orca.json +++ b/data/ships/orca.json @@ -10,7 +10,7 @@ "boost": 380, "agility": 2, "shields": 220, - "armour": 220, + "armour": 396, "fuelcost": 50, "mass": 580 }, diff --git a/data/ships/python.json b/data/ships/python.json index 5a560e92..3054952e 100755 --- a/data/ships/python.json +++ b/data/ships/python.json @@ -10,7 +10,7 @@ "boost": 280, "agility": 6, "shields": 260, - "armour": 260, + "armour": 468, "fuelcost": 50, "mass": 350 }, diff --git a/data/ships/sidewinder.json b/data/ships/sidewinder.json index 70835621..24aefb99 100755 --- a/data/ships/sidewinder.json +++ b/data/ships/sidewinder.json @@ -10,7 +10,7 @@ "boost": 320, "agility": 8, "shields": 40, - "armour": 60, + "armour": 108, "fuelcost": 50, "mass": 25 }, diff --git a/data/ships/type_6_transporter.json b/data/ships/type_6_transporter.json index 72bb9027..09ed81f4 100755 --- a/data/ships/type_6_transporter.json +++ b/data/ships/type_6_transporter.json @@ -10,7 +10,7 @@ "boost": 350, "agility": 3, "shields": 90, - "armour": 90, + "armour": 162, "fuelcost": 50, "mass": 155 }, diff --git a/data/ships/type_7_transport.json b/data/ships/type_7_transport.json index bd124033..09279bd2 100755 --- a/data/ships/type_7_transport.json +++ b/data/ships/type_7_transport.json @@ -10,7 +10,7 @@ "boost": 300, "agility": 2, "shields": 120, - "armour": 120, + "armour": 216, "fuelcost": 50, "mass": 420 }, diff --git a/data/ships/type_9_heavy.json b/data/ships/type_9_heavy.json index 393a1f70..04e34569 100755 --- a/data/ships/type_9_heavy.json +++ b/data/ships/type_9_heavy.json @@ -10,7 +10,7 @@ "boost": 200, "agility": 0, "shields": 240, - "armour": 240, + "armour": 432, "fuelcost": 50, "mass": 1000 }, diff --git a/data/ships/viper.json b/data/ships/viper.json index f9d0cdb7..2b7b4c3f 100755 --- a/data/ships/viper.json +++ b/data/ships/viper.json @@ -10,7 +10,7 @@ "boost": 400, "agility": 6, "shields": 105, - "armour": 70, + "armour": 126, "fuelcost": 50, "mass": 60 }, diff --git a/data/ships/vulture.json b/data/ships/vulture.json index 8ebcc965..e2710d70 100755 --- a/data/ships/vulture.json +++ b/data/ships/vulture.json @@ -10,7 +10,7 @@ "boost": 340, "agility": 9, "shields": 240, - "armour": 160, + "armour": 288, "fuelcost": 50, "mass": 230 }, From b285a433b239b49cce37260082101c20ebd1c2cf Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 18 Jun 2015 09:52:48 -0700 Subject: [PATCH 49/53] Bumping version to 0.13.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5d5c4bb3..5bfde49a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.13.1", + "version": "0.13.2", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" From e6ba0a14e80897bb7d21b27719dfc0a0f609d796 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 18 Jun 2015 15:51:58 -0700 Subject: [PATCH 50/53] Minor tweak to slot size position --- app/less/slot.less | 1 + 1 file changed, 1 insertion(+) diff --git a/app/less/slot.less b/app/less/slot.less index 3258f021..a7d15f0f 100755 --- a/app/less/slot.less +++ b/app/less/slot.less @@ -44,6 +44,7 @@ border-right: 1px solid @primary-disabled; box-sizing: border-box; padding-top: 0.2em; + padding-left: 0.1em; } .empty { From 4e7f1d3e8b2eb51083ed7cfd5e46b9bac45c6fda Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Thu, 18 Jun 2015 16:32:45 -0700 Subject: [PATCH 51/53] Updating README and disclaimer text --- README.md | 7 ++++--- app/index.html | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e4668f76..8c21a4e7 100755 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ The Coriolis project was inspired by [E:D Shipyard](http://www.edshipyard.com/) and, of course, [Elite Dangerous](http://www.elitedangerous.com). The ultimate goal of Coriolis is to provide rich features to support in-game play and planning while engaging the E:D community to support its development. -Coriolis was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. +Coriolis was created for non-commercial purposes. Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it. ## Contributing -Please [submit issues](https://github.com/cmmcleod/coriolis/issues), or better yet [pull requests](http://www.elitedangerous.com) for any corrections or additions to the database or the code. +Please [submit issues](https://github.com/cmmcleod/coriolis/issues), or better yet [pull requests](https://github.com/cmmcleod/coriolis/pulls) for any corrections or additions to the database or the code. ### Feature Requests, Suggestions & Bugs @@ -31,7 +31,8 @@ See [Data wiki](https://github.com/cmmcleod/coriolis/wiki/Database) for details All Data and [associated JSON](https://github.com/cmmcleod/coriolis/tree/master/data) files are intellectual property and copyright of Frontier Developments plc ('Frontier', 'Frontier Developments') and are subject to their [terms and conditions](https://www.frontierstore.net/terms-and-conditions/). -The code specificially for Coriolis.io is released under the MIT License. +The code (Javascript, CSS, HTML, and SVG files only) specificially for Coriolis.io is released under the MIT License. + Copyright (c) 2015 Coriolis.io, Colin McLeod Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/app/index.html b/app/index.html index f557ff1b..6fd111f8 100755 --- a/app/index.html +++ b/app/index.html @@ -66,7 +66,7 @@ Version <%= version %> - <%= date %>
        - Coriolis Shipyard was created for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments. + Coriolis was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.
        From 25020293ecfb6b5b9f0ec9d0daa7abed76ccc2df Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Fri, 19 Jun 2015 10:29:26 -0700 Subject: [PATCH 52/53] Fix unique internal component regression bug, add tests, bump to 0.13.3 --- app/js/shipyard/factory-ship.js | 4 +- package.json | 2 +- test/tests/test-factory-ship.js | 106 ++++++++++++++++++++++++-------- 3 files changed, 82 insertions(+), 30 deletions(-) diff --git a/app/js/shipyard/factory-ship.js b/app/js/shipyard/factory-ship.js index a4d2a90e..c75f004e 100755 --- a/app/js/shipyard/factory-ship.js +++ b/app/js/shipyard/factory-ship.js @@ -164,11 +164,11 @@ angular.module('shipyard').factory('Ship', ['Components', 'calcShieldStrength', Ship.prototype.use = function(slot, id, component, preventUpdate) { if (slot.id != id) { // Selecting a different component // Slot is an internal slot, is not being emptied, and the selected component group/type must be of unique - if (slot.cat != 2 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { + if (slot.cat == 2 && component && _.includes(['sg', 'rf', 'fs'], component.grp)) { // Find another internal slot that already has this type/group installed var similarSlot = this.findInternalByGroup(component.grp); // If another slot has an installed component with of the same type - if (similarSlot && similarSlot !== slot) { + if (!preventUpdate && similarSlot && similarSlot !== slot) { this.updateStats(similarSlot, null, similarSlot.c, true); // Update stats but don't trigger a global update similarSlot.id = similarSlot.c = null; // Empty the slot } diff --git a/package.json b/package.json index 5bfde49a..6ee650a5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "0.13.2", + "version": "0.13.3", "repository": { "type": "git", "url": "https://github.com/cmmcleod/coriolis" diff --git a/test/tests/test-factory-ship.js b/test/tests/test-factory-ship.js index f4242270..03280c9a 100644 --- a/test/tests/test-factory-ship.js +++ b/test/tests/test-factory-ship.js @@ -1,10 +1,12 @@ describe("Ship Factory", function() { var Ship; + var Components; beforeEach(module('shipyard')); - beforeEach(inject(['Ship', function (_Ship_) { + beforeEach(inject(['Ship', 'Components', function (_Ship_, _Components_) { Ship = _Ship_; + Components = _Components_; }])); it("can build all ships", function() { @@ -32,39 +34,89 @@ describe("Ship Factory", function() { }); it("resets and rebuilds properly", function() { - var id = 'cobra_mk_iii'; - var cobra = DB.ships[id]; - var shipA = new Ship(id, cobra.properties, cobra.slots); - var shipB = new Ship(id, cobra.properties, cobra.slots); - var testShip = new Ship(id, cobra.properties, cobra.slots); + var id = 'cobra_mk_iii'; + var cobra = DB.ships[id]; + var shipA = new Ship(id, cobra.properties, cobra.slots); + var shipB = new Ship(id, cobra.properties, cobra.slots); + var testShip = new Ship(id, cobra.properties, cobra.slots); - var buildA = cobra.defaults; - var buildB = { - common:['4A', '4A', '4A', '3D', '3A', '3A', '4C'], - hardpoints: ['0s', '0s', '2d', '2d', 0, '04'], - internal: ['45', '03', '2b', '2o', '27', '53'] - }; + var buildA = cobra.defaults; + var buildB = { + common:['4A', '4A', '4A', '3D', '3A', '3A', '4C'], + hardpoints: ['0s', '0s', '2d', '2d', 0, '04'], + internal: ['45', '03', '2b', '2o', '27', '53'] + }; - shipA.buildWith(buildA); // Build A - shipB.buildWith(buildB);// Build B - testShip.buildWith(buildA); + shipA.buildWith(buildA); // Build A + shipB.buildWith(buildB);// Build B + testShip.buildWith(buildA); - for(var p in testShip) { - expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); - } + for(var p in testShip) { + expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); + } - testShip.buildWith(buildB); + testShip.buildWith(buildB); - for(var p in testShip) { - expect(testShip[p]).toEqual(shipB[p], p + ' does not match'); - } + for(var p in testShip) { + expect(testShip[p]).toEqual(shipB[p], p + ' does not match'); + } - testShip.buildWith(buildA); + testShip.buildWith(buildA); - for(var p in testShip) { - expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); - } + for(var p in testShip) { + expect(testShip[p]).toEqual(shipA[p], p + ' does not match'); + } + }); + + it("enforces a single shield generator", function() { + var id = 'anaconda'; + var anacondaData = DB.ships[id]; + var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots); + anaconda.buildWith(anacondaData.defaults); + + expect(anaconda.internal[2].c.grp).toEqual('sg', 'Anaconda default shield generator slot'); + + anaconda.use(anaconda.internal[1], '4j', Components.internal('4j')); // 6E Shield Generator + + expect(anaconda.internal[2].c).toEqual(null, 'Anaconda default shield generator slot is empty'); + expect(anaconda.internal[2].id).toEqual(null, 'Anaconda default shield generator slot id is null'); + expect(anaconda.internal[1].id).toEqual('4j', 'Slot 1 should have SG 4j in it'); + expect(anaconda.internal[1].c.grp).toEqual('sg','Slot 1 should have SG 4j in it'); }); -}); \ No newline at end of file + it("enforces a single shield fuel scoop", function() { + var id = 'anaconda'; + var anacondaData = DB.ships[id]; + var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots); + anaconda.buildWith(anacondaData.defaults); + + anaconda.use(anaconda.internal[4], '32', Components.internal('32')); // 4A Fuel Scoop + expect(anaconda.internal[4].c.grp).toEqual('fs', 'Anaconda fuel scoop slot'); + + anaconda.use(anaconda.internal[3], '32', Components.internal('32')); + + expect(anaconda.internal[4].c).toEqual(null, 'Anaconda original fuel scoop slot is empty'); + expect(anaconda.internal[4].id).toEqual(null, 'Anaconda original fuel scoop slot id is null'); + expect(anaconda.internal[3].id).toEqual('32', 'Slot 1 should have FS 32 in it'); + expect(anaconda.internal[3].c.grp).toEqual('fs','Slot 1 should have FS 32 in it'); + }); + + it("enforces a single refinery", function() { + var id = 'anaconda'; + var anacondaData = DB.ships[id]; + var anaconda = new Ship(id, anacondaData.properties, anacondaData.slots); + anaconda.buildWith(anacondaData.defaults); + + anaconda.use(anaconda.internal[4], '23', Components.internal('23')); // 4E Refinery + expect(anaconda.internal[4].c.grp).toEqual('rf', 'Anaconda refinery slot'); + + anaconda.use(anaconda.internal[3], '23', Components.internal('23')); + + expect(anaconda.internal[4].c).toEqual(null, 'Anaconda original refinery slot is empty'); + expect(anaconda.internal[4].id).toEqual(null, 'Anaconda original refinery slot id is null'); + expect(anaconda.internal[3].id).toEqual('23', 'Slot 1 should have RF 23 in it'); + expect(anaconda.internal[3].c.grp).toEqual('rf','Slot 1 should have RF 23 in it'); + }); + +}); From 93f92da1df3a00ff27014f75c541d07605a50b42 Mon Sep 17 00:00:00 2001 From: Colin McLeod Date: Fri, 19 Jun 2015 19:04:45 -0700 Subject: [PATCH 53/53] Adding line chart, adding speed function --- app/js/controllers/controller-outfit.js | 56 ++++--- app/js/directives/directive-line-chart.js | 190 ++++++++++++++++++++++ app/js/shipyard/module-shipyard.js | 19 ++- app/less/outfit.less | 4 +- app/views/page-outfit.html | 9 +- 5 files changed, 251 insertions(+), 27 deletions(-) create mode 100644 app/js/directives/directive-line-chart.js diff --git a/app/js/controllers/controller-outfit.js b/app/js/controllers/controller-outfit.js index ad4ea372..91445217 100755 --- a/app/js/controllers/controller-outfit.js +++ b/app/js/controllers/controller-outfit.js @@ -1,4 +1,4 @@ -angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist, calcTotalRange) { +angular.module('app').controller('OutfitController', ['$window', '$rootScope', '$scope', '$state', '$stateParams', 'ShipsDB', 'Ship', 'Components', 'Serializer', 'Persist', 'calcTotalRange', 'calcSpeed', function($window, $rootScope, $scope, $state, $p, Ships, Ship, Components, Serializer, Persist, calcTotalRange, calcSpeed) { var data = Ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance var win = angular.element($window); // Angularized window object for event triggering @@ -55,8 +55,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' title: 'Jump Range', unit: 'LY' } - }, - watch: $scope.fsd + } }; $scope.trSeries = { @@ -78,8 +77,30 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' title: 'Total Range', unit: 'LY' } - }, - watch: $scope.fsd + } + }; + + $scope.speedSeries = { + xMin: 0, + xMax: ship.cargoCapacity, + yMax: 500, + yMin: 0, + series: ['speed', 'boost'], + func: function(cargo) { // X Axis is Cargo + return calcSpeed(ship.unladenMass + $scope.fuel + cargo, ship.speed, ship.boost, $scope.th.c); + } + }; + $scope.speedChart = { + labels: { + xAxis: { + title: 'Cargo', + unit: 'T' + }, + yAxis: { + title: 'Speed', + unit: 'm/s' + } + } }; /** @@ -122,8 +143,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' ship.useBulkhead(id); } $scope.selectedSlot = null; - $scope.code = Serializer.fromShip(ship); - updateState(); + updateState(Serializer.fromShip(ship)); } }; @@ -133,8 +153,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' $scope.reloadBuild = function() { if ($scope.buildName && $scope.savedCode) { Serializer.toShip(ship, $scope.savedCode); // Repopulate with components from last save - $scope.code = $scope.savedCode; - updateState(); + updateState($scope.savedCode); } }; @@ -149,8 +168,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' ship.hardpoints.forEach(function(slot) { ship.use(slot, null, null); }); ship.internal.forEach(function(slot) { ship.use(slot, null, null); }); ship.useBulkhead(0); - $scope.code = Serializer.fromShip(ship); - updateState(); + updateState(Serializer.fromShip(ship)); }; /** @@ -169,7 +187,7 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' if ($scope.code != $scope.savedCode) { Persist.saveBuild(ship.id, $scope.buildName, $scope.code); $scope.savedCode = $scope.code; - updateState(); + updateState($scope.code); } }; @@ -218,21 +236,18 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' */ $scope.togglePwr = function(c) { ship.setSlotEnabled(c, !c.enabled); - $scope.code = Serializer.fromShip(ship); - updateState(); + updateState(Serializer.fromShip(ship)); }; $scope.incPriority = function(c) { if (ship.changePriority(c, c.priority + 1)) { - $scope.code = Serializer.fromShip(ship); - updateState(); + updateState(Serializer.fromShip(ship)); } }; $scope.decPriority = function(c) { if (ship.changePriority(c, c.priority - 1)) { - $scope.code = Serializer.fromShip(ship); - updateState(); + updateState(Serializer.fromShip(ship)); } }; @@ -251,9 +266,10 @@ angular.module('app').controller('OutfitController', ['$window', '$rootScope', ' // Utilify functions - function updateState() { + function updateState(code) { + $scope.code = code; $state.go('outfit', { shipId: ship.id, code: $scope.code, bn: $scope.buildName }, { location: 'replace', notify: false }); - $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity; + $scope.speedSeries.xMax = $scope.trSeries.xMax = $scope.jrSeries.xMax = ship.cargoCapacity; $scope.jrSeries.yMax = ship.unladenRange; $scope.trSeries.yMax = ship.unladenTotalRange; win.triggerHandler('pwrchange'); diff --git a/app/js/directives/directive-line-chart.js b/app/js/directives/directive-line-chart.js new file mode 100644 index 00000000..9b5000b9 --- /dev/null +++ b/app/js/directives/directive-line-chart.js @@ -0,0 +1,190 @@ +angular.module('app').directive('lineChart', ['$window', function($window) { + return { + restrict: 'A', + scope: { + config: '=', + series: '=' + }, + link: function(scope, element) { + var seriesConfig = scope.series, + series = seriesConfig.series, + color = d3.scale.ordinal().range([ '#ff8c0d', '#1fb0ff', '#a05d56', '#d0743c']), + config = scope.config, + labels = config.labels, + margin = { top: 15, right: 15, bottom: 35, left: 60 }, + fmt = d3.format('.3r'), + fmtLong = d3.format('.2f'), + func = seriesConfig.func, + drag = d3.behavior.drag(), + dragging = false, + // Define Scales + x = d3.scale.linear(), + y = d3.scale.linear(), + // Define Axes + xAxis = d3.svg.axis().scale(x).outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')), + yAxis = d3.svg.axis().scale(y).ticks(6).outerTickSize(0).orient('left').tickFormat(fmt), + data = []; + + // Create chart + var svg = d3.select(element[0]).append('svg'); + var vis = svg.append('g').attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); + var lines = vis.append('g'); + + // Define Area + var line = d3.svg.line().y(function(d) { return y(d[1]); }); + + // Create Y Axis SVG Elements + var yTxt = vis.append('g').attr('class', 'y axis') + .append('text') + .attr('transform', 'rotate(-90)') + .attr('y', -50) + .attr('dy', '.1em') + .style('text-anchor', 'middle') + .text(labels.yAxis.title + ' (' + labels.yAxis.unit + ')'); + // Create X Axis SVG Elements + var xLbl = vis.append('g').attr('class', 'x axis'); + var xTxt = xLbl.append('text') + .attr('y', 30) + .attr('dy', '.1em') + .style('text-anchor', 'middle') + .text(labels.xAxis.title + ' (' + labels.xAxis.unit + ')'); + + // Create and Add tooltip + var tipWidth = (Math.max(labels.yAxis.unit.length, labels.xAxis.unit.length) * 1.25) + 2; + var tips = vis.append('g').style('display', 'none'); + + var background = vis.append('rect') // Background to capture hover/drag + .attr('fill-opacity', 0) + .on('mouseover', showTip) + .on('mouseout', hideTip) + .on('mousemove', moveTip) + .call(drag); + + drag + .on('dragstart', function() { + dragging = true; + moveTip.call(this); + showTip(); + }) + .on('dragend', function() { + dragging = false; + hideTip(); + }) + .on('drag', moveTip); + + /** + * Watch for changes in the series data (mass changes, etc) + */ + scope.$watchCollection('series', render); + angular.element($window).bind('orientationchange resize render', render); + + function render() { + var width = element[0].parentElement.offsetWidth, + height = width * 0.5, + xMax = seriesConfig.xMax, + xMin = seriesConfig.xMin, + yMax = seriesConfig.yMax, + yMin = seriesConfig.yMin, + w = width - margin.left - margin.right, + h = height - margin.top - margin.bottom, + s, val, yVal, delta; + + data.length = 0; // Reset Data array + + if (seriesConfig.xMax == seriesConfig.xMin) { + line.x(function(d, i) { return i * w; }); + } else { + line.x(function(d) { return x(d[0]); }); + } + + if (series) { + for (s = 0; s < series.length; s++) { + data.push([]); + } + + if (xMax == xMin) { + yVal = func(xMin); + for (s = 0; s < series.length; s++) { + data[s].push( [ xMin, yVal[ series[s] ] ], [ 1, yVal[ series[s] ] ]); + } + } else { + delta = (xMax - xMin) / 30; // Only render 30 points on the graph + for (val = xMin; val <= xMax; val += delta) { + yVal = func(val); + for (s = 0; s < series.length; s++) { + data[s].push([ val, yVal[ series[s] ] ]); + } + } + } + + } else { + var seriesData = []; + if (xMax == xMin) { + yVal = func(xMin); + seriesData.push([ xMin, yVal ], [ 1, yVal ]); + } else { + delta = (xMax - xMin) / 30; // Only render 30 points on the graph + for (val = xMin; val <= xMax; val += delta) { + seriesData.push([val, func(val) ]); + } + } + + data.push(seriesData); + } + + // Update Chart Size + svg.attr('width', width).attr('height', height); + background.attr('height', h).attr('width', w); + + // Update domain and scale for axes + x.range([0, w]).domain([xMin, xMax]).clamp(true); + xLbl.attr('transform', 'translate(0,' + h + ')'); + xTxt.attr('x', w / 2); + y.range([h, 0]).domain([yMin, yMax]); + yTxt.attr('x', -h / 2); + vis.selectAll('.y.axis').call(yAxis); + vis.selectAll('.x.axis').call(xAxis); + + lines.selectAll('path.line') + .data(data) + .attr('d', line) // Update existing series + .enter() // Add new series + .append('path') + .attr('class', 'line') + .attr('stroke', function(d, i) { return color(i); }) + .attr('stroke-width', 2) + .attr('d', line); + + var tip = tips.selectAll('g.tooltip').data(data).enter().append('g').attr('class', 'tooltip'); + tip.append('rect').attr('width', tipWidth + 'em').attr('height', '2em').attr('x', '0.5em').attr('y', '-1em').attr('class', 'tip'); + tip.append('circle').attr('class', 'marker').attr('r', 4); + tip.append('text').attr('class', 'label x').attr('y', '-0.25em'); + tip.append('text').attr('class', 'label y').attr('y', '0.85em'); + } + + function showTip() { + tips.style('display', null); + } + + function hideTip() { + if (!dragging) { + tips.style('display', 'none'); + } + } + + function moveTip() { + var xPos = d3.mouse(this)[0], x0 = x.invert(xPos), y0 = func(x0), flip = (x0 / x.domain()[1] > 0.65); + var tip = tips.selectAll('g.tooltip').attr('transform', function(d, i) { return 'translate(' + x(x0) + ',' + y(series ? y0[series[i]] : y0) + ')'; }); + tip.selectAll('rect').attr('x', flip ? (-tipWidth - 0.5) + 'em' : '0.5em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('text.label').attr('x', flip ? '-1em' : '1em').style('text-anchor', flip ? 'end' : 'start'); + tip.selectAll('text.label.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit); + tips.selectAll('text.label.y').text(function(d, i) { return fmtLong(series ? y0[series[i]] : y0) + ' ' + labels.yAxis.unit; }); + } + + scope.$on('$destroy', function() { + angular.element($window).unbind('orientationchange resize render', render); + }); + + } + }; +}]); diff --git a/app/js/shipyard/module-shipyard.js b/app/js/shipyard/module-shipyard.js index 618118a8..8c98dad4 100755 --- a/app/js/shipyard/module-shipyard.js +++ b/app/js/shipyard/module-shipyard.js @@ -208,9 +208,6 @@ angular.module('shipyard', ['ngLodash']) * @return {number} Approximate shield strengh in MJ */ .value('calcShieldStrength', function(mass, shields, sg, multiplier) { - if (!sg) { - return 0; - } if (mass <= sg.minmass) { return shields * multiplier * sg.minmul; } @@ -221,4 +218,20 @@ angular.module('shipyard', ['ngLodash']) return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul)); } return shields * multiplier * sg.maxmul; + }) + /** + * Calculate the a ships speed based on mass, and thrusters. Currently Innacurate / Incomplete :( + * + * @private + * @param {number} mass Current mass of the ship + * @param {number} baseSpeed Base speed m/s for ship + * @param {number} baseBoost Base boost m/s for ship + * @param {object} thrusters The shield generator used + * @return {object} Approximate speed and boost speed in m/s + */ + .value('calcSpeed', function(mass, baseSpeed, baseBoost) { //, thrusters) { + //var speed = baseSpeed * (1 + ((thrusters.optmass / mass) * 0.1 ) ); // TODO: find thruser coefficient(s) + //var boost = baseBoost * (1 + ((thrusters.optmass / mass) * 0.1 ) ); + + return { boost: baseSpeed, speed: baseBoost }; }); diff --git a/app/less/outfit.less b/app/less/outfit.less index 570d81a9..faad7a9e 100755 --- a/app/less/outfit.less +++ b/app/less/outfit.less @@ -167,7 +167,7 @@ table.total { } &.semi { - width: 50%; + width: 33%; .smallTablet({ .axis { @@ -179,7 +179,7 @@ table.total { } }); - .medPhone({ + .largePhone({ width: 100% !important; }); } diff --git a/app/views/page-outfit.html b/app/views/page-outfit.html index 67c1e44f..63030e12 100644 --- a/app/views/page-outfit.html +++ b/app/views/page-outfit.html @@ -266,12 +266,17 @@

        Jump Range

        -
        +

        Total Range

        -
        +
        +
        + +
        +

        Thruster Speed

        +