Chart performance tweaks, UI tweaks

This commit is contained in:
Colin McLeod
2015-06-15 21:46:55 -07:00
parent bee4f7e6bc
commit b94e6126cd
4 changed files with 47 additions and 82 deletions

View File

@@ -19,7 +19,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')), xAxis = d3.svg.axis().outerTickSize(0).orient('bottom').tickFormat(d3.format('.2r')),
yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt), yAxis = d3.svg.axis().ticks(6).outerTickSize(0).orient('left').tickFormat(fmt),
x = d3.scale.linear(), x = d3.scale.linear(),
y = d3.scale.linear(); y = d3.scale.linear(),
data = [];
// Create chart // Create chart
var svg = d3.select(element[0]).append('svg'); var svg = d3.select(element[0]).append('svg');
@@ -61,56 +62,15 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
// Create and Add tooltip // Create and Add tooltip
var tip = vis.append('g').style('display', 'none'); 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') tip.append('circle')
.attr('class', 'marker') .attr('class', 'marker')
.attr('r', 4); .attr('r', 4);
tip.append('text').attr('class', 'label x').attr('y', '-0.25em'); tip.append('text').attr('class', 'label x').attr('y', '-0.25em');
tip.append('text').attr('class', 'label y').attr('y', '0.85em'); tip.append('text').attr('class', 'label y').attr('y', '0.85em');
/**
* 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,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom,
data = [];
if (series.xMax == series.xMin) {
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]); });
} else {
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);
// 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);
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);
// 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) .data([data])
.attr('class', 'area') .attr('class', 'area')
.attr('fill', 'url(#gradient)') .attr('fill', 'url(#gradient)')
.attr('d', area) .attr('d', area)
@@ -130,6 +90,49 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
hideTip(); hideTip();
}) })
.on('drag', moveTip); .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,
w = width - margin.left - margin.right,
h = height - margin.top - margin.bottom;
data.length = 0; // Reset Data array
if (series.xMax == series.xMin) {
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]); });
} else {
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);
// 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);
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);
vis.selectAll('path.area') // Area/Path to appear behind everything else
.data([data])
.attr('d', area);
} }
function showTip() { function showTip() {
@@ -145,8 +148,8 @@ angular.module('app').directive('areaChart', ['$window', function($window) {
function moveTip() { 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.75);
tip.attr('transform', 'translate(' + x(x0) + ',' + y(y0) + ')'); 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('rect').attr('x', flip ? '-6.25em' : '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').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.x').text(fmtLong(x0) + ' ' + labels.xAxis.unit);
tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit); tip.select('text.label.y').text(fmtLong(y0) + ' ' + labels.yAxis.unit);
} }

View File

@@ -177,14 +177,14 @@ angular.module('shipyard', ['ngLodash'])
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 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 {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass * @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 * @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 fuelRemaining = fuel % fsd.maxfuel; // Fuel left after making N max jumps
var jumps = fuel / fsd.maxfuel; var jumps = fuel / fsd.maxfuel;
mass += fuelRemaining; mass += fuelRemaining;
@@ -196,29 +196,6 @@ angular.module('shipyard', ['ngLodash'])
totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; totalRange += Math.pow(fsd.maxfuel / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
} }
return totalRange; 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. * Calculate the a ships shield strength based on mass, shield generator and shield boosters used.

View File

@@ -1,29 +1,14 @@
.chart { .chart {
.user-select-none(); .medPhone({
display: inline-block; .axis {
margin: 0; font-size: 0.8em;
cursor: default;
overflow: hidden;
width: 33%; g.tick:nth-child(2n + 1) text {
box-sizing: border-box; display: none;
.tablet({
width: 50%;
});
.largePhone({
width: 100%;
});
h3 {
text-align: center;
&[ng-click] {
cursor: pointer;
} }
} }
});
} }
svg { svg {

View File

@@ -266,12 +266,12 @@
<div class="group dbl"> <div class="group dbl">
<h1>Jump Range</h1> <h1>Jump Range</h1>
<div area-chart config="jrChart" series="jrSeries"></div> <div class="chart" area-chart config="jrChart" series="jrSeries"></div>
</div> </div>
<div class="group dbl"> <div class="group dbl">
<h1>Total Range</h1> <h1>Total Range</h1>
<div area-chart config="trChart" series="trSeries"></div> <div class="chart" area-chart config="trChart" series="trSeries"></div>
</div> </div>
<div class="group dbl"> <div class="group dbl">