From 9ef2f4179bbb4597399f7941271a59bc7717730a Mon Sep 17 00:00:00 2001 From: William Blythe Date: Sat, 25 Aug 2018 18:09:58 +1000 Subject: [PATCH 1/9] add alliance crusader --- src/app/utils/CompanionApiUtils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index 23fd557f..ee0a207b 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -38,6 +38,7 @@ export const SHIP_FD_NAME_TO_CORIOLIS_NAME = { 'Type9': 'type_9_heavy', 'Type9_Military': 'type_10_defender', 'TypeX': 'alliance_chieftain', + 'TypeX_2': 'alliance_crusader', 'TypeX_3': 'alliance_challenger', 'Viper': 'viper', 'Viper_MkIV': 'viper_mk_iv', From 903d791549f6169abfae5380c1d9ca16abd742c1 Mon Sep 17 00:00:00 2001 From: felixlinker Date: Tue, 28 Aug 2018 10:53:40 +0200 Subject: [PATCH 2/9] Fixed tooltip for module protection in ShipSummaryTable --- src/app/components/ShipSummaryTable.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx index b0d8d016..7bf07146 100644 --- a/src/app/components/ShipSummaryTable.jsx +++ b/src/app/components/ShipSummaryTable.jsx @@ -165,7 +165,7 @@ export default class ShipSummaryTable extends TranslatedComponent { {`${translate('kinetic')} ${translate('HP')}`} {`${translate('thermal')} ${translate('HP')}`} {translate('raw module armour')} - {translate('internal protection')} + {translate('internal protection')} From 1b5402fd2daffe7d4a84047a07e68179d94a0b02 Mon Sep 17 00:00:00 2001 From: felixlinker Date: Tue, 28 Aug 2018 12:38:47 +0200 Subject: [PATCH 3/9] Added support for caustic armour resistance --- src/app/components/Defence.jsx | 11 ++ src/app/components/InternalSlot.jsx | 1 + src/app/components/ShipSummaryTable.jsx | 183 +++++++++++++----------- src/app/i18n/en.json | 2 + src/app/shipyard/Calculations.js | 11 ++ src/app/shipyard/Module.js | 6 +- src/app/shipyard/Ship.js | 1 + src/less/outfit.less | 3 + 8 files changed, 135 insertions(+), 83 deletions(-) diff --git a/src/app/components/Defence.jsx b/src/app/components/Defence.jsx index 0528c192..3419801f 100644 --- a/src/app/components/Defence.jsx +++ b/src/app/components/Defence.jsx @@ -160,18 +160,21 @@ export default class Defence extends TranslatedComponent { const effectiveArmourExplosiveTt = []; const effectiveArmourKineticTt = []; const effectiveArmourThermalTt = []; + const effectiveArmourCausticTt = []; if (armour.bulkheads > 0) { armourSourcesTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourAbsoluteTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourExplosiveTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourKineticTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); effectiveArmourThermalTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); + effectiveArmourCausticTt.push(
{translate('bulkheads') + ' ' + formats.int(armour.bulkheads)}
); if (armour.reinforcement > 0) { armourSourcesTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourAbsoluteTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourExplosiveTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourKineticTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); effectiveArmourThermalTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); + effectiveArmourCausticTt.push(
{translate('reinforcement') + ' ' + formats.int(armour.reinforcement)}
); } } @@ -196,6 +199,11 @@ export default class Defence extends TranslatedComponent { armourDamageTakenThermalTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.thermal.reinforcement)}
); if (armour.thermal.total != 1) effectiveArmourThermalTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.thermal.total - rawArmour)}
); + const armourDamageTakenCausticTt = []; + armourDamageTakenCausticTt.push(
{translate('bulkheads') + ' ' + formats.pct1(armour.caustic.bulkheads)}
); + armourDamageTakenCausticTt.push(
{translate('reinforcement') + ' ' + formats.pct1(armour.caustic.reinforcement)}
); + if (armour.thermal.total != 1) effectiveArmourCausticTt.push(
{translate('resistance') + ' ' + formats.int(rawArmour / armour.caustic.total - rawArmour)}
); + const effectiveArmourData = []; const effectiveAbsoluteArmour = armour.total / armour.absolute.total; effectiveArmourData.push({ value: Math.round(effectiveAbsoluteArmour), label: translate('absolute'), tooltip: effectiveArmourAbsoluteTt }); @@ -205,12 +213,15 @@ export default class Defence extends TranslatedComponent { effectiveArmourData.push({ value: Math.round(effectiveKineticArmour), label: translate('kinetic'), tooltip: effectiveArmourKineticTt }); const effectiveThermalArmour = armour.total / armour.thermal.total; effectiveArmourData.push({ value: Math.round(effectiveThermalArmour), label: translate('thermal'), tooltip: effectiveArmourThermalTt }); + const effectiveCausticArmour = armour.total / armour.caustic.total; + effectiveArmourData.push({ value: Math.round(effectiveCausticArmour), label: translate('caustic'), tooltip: effectiveArmourCausticTt }); const armourDamageTakenData = []; armourDamageTakenData.push({ value: Math.round(armour.absolute.total * 100), label: translate('absolute'), tooltip: armourDamageTakenTt }); armourDamageTakenData.push({ value: Math.round(armour.explosive.total * 100), label: translate('explosive'), tooltip: armourDamageTakenExplosiveTt }); armourDamageTakenData.push({ value: Math.round(armour.kinetic.total * 100), label: translate('kinetic'), tooltip: armourDamageTakenKineticTt }); armourDamageTakenData.push({ value: Math.round(armour.thermal.total * 100), label: translate('thermal'), tooltip: armourDamageTakenThermalTt }); + armourDamageTakenData.push({ value: Math.round(armour.caustic.total * 100), label: translate('caustic'), tooltip: armourDamageTakenCausticTt }); return ( diff --git a/src/app/components/InternalSlot.jsx b/src/app/components/InternalSlot.jsx index 38f1011f..2460830b 100644 --- a/src/app/components/InternalSlot.jsx +++ b/src/app/components/InternalSlot.jsx @@ -85,6 +85,7 @@ export default class InternalSlot extends Slot { { showModuleResistances && m.getExplosiveResistance() ?
{translate('explres')}: {formats.pct(m.getExplosiveResistance())}
: null } { showModuleResistances && m.getKineticResistance() ?
{translate('kinres')}: {formats.pct(m.getKineticResistance())}
: null } { showModuleResistances && m.getThermalResistance() ?
{translate('thermres')}: {formats.pct(m.getThermalResistance())}
: null } + { showModuleResistances && m.getCausticResistance() ?
{translate('causres')}: {formats.pct(m.getCausticResistance())}
: null } { m.getHullReinforcement() ?
{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}
: null } { m.getProtection() ?
{translate('protection')}: {formats.rPct(m.getProtection())}
: null } { m.getIntegrity() ?
{translate('integrity')}: {formats.int(m.getIntegrity())}
: null } diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx index 7bf07146..82ff1032 100644 --- a/src/app/components/ShipSummaryTable.jsx +++ b/src/app/components/ShipSummaryTable.jsx @@ -63,80 +63,88 @@ export default class ShipSummaryTable extends TranslatedComponent { shieldColour }; return
- - - - - - - - - - - - {/* */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {/* */} - - - - - - - - - - - - -
{translate('speed')}{translate('boost')}{translate('jump range')}{translate('shield')}{translate('integrity')}{translate('DPS')}{translate('EPS')}{translate('TTD')}{translate('HPS')}{translate('cargo')}{translate('pax')}{translate('fuel')}{translate('mass')}{translate('hrd')}{translate('crew')}{translate('MLF')}{translate('boost time')}
{translate('max')}{translate('unladen')}{translate('laden')}{translate('total unladen')}{translate('total laden')}{translate('hull')}{translate('unladen')}{translate('laden')}
{ canThrust ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']} : 0 }{ canBoost ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']} : 0 }{f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{int(ship.shield)}{u.MJ}{int(ship.armour)}{f1(ship.totalDps)}{f1(ship.totalEps)}{timeToDrain === Infinity ? '∞' : time(timeToDrain)}{f1(ship.totalHps)}{round(ship.cargoCapacity)}{u.T}{ship.passengerCapacity}{round(ship.fuelCapacity)}{u.T}{ship.hullMass}{u.T}{int(ship.unladenMass)}{u.T}{int(ship.ladenMass)}{u.T}{int(ship.hardness)}{ship.crew}{ship.masslock}{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}
- +
+
+ + + + + + + + + + + {/* */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + + + + + + + + + + + +
{translate('speed')}{translate('boost')}{translate('jump range')}{translate('shield')}{translate('integrity')}{translate('DPS')}{translate('EPS')}{translate('TTD')}{translate('HPS')}{translate('cargo')}{translate('pax')}{translate('fuel')}{translate('mass')}{translate('hrd')}{translate('crew')}{translate('MLF')}{translate('boost time')}
{translate('max')}{translate('unladen')}{translate('laden')}{translate('total unladen')}{translate('total laden')}{translate('hull')}{translate('unladen')}{translate('laden')}
{ canThrust ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']} : 0 }{ canBoost ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']} : 0 }{f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{int(ship.shield)}{u.MJ}{int(ship.armour)}{f1(ship.totalDps)}{f1(ship.totalEps)}{timeToDrain === Infinity ? '∞' : time(timeToDrain)}{f1(ship.totalHps)}{round(ship.cargoCapacity)}{u.T}{ship.passengerCapacity}{round(ship.fuelCapacity)}{u.T}{ship.hullMass}{u.T}{int(ship.unladenMass)}{u.T}{int(ship.ladenMass)}{u.T}{int(ship.hardness)}{ship.crew}{ship.masslock}{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}
+ - - - - + + - - - - - - + + + + + + + + + + + + + + + @@ -145,29 +153,37 @@ export default class ShipSummaryTable extends TranslatedComponent { + + + - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -176,16 +192,19 @@ export default class ShipSummaryTable extends TranslatedComponent { + +
{translate('shield')}{translate('explres')}{translate('kinres')}{translate('thermres')}{translate('shield')}{translate('resistance')}{`${translate('absolute')} ${translate('HP')}`}{`${translate('explosive')} ${translate('HP')}`}{`${translate('kinetic')} ${translate('HP')}`}{`${translate('thermal')} ${translate('HP')}`}{translate('recovery')}{translate('recharge')}{`${translate('HP')}`}{translate('recovery')}{translate('recharge')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('explosive')}`}
{formats.pct1(ship.shieldExplRes)} {formats.pct1(ship.shieldKinRes)} {formats.pct1(ship.shieldThermRes)}{int(ship && ship.shield > 0 ? ship.shield : 0)}{u.MJ} {int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldExplRes)))) : 0)}{u.MJ} {int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldKinRes)))) : 0)}{u.MJ} {int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ} {sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)} {sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}
{translate('armour')}{translate('explres')}{translate('kinres')}{translate('thermres')}{`${translate('absolute')} ${translate('HP')}`}{`${translate('explosive')} ${translate('HP')}`}{`${translate('kinetic')} ${translate('HP')}`}{`${translate('thermal')} ${translate('HP')}`}{translate('raw module armour')}{translate('internal protection')}{translate('armour')}{translate('resistance')}{`${translate('HP')}`}{translate('raw module armour')}{translate('internal protection')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}
{formats.pct1(ship.hullExplRes)} {formats.pct1(ship.hullKinRes)} {formats.pct1(ship.hullThermRes)}{formats.pct1(ship.hullCausRes)} {int(ship.armour)} {int(ship.armour * ((1 / (1 - (ship.hullExplRes)))))} {int(ship.armour * ((1 / (1 - (ship.hullKinRes)))))} {int(ship.armour * ((1 / (1 - (ship.hullThermRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullCausRes)))))} {int(armourMetrics.modulearmour)} {int(armourMetrics.moduleprotection * 100) + '%'}
+
; } diff --git a/src/app/i18n/en.json b/src/app/i18n/en.json index 83f11835..f35f444c 100644 --- a/src/app/i18n/en.json +++ b/src/app/i18n/en.json @@ -85,6 +85,7 @@ "bl": "Beam Laser", "bsg": "Bi-Weave Shield Generator", "c": "Cannon", + "causres": "Caustic resistance", "cc": "Collector Limpet Controller", "ch": "Chaff Launcher", "cr": "Cargo Rack", @@ -266,6 +267,7 @@ "explosive": "Explosive", "kinetic": "Kinetic", "thermal": "Thermal", + "caustic": "Caustic", "generator": "Generator", "boosters": "Boosters", "cells": "Cells", diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js index cf66dfee..109d466e 100644 --- a/src/app/shipyard/Calculations.js +++ b/src/app/shipyard/Calculations.js @@ -564,6 +564,7 @@ export function armourMetrics(ship) { let hullExplDmg = 1; let hullKinDmg = 1; let hullThermDmg = 1; + let hullCausDmg = 1; // const dimReturnLine = (res) => 1 - (1 - res) * 0.7; // let res = { // kin: 0, @@ -582,6 +583,7 @@ export function armourMetrics(ship) { hullExplDmg = hullExplDmg * (1 - slot.m.getExplosiveResistance()); hullKinDmg = hullKinDmg * (1 - slot.m.getKineticResistance()); hullThermDmg = hullThermDmg * (1 - slot.m.getThermalResistance()); + hullCausDmg = hullCausDmg * (1 - slot.m.getCausticResistance()); } if (slot.m && slot.m.grp == 'mrp') { moduleArmour += slot.m.getIntegrity(); @@ -653,6 +655,15 @@ export function armourMetrics(ship) { total: armourReinforcedThermDmg, res: 1 - armourReinforcedThermDmg }; + + let armourCausDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getCausticResistance()); + let armourReinforcedCausDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getCausticResistance()) * hullCausDmg); + armour.caustic = { + bulkeads: armourCausDmg, + reinforcement: armourReinforcedCausDmg / armourCausDmg, + total: armourReinforcedCausDmg, + res: 1 - armourReinforcedCausDmg, + }; return armour; } diff --git a/src/app/shipyard/Module.js b/src/app/shipyard/Module.js index 350d0374..a8e5c3cd 100755 --- a/src/app/shipyard/Module.js +++ b/src/app/shipyard/Module.js @@ -48,7 +48,7 @@ export default class Module { // this special effect modifies our returned value const modification = Modifications.modifications[name]; const multiplier = modification.type === 'percentage' ? 10000 : 100; - if (name === 'explres' || name === 'kinres' || name === 'thermres') { + if (name === 'explres' || name === 'kinres' || name === 'thermres' || name === 'causres') { // Resistance modifications in itself are additive, however their // special effects are multiplicative. They affect the overall result // by (special effect resistance) * (damage mult after modification), @@ -293,6 +293,10 @@ export default class Module { return this._getModifiedValue('explres'); } + getCausticResistance() { + return this._getModifiedValue('causres'); + } + /** * Get the regeneration rate for this module, taking in to account modifications * @return {Number} the regeneration rate of this module diff --git a/src/app/shipyard/Ship.js b/src/app/shipyard/Ship.js index df219a83..19bfdf64 100755 --- a/src/app/shipyard/Ship.js +++ b/src/app/shipyard/Ship.js @@ -1295,6 +1295,7 @@ export default class Ship { this.hullExplRes = 1 - metrics.explosive.total; this.hullKinRes = 1 - metrics.kinetic.total; this.hullThermRes = 1 - metrics.thermal.total; + this.hullCausRes = 1 - metrics.caustic.total; return this; } diff --git a/src/less/outfit.less b/src/less/outfit.less index 8455feab..0ec6db88 100755 --- a/src/less/outfit.less +++ b/src/less/outfit.less @@ -93,6 +93,9 @@ color: @primary-bg; } + & thead th.bordered { + border-left: 1px solid @primary-bg; + } } } From 24f206ad8290432d102e6e4b73c98e6017bdbd1b Mon Sep 17 00:00:00 2001 From: felixlinker Date: Wed, 29 Aug 2018 11:37:14 +0200 Subject: [PATCH 4/9] Fixed ship summary table width --- src/app/components/ShipSummaryTable.jsx | 275 ++++++++++++------------ 1 file changed, 138 insertions(+), 137 deletions(-) diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx index 82ff1032..35eaba08 100644 --- a/src/app/components/ShipSummaryTable.jsx +++ b/src/app/components/ShipSummaryTable.jsx @@ -63,149 +63,150 @@ export default class ShipSummaryTable extends TranslatedComponent { shieldColour }; return
-
- - - - - - - - - - - - {/* */} - - - - - - - - - +
+
+
{translate('speed')}{translate('boost')}{translate('jump range')}{translate('shield')}{translate('integrity')}{translate('DPS')}{translate('EPS')}{translate('TTD')}{translate('HPS')}{translate('cargo')}{translate('pax')}{translate('fuel')}{translate('mass')}{translate('hrd')}{translate('crew')}{translate('MLF')}{translate('boost time')}
+ + + + + + + + + + + {/* */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* */} + + + + + + + + + + + + +
{translate('speed')}{translate('boost')}{translate('jump range')}{translate('shield')}{translate('integrity')}{translate('DPS')}{translate('EPS')}{translate('TTD')}{translate('HPS')}{translate('cargo')}{translate('pax')}{translate('fuel')}{translate('mass')}{translate('hrd')}{translate('crew')}{translate('MLF')}{translate('boost time')}
{translate('max')}{translate('unladen')}{translate('laden')}{translate('total unladen')}{translate('total laden')}{translate('hull')}{translate('unladen')}{translate('laden')}
{ canThrust ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']} : 0 }{ canBoost ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']} : 0 }{f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{int(ship.shield)}{u.MJ}{int(ship.armour)}{f1(ship.totalDps)}{f1(ship.totalEps)}{timeToDrain === Infinity ? '∞' : time(timeToDrain)}{f1(ship.totalHps)}{round(ship.cargoCapacity)}{u.T}{ship.passengerCapacity}{round(ship.fuelCapacity)}{u.T}{ship.hullMass}{u.T}{int(ship.unladenMass)}{u.T}{int(ship.ladenMass)}{u.T}{int(ship.hardness)}{ship.crew}{ship.masslock}{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}
+ + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - {/* */} - - - - - - - - - - - - -
{translate('shield')}{translate('resistance')}{`${translate('HP')}`}{translate('recovery')}{translate('recharge')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('explosive')}`}
{translate('max')}{translate('unladen')}{translate('laden')}{translate('total unladen')}{translate('total laden')}{translate('hull')}{translate('unladen')}{translate('laden')}{translate(shieldGenerator && shieldGenerator.m.grp || 'No Shield')}{formats.pct1(ship.shieldExplRes)}{formats.pct1(ship.shieldKinRes)}{formats.pct1(ship.shieldThermRes)}{int(ship && ship.shield > 0 ? ship.shield : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldExplRes)))) : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldKinRes)))) : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ}{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)}{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}
{ canThrust ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, false))}{u['m/s']} : 0 }{ canBoost ? {int(ship.calcSpeed(4, ship.fuelCapacity, 0, true))}{u['m/s']} : 0 }{f2(Calc.jumpRange(ship.unladenMass + ship.standard[2].m.getMaxFuelPerJump(), ship.standard[2].m, ship.standard[2].m.getMaxFuelPerJump(), ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.jumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{f2(Calc.totalJumpRange(ship.unladenMass + ship.fuelCapacity + ship.cargoCapacity, ship.standard[2].m, ship.fuelCapacity, ship))}{u.LY}{int(ship.shield)}{u.MJ}{int(ship.armour)}{f1(ship.totalDps)}{f1(ship.totalEps)}{timeToDrain === Infinity ? '∞' : time(timeToDrain)}{f1(ship.totalHps)}{round(ship.cargoCapacity)}{u.T}{ship.passengerCapacity}{round(ship.fuelCapacity)}{u.T}{ship.hullMass}{u.T}{int(ship.unladenMass)}{u.T}{int(ship.ladenMass)}{u.T}{int(ship.hardness)}{ship.crew}{ship.masslock}{shipBoost !== 'No Boost' ? formats.time(shipBoost) : 'No Boost'}
- - - - - + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
{translate('shield')}{translate('resistance')}
{translate('armour')}{translate('resistance')}{`${translate('HP')}`}{translate('recovery')}{translate('recharge')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('HP')}`}{translate('raw module armour')}{translate('internal protection')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('explosive')}`}
{translate(shieldGenerator && shieldGenerator.m.grp || 'No Shield')}{formats.pct1(ship.shieldExplRes)}{formats.pct1(ship.shieldKinRes)}{formats.pct1(ship.shieldThermRes)}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}
{translate(ship && ship.bulkheads && ship.bulkheads.m && ship.bulkheads.m.name || 'No Armour')}{formats.pct1(ship.hullExplRes)}{formats.pct1(ship.hullKinRes)}{formats.pct1(ship.hullThermRes)}{formats.pct1(ship.hullCausRes)}{int(ship.armour)}{int(ship.armour * ((1 / (1 - (ship.hullExplRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullKinRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullThermRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullCausRes)))))}{int(armourMetrics.modulearmour)}{int(armourMetrics.moduleprotection * 100) + '%'}{int(ship && ship.shield > 0 ? ship.shield : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldExplRes)))) : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldKinRes)))) : 0)}{u.MJ}{int(ship && ship.shield > 0 ? ship.shield * ((1 / (1 - (ship.shieldThermRes)))) : 0)}{u.MJ}{sgMetrics && sgMetrics.recover === Math.Inf ? translate('Never') : formats.time(sgMetrics.recover)}{sgMetrics && sgMetrics.recharge === Math.Inf ? translate('Never') : formats.time(sgMetrics.recharge)}
{translate('armour')}{translate('resistance')}{`${translate('HP')}`}{translate('raw module armour')}{translate('internal protection')}
{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}{`${translate('absolute')}`}{`${translate('explosive')}`}{`${translate('kinetic')}`}{`${translate('thermal')}`}{`${translate('caustic')}`}
{translate(ship && ship.bulkheads && ship.bulkheads.m && ship.bulkheads.m.name || 'No Armour')}{formats.pct1(ship.hullExplRes)}{formats.pct1(ship.hullKinRes)}{formats.pct1(ship.hullThermRes)}{formats.pct1(ship.hullCausRes)}{int(ship.armour)}{int(ship.armour * ((1 / (1 - (ship.hullExplRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullKinRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullThermRes)))))}{int(ship.armour * ((1 / (1 - (ship.hullCausRes)))))}{int(armourMetrics.modulearmour)}{int(armourMetrics.moduleprotection * 100) + '%'}
+ + + +
- ; } } From df14786e795e3936726935ad12881aa6ced330be Mon Sep 17 00:00:00 2001 From: felixlinker Date: Wed, 29 Aug 2018 11:37:28 +0200 Subject: [PATCH 5/9] Fixed bulkheads value for caustic damage --- src/app/shipyard/Calculations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shipyard/Calculations.js b/src/app/shipyard/Calculations.js index 109d466e..b7a2f22a 100644 --- a/src/app/shipyard/Calculations.js +++ b/src/app/shipyard/Calculations.js @@ -659,7 +659,7 @@ export function armourMetrics(ship) { let armourCausDmg = diminishDamageMult(0.7, 1 - ship.bulkheads.m.getCausticResistance()); let armourReinforcedCausDmg = diminishDamageMult(0.7, (1 - ship.bulkheads.m.getCausticResistance()) * hullCausDmg); armour.caustic = { - bulkeads: armourCausDmg, + bulkheads: armourCausDmg, reinforcement: armourReinforcedCausDmg / armourCausDmg, total: armourReinforcedCausDmg, res: 1 - armourReinforcedCausDmg, From d46ad89dc51e26c3c58b1b0b967ef6a3a86afddd Mon Sep 17 00:00:00 2001 From: William Blythe Date: Thu, 30 Aug 2018 08:25:50 +1000 Subject: [PATCH 6/9] fix sw waiting --- src/sw.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sw.js b/src/sw.js index a12b92a0..7d6f810d 100644 --- a/src/sw.js +++ b/src/sw.js @@ -1,6 +1,8 @@ console.log('Hello from sw.js'); if (workbox) { + workbox.skipWaiting(); + workbox.clientsClaim(); console.log('Yay! Workbox is loaded 🎉'); workbox.routing.registerRoute( new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'), From 013460ada4126284bc5651c315ea7863cfc66898 Mon Sep 17 00:00:00 2001 From: felixlinker Date: Thu, 30 Aug 2018 19:14:16 +0200 Subject: [PATCH 7/9] Ship summary table header fix --- src/app/components/ShipSummaryTable.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/ShipSummaryTable.jsx b/src/app/components/ShipSummaryTable.jsx index 35eaba08..b032dfa0 100644 --- a/src/app/components/ShipSummaryTable.jsx +++ b/src/app/components/ShipSummaryTable.jsx @@ -144,7 +144,7 @@ export default class ShipSummaryTable extends TranslatedComponent { {`${translate('absolute')}`} {`${translate('explosive')}`} {`${translate('kinetic')}`} - {`${translate('explosive')}`} + {`${translate('thermal')}`} From 8a386c4ece7ef61d68f666182b35acaf298d905a Mon Sep 17 00:00:00 2001 From: felixlinker Date: Fri, 31 Aug 2018 15:02:17 +0200 Subject: [PATCH 8/9] Use react-container-dimensions instead of react-measure --- package.json | 2 +- src/app/components/LineChart.jsx | 564 ++++++++++++------------ src/app/components/PieChart.jsx | 189 ++++---- src/app/components/VerticalBarChart.jsx | 216 +++++---- 4 files changed, 479 insertions(+), 492 deletions(-) diff --git a/package.json b/package.json index 785f0ff3..e345a228 100644 --- a/package.json +++ b/package.json @@ -88,7 +88,7 @@ "less": "^2.7.2", "less-loader": "^4.0.3", "react-addons-perf": "^15.4.2", - "react-measure": "^1.4.7", + "react-container-dimensions": "^1.4.1", "react-testutils-additions": "^15.2.0", "react-transition-group": "^1.1.2", "rimraf": "^2.6.1", diff --git a/src/app/components/LineChart.jsx b/src/app/components/LineChart.jsx index 9dd1d3ee..b4113ee6 100644 --- a/src/app/components/LineChart.jsx +++ b/src/app/components/LineChart.jsx @@ -1,283 +1,281 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import Measure from 'react-measure'; -import * as d3 from 'd3'; -import TranslatedComponent from './TranslatedComponent'; - -const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 }; - -/** - * Line Chart - */ -export default class LineChart extends TranslatedComponent { - - static defaultProps = { - code: '', - xMin: 0, - yMin: 0, - points: 20, - colors: ['#ff8c0d'], - aspect: 0.5 - }; - - static propTypes = { - func: PropTypes.func.isRequired, - xLabel: PropTypes.string.isRequired, - xMin: PropTypes.number, - xMax: PropTypes.number.isRequired, - xUnit: PropTypes.string.isRequired, - xMark: PropTypes.number, - yLabel: PropTypes.string.isRequired, - yMin: PropTypes.number, - yMax: PropTypes.number.isRequired, - yUnit: PropTypes.string, - series: PropTypes.array, - colors: PropTypes.array, - points: PropTypes.number, - aspect: PropTypes.number, - code: PropTypes.string, - }; - - /** - * Constructor - * @param {Object} props React Component properties - * @param {Object} context React Component context - */ - constructor(props, context) { - super(props); - - this._updateDimensions = this._updateDimensions.bind(this); - this._updateSeries = this._updateSeries.bind(this); - this._tooltip = this._tooltip.bind(this); - this._showTip = this._showTip.bind(this); - this._hideTip = this._hideTip.bind(this); - this._moveTip = this._moveTip.bind(this); - - const series = props.series; - - let xScale = d3.scaleLinear(); - let yScale = d3.scaleLinear(); - let xAxisScale = d3.scaleLinear(); - - this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0); - this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0); - - this.state = { - xScale, - xAxisScale, - yScale, - tipHeight: 2 + (1.2 * (series ? series.length : 0.8)), - dimensions: { - width: 100, - height: 100 - } - }; - } - - /** - * Update tooltip content - * @param {number} xPos x coordinate - */ - _tooltip(xPos) { - let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props; - let { xScale, yScale } = this.state; - let { width } = this.state.dimensions; - let { formats, translate } = this.context.language; - let x0 = xScale.invert(xPos), - y0 = func(x0), - tips = this.tipContainer, - yTotal = 0, - flip = (xPos / width > 0.50), - tipWidth = 0, - tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height; - - - xPos = xScale(x0); // Clamp xPos - - tips.selectAll('text.text-tip.y').text(function(d, i) { - let yVal = series ? y0[series[i]] : y0; - yTotal += yVal; - return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal); - }).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : ''); - - tips.selectAll('text').each(function() { - if (this.getBBox().width > tipWidth) { - tipWidth = Math.ceil(this.getBBox().width); - } - }); - - let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2)); - - tipWidth += 8; - tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')'); - tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start'); - tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit); - tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start'); - this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0)); - } - - /** - * Update dimensions based on properties and scale - * @param {Object} props React Component properties - * @param {number} scale size ratio / scale - * @returns {Object} calculated dimensions - */ - _updateDimensions(props, scale) { - const { xMax, xMin, yMin, yMax } = props; - const { width, height } = this.state.dimensions; - const innerWidth = width - MARGIN.left - MARGIN.right; - const outerHeight = Math.round(width * props.aspect); - const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom; - - this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true); - this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true); - this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility - return { innerWidth, outerHeight, innerHeight }; - } - - /** - * Show tooltip - * @param {SyntheticEvent} e Event - */ - _showTip(e) { - e.preventDefault(); - this.tipContainer.style('display', null); - this.markersContainer.style('display', null); - this._moveTip(e); - } - - /** - * Move and update tooltip - * @param {SyntheticEvent} e Event - */ - _moveTip(e) { - let clientX = e.touches ? e.touches[0].clientX : e.clientX; - this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left)); - } - - /** - * Hide tooltip - * @param {SyntheticEvent} e Event - */ - _hideTip(e) { - e.preventDefault(); - this.tipContainer.style('display', 'none'); - this.markersContainer.style('display', 'none'); - } - - /** - * Update series generated from props - * @param {Object} props React Component properties - * @param {Object} state React Component state - */ - _updateSeries(props, state) { - let { func, xMin, xMax, series, points } = props; - let delta = (xMax - xMin) / points; - let seriesData = new Array(points); - - if (delta) { - seriesData = new Array(points); - for (let i = 0, x = xMin; i < points; i++) { - seriesData[i] = [x, func(x)]; - x += delta; - } - seriesData[points - 1] = [xMax, func(xMax)]; - } else { - let yVal = func(xMin); - seriesData = [[0, yVal], [1, yVal]]; - } - - const markerElems = []; - const detailElems = []; - const seriesLines = []; - for (let i = 0, l = series ? series.length : 1; i < l; i++) { - const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]); - seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor)); - detailElems.push(); - markerElems.push(); - } - - const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8)); - - this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight }); - } - - /** - * Update dimensions and series data based on props and context. - */ - componentWillMount() { - this._updateSeries(this.props, this.state); - } - - /** - * Update state based on property and context changes - * @param {Object} nextProps Incoming/Next properties - * @param {Object} nextContext Incoming/Next conext - */ - componentWillReceiveProps(nextProps, nextContext) { - const props = this.props; - - if (props.code != nextProps.code) { - this._updateSeries(nextProps, this.state); - } - } - - /** - * Render the chart - * @return {React.Component} Chart SVG - */ - render() { - const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio); - const { width, height } = this.state.dimensions; - const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props; - const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state; - const line = this.line; - const lines = seriesLines.map((line, i) => ).reverse(); - - const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0; - const xmark = xMark ? : ''; - - return ( - { this.setState({ dimensions }); }}> -
- - - {xmark} - {lines} - d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}> - - {xLabel} - ({xUnit}) - - - d3.select(elem).call(this.yAxis)}> - - {yLabel} - { yUnit && ({yUnit}) } - - - this.tipContainer = d3.select(g)} style={{ display: 'none' }}> - - {detailElems} - - this.markersContainer = d3.select(g)} style={{ display: 'none' }}> - {markerElems} - - - - -
-
- ); - } -} +import React from 'react'; +import PropTypes from 'prop-types'; +import ContainerDimensions from 'react-container-dimensions'; +import * as d3 from 'd3'; +import TranslatedComponent from './TranslatedComponent'; + +const MARGIN = { top: 15, right: 20, bottom: 35, left: 60 }; + +/** + * Line Chart + */ +export default class LineChart extends TranslatedComponent { + + static defaultProps = { + code: '', + xMin: 0, + yMin: 0, + points: 20, + colors: ['#ff8c0d'], + aspect: 0.5 + }; + + static propTypes = { + func: PropTypes.func.isRequired, + xLabel: PropTypes.string.isRequired, + xMin: PropTypes.number, + xMax: PropTypes.number.isRequired, + xUnit: PropTypes.string.isRequired, + xMark: PropTypes.number, + yLabel: PropTypes.string.isRequired, + yMin: PropTypes.number, + yMax: PropTypes.number.isRequired, + yUnit: PropTypes.string, + series: PropTypes.array, + colors: PropTypes.array, + points: PropTypes.number, + aspect: PropTypes.number, + code: PropTypes.string, + }; + + /** + * Constructor + * @param {Object} props React Component properties + * @param {Object} context React Component context + */ + constructor(props, context) { + super(props); + + this._updateDimensions = this._updateDimensions.bind(this); + this._updateSeries = this._updateSeries.bind(this); + this._tooltip = this._tooltip.bind(this); + this._showTip = this._showTip.bind(this); + this._hideTip = this._hideTip.bind(this); + this._moveTip = this._moveTip.bind(this); + + const series = props.series; + + let xScale = d3.scaleLinear(); + let yScale = d3.scaleLinear(); + let xAxisScale = d3.scaleLinear(); + + this.xAxis = d3.axisBottom(xAxisScale).tickSizeOuter(0); + this.yAxis = d3.axisLeft(yScale).ticks(6).tickSizeOuter(0); + + this.state = { + xScale, + xAxisScale, + yScale, + tipHeight: 2 + (1.2 * (series ? series.length : 0.8)), + }; + } + + /** + * Update tooltip content + * @param {number} xPos x coordinate + * @param {number} width current container width + */ + _tooltip(xPos, width) { + let { xLabel, yLabel, xUnit, yUnit, func, series } = this.props; + let { xScale, yScale } = this.state; + let { formats, translate } = this.context.language; + let x0 = xScale.invert(xPos), + y0 = func(x0), + tips = this.tipContainer, + yTotal = 0, + flip = (xPos / width > 0.50), + tipWidth = 0, + tipHeightPx = tips.selectAll('rect').node().getBoundingClientRect().height; + + + xPos = xScale(x0); // Clamp xPos + + tips.selectAll('text.text-tip.y').text(function(d, i) { + let yVal = series ? y0[series[i]] : y0; + yTotal += yVal; + return (series ? translate(series[i]) : '') + ' ' + formats.f2(yVal); + }).append('tspan').attr('class', 'metric').text(yUnit ? ' ' + yUnit : ''); + + tips.selectAll('text').each(function() { + if (this.getBBox().width > tipWidth) { + tipWidth = Math.ceil(this.getBBox().width); + } + }); + + let tipY = Math.floor(yScale(yTotal / (series ? series.length : 1)) - (tipHeightPx / 2)); + + tipWidth += 8; + tips.attr('transform', 'translate(' + xPos + ',' + tipY + ')'); + tips.selectAll('text.text-tip').attr('x', flip ? -12 : 12).style('text-anchor', flip ? 'end' : 'start'); + tips.selectAll('text.text-tip.x').text(formats.f2(x0)).append('tspan').attr('class', 'metric').text(' ' + xUnit); + tips.selectAll('rect').attr('width', tipWidth + 4).attr('x', flip ? -tipWidth - 12 : 8).attr('y', 0).style('text-anchor', flip ? 'end' : 'start'); + this.markersContainer.selectAll('circle').attr('cx', xPos).attr('cy', (d, i) => yScale(series ? y0[series[i]] : y0)); + } + + /** + * Update dimensions based on properties and scale + * @param {Object} props React Component properties + * @param {number} scale size ratio / scale + * @param {number} width current width of the container + * @returns {Object} calculated dimensions + */ + _updateDimensions(props, scale, width) { + const { xMax, xMin, yMin, yMax } = props; + const innerWidth = width - MARGIN.left - MARGIN.right; + const outerHeight = Math.round(width * props.aspect); + const innerHeight = outerHeight - MARGIN.top - MARGIN.bottom; + + this.state.xScale.range([0, innerWidth]).domain([xMin, xMax || 1]).clamp(true); + this.state.xAxisScale.range([0, innerWidth]).domain([xMin, xMax]).clamp(true); + this.state.yScale.range([innerHeight, 0]).domain([yMin, yMax + (yMax - yMin) * 0.1]); // 10% higher than maximum value for tooltip visibility + return { innerWidth, outerHeight, innerHeight }; + } + + /** + * Show tooltip + * @param {SyntheticEvent} e Event + */ + _showTip(e) { + e.preventDefault(); + this.tipContainer.style('display', null); + this.markersContainer.style('display', null); + this._moveTip(e); + } + + /** + * Move and update tooltip + * @param {SyntheticEvent} e Event + * @param {number} width current container width + */ + _moveTip(e, width) { + let clientX = e.touches ? e.touches[0].clientX : e.clientX; + this._tooltip(Math.round(clientX - e.currentTarget.getBoundingClientRect().left), width); + } + + /** + * Hide tooltip + * @param {SyntheticEvent} e Event + */ + _hideTip(e) { + e.preventDefault(); + this.tipContainer.style('display', 'none'); + this.markersContainer.style('display', 'none'); + } + + /** + * Update series generated from props + * @param {Object} props React Component properties + * @param {Object} state React Component state + */ + _updateSeries(props, state) { + let { func, xMin, xMax, series, points } = props; + let delta = (xMax - xMin) / points; + let seriesData = new Array(points); + + if (delta) { + seriesData = new Array(points); + for (let i = 0, x = xMin; i < points; i++) { + seriesData[i] = [x, func(x)]; + x += delta; + } + seriesData[points - 1] = [xMax, func(xMax)]; + } else { + let yVal = func(xMin); + seriesData = [[0, yVal], [1, yVal]]; + } + + const markerElems = []; + const detailElems = []; + const seriesLines = []; + for (let i = 0, l = series ? series.length : 1; i < l; i++) { + const yAccessor = series ? function(d) { return state.yScale(d[1][this]); }.bind(series[i]) : (d) => state.yScale(d[1]); + seriesLines.push(d3.line().x((d, i) => this.state.xScale(d[0])).y(yAccessor)); + detailElems.push(); + markerElems.push(); + } + + const tipHeight = 2 + (1.2 * (seriesLines ? seriesLines.length : 0.8)); + + this.setState({ markerElems, detailElems, seriesLines, seriesData, tipHeight }); + } + + /** + * Update dimensions and series data based on props and context. + */ + componentWillMount() { + this._updateSeries(this.props, this.state); + } + + /** + * Update state based on property and context changes + * @param {Object} nextProps Incoming/Next properties + * @param {Object} nextContext Incoming/Next conext + */ + componentWillReceiveProps(nextProps, nextContext) { + const props = this.props; + + if (props.code != nextProps.code) { + this._updateSeries(nextProps, this.state); + } + } + + /** + * Render the chart + * @return {React.Component} Chart SVG + */ + render() { + return ( + + { ({ width, height }) => { + const { innerWidth, outerHeight, innerHeight } = this._updateDimensions(this.props, this.context.sizeRatio, width, height); + const { xMin, xMax, xLabel, yLabel, xUnit, yUnit, xMark, colors } = this.props; + const { tipHeight, detailElems, markerElems, seriesData, seriesLines } = this.state; + const lines = seriesLines.map((line, i) => ).reverse(); + + const markX = xMark ? innerWidth * (xMark - xMin) / (xMax - xMin) : 0; + const xmark = xMark ? : ''; + return ( +
+ + + {xmark} + {lines} + d3.select(elem).call(this.xAxis)} transform={`translate(0,${innerHeight})`}> + + {xLabel} + ({xUnit}) + + + d3.select(elem).call(this.yAxis)}> + + {yLabel} + { yUnit && ({yUnit}) } + + + this.tipContainer = d3.select(g)} style={{ display: 'none' }}> + + {detailElems} + + this.markersContainer = d3.select(g)} style={{ display: 'none' }}> + {markerElems} + + this._moveTip(e, width)} + onTouchMove={e => this._moveTip(e, width)} + /> + + +
+ ); + }} +
+ ); + } +} diff --git a/src/app/components/PieChart.jsx b/src/app/components/PieChart.jsx index d1ce9717..1c9ccac8 100644 --- a/src/app/components/PieChart.jsx +++ b/src/app/components/PieChart.jsx @@ -1,97 +1,92 @@ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; -import Measure from 'react-measure'; -import * as d3 from 'd3'; - -const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D']; -const LABEL_COLOUR = '#000000'; - -/** - * A pie chart - */ -export default class PieChart extends Component { - - static propTypes = { - data : PropTypes.array.isRequired - }; - - /** - * Constructor - * @param {Object} props React Component properties - * @param {Object} context React Component context - */ - constructor(props, context) { - super(props); - - this.pie = d3.pie().value((d) => d.value); - this.colors = CORIOLIS_COLOURS; - this.arc = d3.arc(); - this.arc.innerRadius(0); - - this.state = { - dimensions: { - width: 100, - height: 100 - } - }; - } - - - /** - * Generate a slice of the pie chart - * @param {Object} d the data for this slice - * @param {number} i the index of this slice - * @returns {Object} the SVG for the slice - */ - sliceGenerator(d, i) { - if (!d || d.value == 0) { - // Ignore 0 values - return null; - } - - const { width, height } = this.state.dimensions; - const { data } = this.props; - - // Push the labels further out from the centre of the slice - let [labelX, labelY] = this.arc.centroid(d); - const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`; - - // Put the keys in a line with equal spacing - const nonZeroItems = data.filter(d => d.value != 0).length; - const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1; - const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5); - const keyTranslate = `translate(${keyX}, ${width * 0.45})`; - - return ( - - - {d.value} - {d.data.label} - - ); - } - - /** - * Render the component - * @returns {object} Markup - */ - render() { - const { width, height } = this.state.dimensions; - const pie = this.pie(this.props.data), - translate = `translate(${width / 2}, ${width * 0.4})`; - - this.arc.outerRadius(width * 0.4); - - return ( - { this.setState({ dimensions }); }}> -
- - - {pie.map((d, i) => this.sliceGenerator(d, i))} - - -
-
- ); - } -} +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import ContainerDimensions from 'react-container-dimensions'; +import * as d3 from 'd3'; + +const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D']; +const LABEL_COLOUR = '#000000'; + +/** + * A pie chart + */ +export default class PieChart extends Component { + + static propTypes = { + data : PropTypes.array.isRequired + }; + + /** + * Constructor + * @param {Object} props React Component properties + * @param {Object} context React Component context + */ + constructor(props, context) { + super(props); + + this.pie = d3.pie().value((d) => d.value); + this.colors = CORIOLIS_COLOURS; + this.arc = d3.arc(); + this.arc.innerRadius(0); + } + + + /** + * Generate a slice of the pie chart + * @param {Object} d the data for this slice + * @param {number} i the index of this slice + * @param {number} width the current width of the parent container + * @returns {Object} the SVG for the slice + */ + sliceGenerator(d, i, width) { + if (!d || d.value == 0) { + // Ignore 0 values + return null; + } + + const { data } = this.props; + + // Push the labels further out from the centre of the slice + let [labelX, labelY] = this.arc.centroid(d); + const labelTranslate = `translate(${labelX * 1.5}, ${labelY * 1.5})`; + + // Put the keys in a line with equal spacing + const nonZeroItems = data.filter(d => d.value != 0).length; + const thisItemIndex = data.slice(0, i + 1).filter(d => d.value != 0).length - 1; + const keyX = -width / 2 + (width / nonZeroItems) * (thisItemIndex + 0.5); + const keyTranslate = `translate(${keyX}, ${width * 0.45})`; + + return ( + + + {d.value} + {d.data.label} + + ); + } + + /** + * Render the component + * @returns {object} Markup + */ + render() { + return ( + + { ({ width }) => { + const pie = this.pie(this.props.data), + translate = `translate(${width / 2}, ${width * 0.4})`; + + this.arc.outerRadius(width * 0.4); + return ( +
+ + + {pie.map((d, i) => this.sliceGenerator(d, i, width))} + + +
+ ); + }} +
+ ); + } +} diff --git a/src/app/components/VerticalBarChart.jsx b/src/app/components/VerticalBarChart.jsx index d4cbee36..52774ef9 100644 --- a/src/app/components/VerticalBarChart.jsx +++ b/src/app/components/VerticalBarChart.jsx @@ -1,111 +1,105 @@ -import TranslatedComponent from './TranslatedComponent'; -import React, { PropTypes } from 'react'; -import Measure from 'react-measure'; -import { BarChart, Bar, XAxis, YAxis } from 'recharts'; - -const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D']; -const LABEL_COLOUR = '#000000'; -const AXIS_COLOUR = '#C06400'; - -const ASPECT = 1; - -const merge = function(one, two) { - return Object.assign({}, one, two); -}; - -/** - * A vertical bar chart - */ -export default class VerticalBarChart extends TranslatedComponent { - - static propTypes = { - data : PropTypes.array.isRequired, - yMax : PropTypes.number - }; - - /** - * Constructor - * @param {Object} props React Component properties - * @param {Object} context React Component context - */ - constructor(props, context) { - super(props); - - this._termtip = this._termtip.bind(this); - - this.state = { - dimensions: { - width: 300, - height: 300 - } - }; - } - - /** - * Render the bar chart - * @returns {Object} the markup - */ - render() { - const { width, height } = this.state.dimensions; - const { tooltip, termtip } = this.context; - - // Calculate maximum for Y - let dataMax = Math.max(...this.props.data.map(d => d.value)); - if (dataMax == -Infinity) dataMax = 0; - let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0; - const localMax = Math.max(dataMax, yMax); - - return ( - this.setState({ dimensions }) }> -
- - - - } fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}/> - -
-
- ); - } - - /** - * Generate a term tip - * @param {Object} d the data - * @param {number} i the index - * @param {Object} e the event - * @returns {Object} termtip markup - */ - _termtip(d, i, e) { - if (this.props.data[i].tooltip) { - return this.context.termtip(this.props.data[i].tooltip, e); - } else { - return null; - } - } -} - -/** - * A label that displays the value within the bar of the chart - */ -class ValueLabel extends React.Component { - static propTypes = { - x: PropTypes.number, - y: PropTypes.number, - payload: PropTypes.object, - value: PropTypes.number - }; - - /** - * Render offence - * @return {React.Component} contents - */ - render() { - const { x, y, payload, value } = this.props; - - const em = value < 1000 ? '1em' : value < 1000 ? '0.8em' : '0.7em'; - - return ( - {value} - ); - } -}; +import TranslatedComponent from './TranslatedComponent'; +import React, { PropTypes } from 'react'; +import ContainerDimensions from 'react-container-dimensions'; +import { BarChart, Bar, XAxis, YAxis } from 'recharts'; + +const CORIOLIS_COLOURS = ['#FF8C0D', '#1FB0FF', '#71A052', '#D5D54D']; +const LABEL_COLOUR = '#000000'; +const AXIS_COLOUR = '#C06400'; + +const ASPECT = 1; + +const merge = function(one, two) { + return Object.assign({}, one, two); +}; + +/** + * A vertical bar chart + */ +export default class VerticalBarChart extends TranslatedComponent { + + static propTypes = { + data : PropTypes.array.isRequired, + yMax : PropTypes.number + }; + + /** + * Constructor + * @param {Object} props React Component properties + * @param {Object} context React Component context + */ + constructor(props, context) { + super(props); + + this._termtip = this._termtip.bind(this); + } + + /** + * Render the bar chart + * @returns {Object} the markup + */ + render() { + const { tooltip, termtip } = this.context; + + // Calculate maximum for Y + let dataMax = Math.max(...this.props.data.map(d => d.value)); + if (dataMax == -Infinity) dataMax = 0; + let yMax = this.props.yMax ? Math.round(this.props.yMax) : 0; + const localMax = Math.max(dataMax, yMax); + + return ( + + { ({ width }) => ( +
+ + + + } fill={CORIOLIS_COLOURS[0]} isAnimationActive={false} onMouseOver={this._termtip} onMouseOut={tooltip.bind(null, null)}/> + +
+ )} +
+ ); + } + + /** + * Generate a term tip + * @param {Object} d the data + * @param {number} i the index + * @param {Object} e the event + * @returns {Object} termtip markup + */ + _termtip(d, i, e) { + if (this.props.data[i].tooltip) { + return this.context.termtip(this.props.data[i].tooltip, e); + } else { + return null; + } + } +} + +/** + * A label that displays the value within the bar of the chart + */ +class ValueLabel extends React.Component { + static propTypes = { + x: PropTypes.number, + y: PropTypes.number, + payload: PropTypes.object, + value: PropTypes.number + }; + + /** + * Render offence + * @return {React.Component} contents + */ + render() { + const { x, y, payload, value } = this.props; + + const em = value < 1000 ? '1em' : value < 1000 ? '0.8em' : '0.7em'; + + return ( + {value} + ); + } +}; From ec70ad5d29946bed2f0c2ae6e77375219dba0c06 Mon Sep 17 00:00:00 2001 From: felixlinker Date: Fri, 31 Aug 2018 15:02:44 +0200 Subject: [PATCH 9/9] WeaponDamageChart wrapped in div instead of span --- src/app/components/WeaponDamageChart.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/components/WeaponDamageChart.jsx b/src/app/components/WeaponDamageChart.jsx index fb4d8a49..610e1755 100644 --- a/src/app/components/WeaponDamageChart.jsx +++ b/src/app/components/WeaponDamageChart.jsx @@ -74,7 +74,7 @@ export default class WeaponDamageChart extends TranslatedComponent { * Calculate the maximum range of a ship's weapons * @param {Object} ship The ship * @returns {int} The maximum range, in metres - */ + */ _calcMaxRange(ship) { let maxRange = 1000; // Minimum for (let i = 0; i < ship.hardpoints.length; i++) { @@ -184,7 +184,7 @@ export default class WeaponDamageChart extends TranslatedComponent { const code = `${ship.toString()}:${opponent.toString()}`; return ( - +
- +
); } }