diff options
author | notoraptor <stevenbocco@gmail.com> | 2019-08-14 12:22:22 -0400 |
---|---|---|
committer | Philip Paquette <pcpaquette@gmail.com> | 2019-08-14 12:40:01 -0400 |
commit | 5c3bd9b3802e2001a7e77baf2911386135a03839 (patch) | |
tree | e641744650b05cddc85bc60c2d7e2d6fe2d88b47 /diplomacy/web/src/gui/maps/common | |
parent | 5acb4ff23be4757a49b234f93928f13c436b60c6 (diff) |
[Web] Integrated new maps on the web interface
- Fixed bug with incorrect dislodged unit on pure map
- [python] Make sure dummy powers are registered only for standard maps.
- Hardcoded supply centers into SVG files.
- Removed supply centers CSS classes.
- Update positions for units and dislodged units on all maps.
- Converted SVGs to React.
- Removed "sym" classes and hardcode related styles into symbol definitions.
- Reordered map list (standard at top, then other ones in alphabetical order)
- Displayed + button for all maps and disable it for maps without variants.
- Minified generated code when converting SVG files to React.
- [web] Added ability to hide/display map abbreviations.
Diffstat (limited to 'diplomacy/web/src/gui/maps/common')
-rw-r--r-- | diplomacy/web/src/gui/maps/common/build.js | 57 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/common.js | 83 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/convoy.js | 103 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/disband.js | 47 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/equilateralTriangle.js | 122 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/hold.js | 47 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/move.js | 67 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/supportHold.js | 72 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/supportMove.js | 61 | ||||
-rw-r--r-- | diplomacy/web/src/gui/maps/common/unit.js | 50 |
10 files changed, 709 insertions, 0 deletions
diff --git a/diplomacy/web/src/gui/maps/common/build.js b/diplomacy/web/src/gui/maps/common/build.js new file mode 100644 index 0000000..765dbad --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/build.js @@ -0,0 +1,57 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {ARMY, centerSymbolAroundUnit, FLEET} from "./common"; +import PropTypes from "prop-types"; + +export class Build extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const loc = this.props.loc; + const unit_type = this.props.unitType; + const build_symbol = 'BuildUnit'; + const loc_x = Coordinates[loc].unit[0]; + const loc_y = Coordinates[loc].unit[1]; + const [build_loc_x, build_loc_y] = centerSymbolAroundUnit(Coordinates, SymbolSizes, loc, false, build_symbol); + + const symbol = unit_type === 'A' ? ARMY : FLEET; + return ( + <g> + <use x={build_loc_x} + y={build_loc_y} + height={SymbolSizes[build_symbol].height} + width={SymbolSizes[build_symbol].width} + href={`#${build_symbol}`}/> + <use x={loc_x} + y={loc_y} + height={SymbolSizes[symbol].height} + width={SymbolSizes[symbol].width} + href={`#${symbol}`} + className={`unit${this.props.powerName.toLowerCase()}`}/> + </g> + ); + } +} + +Build.propTypes = { + unitType: PropTypes.string.isRequired, + loc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/common.js b/diplomacy/web/src/gui/maps/common/common.js new file mode 100644 index 0000000..750f786 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/common.js @@ -0,0 +1,83 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== + +export const ARMY = 'Army'; +export const FLEET = 'Fleet'; + +export function offset(floatString, offset) { + return "" + (parseFloat(floatString) + offset); +} + +export function setInfluence(classes, mapData, loc, power_name) { + const province = mapData.getProvince(loc); + if (!province) + throw new Error(`Unable to find province ${loc}`); + if (!['LAND', 'COAST'].includes(province.type)) + return; + const id = province.getID(classes); + if (!id) + throw new Error(`Unable to find SVG path for loc ${id}`); + classes[id] = power_name ? power_name.toLowerCase() : 'nopower'; +} + +export function getClickedID(event) { + let node = event.target; + if (!node.id && node.parentNode.id && node.parentNode.tagName === 'g') + node = node.parentNode; + let id = node.id; + return id ? id.substr(0, 3) : null; +} + +export function parseLocation(txt) { + if (txt.length > 2 && txt[1] === ' ' && ['A', 'F'].includes(txt[0])) + return txt.substr(2); + return txt; +} + +export function centerSymbolAroundUnit(coordinates, symbolSizes, loc, isDislodged, symbol) { + const key = isDislodged ? 'disl' : 'unit'; + const unitKey = ARMY; + const [unit_x, unit_y] = coordinates[loc][key]; + const unit_height = symbolSizes[unitKey].height; + const unit_width = symbolSizes[unitKey].width; + const symbol_height = symbolSizes[symbol].height; + const symbol_width = symbolSizes[symbol].width; + return [ + `${(parseFloat(unit_x) + parseFloat(unit_width) / 2 - parseFloat(symbol_width) / 2)}`, + `${(parseFloat(unit_y) + parseFloat(unit_height) / 2 - parseFloat(symbol_height) / 2)}` + ]; +} + +export function getUnitCenter(coordinates, symbolSizes, loc, isDislodged) { + const key = isDislodged ? 'disl' : 'unit'; + const unitKey = ARMY; + const [unit_x, unit_y] = coordinates[loc][key]; + const unit_height = symbolSizes[unitKey].height; + const unit_width = symbolSizes[unitKey].width; + return [ + `${parseFloat(unit_x) + parseFloat(unit_width) / 2}`, + `${parseFloat(unit_y) + parseFloat(unit_height) / 2}` + ]; +} + +export function plainStrokeWidth(symbolSizes) { + return parseFloat(symbolSizes.Stroke.height); +} + +export function coloredStrokeWidth(symbolSizes) { + return parseFloat(symbolSizes.Stroke.width); +} diff --git a/diplomacy/web/src/gui/maps/common/convoy.js b/diplomacy/web/src/gui/maps/common/convoy.js new file mode 100644 index 0000000..c966161 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/convoy.js @@ -0,0 +1,103 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {ARMY, centerSymbolAroundUnit, coloredStrokeWidth, getUnitCenter} from "./common"; +import {EquilateralTriangle} from "./equilateralTriangle"; +import PropTypes from "prop-types"; + +export class Convoy extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const Colors = this.props.colors; + const loc = this.props.loc; + const src_loc = this.props.srcLoc; + const dest_loc = this.props.dstLoc; + + const symbol = 'ConvoyTriangle'; + let [symbol_loc_x, symbol_loc_y] = centerSymbolAroundUnit(Coordinates, SymbolSizes, src_loc, false, symbol); + const symbol_height = parseFloat(SymbolSizes[symbol].height); + const symbol_width = parseFloat(SymbolSizes[symbol].width); + const triangle = new EquilateralTriangle( + parseFloat(symbol_loc_x) + symbol_width / 2, + parseFloat(symbol_loc_y), + parseFloat(symbol_loc_x) + symbol_width, + parseFloat(symbol_loc_y) + symbol_height, + parseFloat(symbol_loc_x), + parseFloat(symbol_loc_y) + symbol_height + ); + symbol_loc_y = '' + (parseFloat(symbol_loc_y) - symbol_height / 6); + const [loc_x, loc_y] = getUnitCenter(Coordinates, SymbolSizes, loc, false); + const [src_loc_x, src_loc_y] = getUnitCenter(Coordinates, SymbolSizes, src_loc, false); + let [dest_loc_x, dest_loc_y] = getUnitCenter(Coordinates, SymbolSizes, dest_loc, false); + + const [src_loc_x_1, src_loc_y_1] = triangle.intersection(loc_x, loc_y); + const [src_loc_x_2, src_loc_y_2] = triangle.intersection(dest_loc_x, dest_loc_y); + + const dest_delta_x = dest_loc_x - src_loc_x; + const dest_delta_y = dest_loc_y - src_loc_y; + const dest_vector_length = Math.sqrt(dest_delta_x * dest_delta_x + dest_delta_y * dest_delta_y); + const delta_dec = parseFloat(SymbolSizes[ARMY].width) / 2 + 2 * coloredStrokeWidth(SymbolSizes); + dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (dest_vector_length - delta_dec) / dest_vector_length * dest_delta_x) * 100.) / 100.; + dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (dest_vector_length - delta_dec) / dest_vector_length * dest_delta_y) * 100.) / 100.; + + return ( + <g stroke={Colors[this.props.powerName]}> + <line x1={loc_x} + y1={loc_y} + x2={src_loc_x_1} + y2={src_loc_y_1} + className={'shadowdash'}/> + <line x1={src_loc_x_2} + y1={src_loc_y_2} + x2={dest_loc_x} + y2={dest_loc_y} + className={'shadowdash'}/> + <line x1={loc_x} + y1={loc_y} + x2={src_loc_x_1} + y2={src_loc_y_1} + className={'convoyorder'} + stroke={Colors[this.props.powerName]}/> + <line x1={src_loc_x_2} + y1={src_loc_y_2} + x2={dest_loc_x} + y2={dest_loc_y} + className={'convoyorder'} + markerEnd={'url(#arrow)'} + stroke={Colors[this.props.powerName]}/> + <use + x={symbol_loc_x} + y={symbol_loc_y} + width={'' + symbol_width} + height={'' + symbol_height} + href={`#${symbol}`} + /> + </g> + ); + } +} + +Convoy.propTypes = { + loc: PropTypes.string.isRequired, + srcLoc: PropTypes.string.isRequired, + dstLoc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired, + colors: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/disband.js b/diplomacy/web/src/gui/maps/common/disband.js new file mode 100644 index 0000000..97d5c04 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/disband.js @@ -0,0 +1,47 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {centerSymbolAroundUnit} from "./common"; +import PropTypes from "prop-types"; + +export class Disband extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const loc = this.props.loc; + const phaseType = this.props.phaseType; + const symbol = 'RemoveUnit'; + const [loc_x, loc_y] = centerSymbolAroundUnit(Coordinates, SymbolSizes, loc, phaseType === 'R', symbol); + return ( + <g> + <use x={loc_x} + y={loc_y} + height={SymbolSizes[symbol].height} + width={SymbolSizes[symbol].width} + href={`#${symbol}`} + /> + </g> + ); + } +} + +Disband.propTypes = { + loc: PropTypes.string.isRequired, + phaseType: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/equilateralTriangle.js b/diplomacy/web/src/gui/maps/common/equilateralTriangle.js new file mode 100644 index 0000000..8c433ea --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/equilateralTriangle.js @@ -0,0 +1,122 @@ +export class EquilateralTriangle { + /** Helper class that represent an equilateral triangle.; + Used to compute intersection of a line with a side of convoy symbol, which is an equilateral triangle. **/ + constructor(x_top, y_top, x_right, y_right, x_left, y_left) { + this.x_A = x_top; + this.y_A = y_top; + this.x_B = x_right; + this.y_B = y_right; + this.x_C = x_left; + this.y_C = y_left; + this.h = this.y_B - this.y_A; + this.x_O = this.x_A; + this.y_O = this.y_A + 2 * this.h / 3; + this.line_AB_a = (this.y_B - this.y_A) / (this.x_B - this.x_A); + this.line_AB_b = this.y_B - this.x_B * this.line_AB_a; + this.line_AC_a = (this.y_C - this.y_A) / (this.x_C - this.x_A); + this.line_AC_b = this.y_C - this.x_C * this.line_AC_a; + } + + __line_OM(x_M, y_M) { + const a = (y_M - this.y_O) / (x_M - this.x_O); + const b = y_M - a * x_M; + return [a, b]; + } + + __intersection_with_AB(x_M, y_M) { + const [a, b] = [this.line_AB_a, this.line_AB_b]; + let x = null; + if (x_M === this.x_O) { + x = x_M; + } else { + const [u, v] = this.__line_OM(x_M, y_M); + if (a === u) + return [null, null]; + x = (v - b) / (a - u); + } + const y = a * x + b; + if (this.x_A <= x && x <= this.x_B && this.y_A <= y && y <= this.y_B) + return [x, y]; + return [null, null]; + } + + __intersection_with_AC(x_M, y_M) { + const [a, b] = [this.line_AC_a, this.line_AC_b]; + let x = null; + if (x_M === this.x_O) { + x = x_M; + } else { + const [u, v] = this.__line_OM(x_M, y_M); + if (a === u) + return [null, null]; + x = (v - b) / (a - u); + } + const y = a * x + b; + if (this.x_C <= x && x <= this.x_A && this.y_A <= y && y <= this.y_C) + return [x, y]; + return [null, null]; + } + + __intersection_with_BC(x_M, y_M) { + const y = this.y_C; + let x = null; + if (x_M === this.x_O) { + x = x_M; + } else { + const [a, b] = this.__line_OM(x_M, y_M); + if (a === 0) + return [null, null]; + x = (y - b) / a; + } + if (this.x_C <= x && x <= this.x_A) + return [x, y]; + return [null, null]; + } + + intersection(x_M, y_M) { + if (this.x_O === x_M && this.y_O === y_M) + return [x_M, y_M]; + if (this.x_O === x_M) { + if (y_M < this.y_O) + return [x_M, this.y_A]; + else { + // vertical line intersects BC; + return [x_M, this.y_C]; + } + } else if (this.y_O === y_M) { + let a = null; + let b = null; + if (x_M < this.x_O) { + // horizontal line intersects AC; + [a, b] = [this.line_AC_a, this.line_AC_b]; + } else { + // horizontal line intersects AB; + [a, b] = [this.line_AB_a, this.line_AB_b]; + } + const x = (y_M - b) / a; + return [x, y_M]; + } else { + // get nearest point in intersections with AB, AC, BC; + const [p1_x, p1_y] = this.__intersection_with_AB(x_M, y_M); + const [p2_x, p2_y] = this.__intersection_with_AC(x_M, y_M); + const [p3_x, p3_y] = this.__intersection_with_BC(x_M, y_M); + const distances = []; + if (p1_x !== null) { + const d1 = Math.sqrt((p1_x - x_M) * (p1_x - x_M) + (p1_y - y_M) * (p1_y - y_M)); + distances.push([d1, p1_x, p1_y]); + } + if (p2_x !== null) { + const d2 = Math.sqrt((p2_x - x_M) * (p2_x - x_M) + (p2_y - y_M) * (p2_y - y_M)); + distances.push([d2, p2_x, p2_y]); + } + if (p3_x !== null) { + const d3 = Math.sqrt((p3_x - x_M) * (p3_x - x_M) + (p3_y - y_M) * (p3_y - y_M)); + distances.push([d3, p3_x, p3_y]); + } + distances.sort(); + const output = distances[0]; + output.shift(); + return output; + } + } +} diff --git a/diplomacy/web/src/gui/maps/common/hold.js b/diplomacy/web/src/gui/maps/common/hold.js new file mode 100644 index 0000000..ce77ec5 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/hold.js @@ -0,0 +1,47 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {centerSymbolAroundUnit} from "./common"; +import PropTypes from "prop-types"; + +export class Hold extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const Colors = this.props.colors; + const SymbolSizes = this.props.symbolSizes; + const symbol = 'HoldUnit'; + const [loc_x, loc_y] = centerSymbolAroundUnit(Coordinates, SymbolSizes, this.props.loc, false, symbol); + return ( + <g stroke={Colors[this.props.powerName]}> + <use + x={loc_x} + y={loc_y} + width={SymbolSizes[symbol].width} + height={SymbolSizes[symbol].height} + href={`#${symbol}`}/> + </g> + ); + } +} + +Hold.propTypes = { + loc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired, + colors: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/move.js b/diplomacy/web/src/gui/maps/common/move.js new file mode 100644 index 0000000..cefb6de --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/move.js @@ -0,0 +1,67 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {ARMY, coloredStrokeWidth, getUnitCenter, plainStrokeWidth} from "./common"; +import PropTypes from "prop-types"; + +export class Move extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const Colors = this.props.colors; + const src_loc = this.props.srcLoc; + const dest_loc = this.props.dstLoc; + const is_dislodged = this.props.phaseType === 'R'; + const [src_loc_x, src_loc_y] = getUnitCenter(Coordinates, SymbolSizes, src_loc, is_dislodged); + let [dest_loc_x, dest_loc_y] = getUnitCenter(Coordinates, SymbolSizes, dest_loc, is_dislodged); + // Adjusting destination + const delta_x = dest_loc_x - src_loc_x; + const delta_y = dest_loc_y - src_loc_y; + const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y); + const delta_dec = parseFloat(SymbolSizes[ARMY].width) / 2 + 2 * coloredStrokeWidth(SymbolSizes); + dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (vector_length - delta_dec) / vector_length * delta_x) * 100.) / 100.; + dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (vector_length - delta_dec) / vector_length * delta_y) * 100.) / 100.; + return ( + <g> + <line x1={src_loc_x} + y1={src_loc_y} + x2={dest_loc_x} + y2={dest_loc_y} + className={'varwidthshadow'} + strokeWidth={'' + plainStrokeWidth(SymbolSizes)}/> + <line x1={src_loc_x} + y1={src_loc_y} + x2={dest_loc_x} + y2={dest_loc_y} + className={'varwidthorder'} + markerEnd={'url(#arrow)'} + stroke={Colors[this.props.powerName]} + strokeWidth={'' + coloredStrokeWidth(SymbolSizes)}/> + </g> + ); + } +} + +Move.propTypes = { + srcLoc: PropTypes.string.isRequired, + dstLoc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + phaseType: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired, + colors: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/supportHold.js b/diplomacy/web/src/gui/maps/common/supportHold.js new file mode 100644 index 0000000..9b350d2 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/supportHold.js @@ -0,0 +1,72 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {centerSymbolAroundUnit, getUnitCenter} from "./common"; +import PropTypes from "prop-types"; + +export class SupportHold extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const Colors = this.props.colors; + const loc = this.props.loc; + const dest_loc = this.props.dstLoc; + const symbol = 'SupportHoldUnit'; + const [symbol_loc_x, symbol_loc_y] = centerSymbolAroundUnit(Coordinates, SymbolSizes, dest_loc, false, symbol); + const [loc_x, loc_y] = getUnitCenter(Coordinates, SymbolSizes, loc, false); + let [dest_loc_x, dest_loc_y] = getUnitCenter(Coordinates, SymbolSizes, dest_loc, false); + + const delta_x = dest_loc_x - loc_x; + const delta_y = dest_loc_y - loc_y; + const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y); + const delta_dec = parseFloat(SymbolSizes[symbol].height) / 2; + dest_loc_x = '' + Math.round((parseFloat(loc_x) + (vector_length - delta_dec) / vector_length * delta_x) * 100.) / 100.; + dest_loc_y = '' + Math.round((parseFloat(loc_y) + (vector_length - delta_dec) / vector_length * delta_y) * 100.) / 100.; + + return ( + <g stroke={Colors[this.props.powerName]}> + <line x1={loc_x} + y1={loc_y} + x2={dest_loc_x} + y2={dest_loc_y} + className={'shadowdash'}/> + <line x1={loc_x} + y1={loc_y} + x2={dest_loc_x} + y2={dest_loc_y} + className={'supportorder'} + stroke={Colors[this.props.powerName]}/> + <use + x={symbol_loc_x} + y={symbol_loc_y} + width={SymbolSizes[symbol].width} + height={SymbolSizes[symbol].height} + href={`#${symbol}`} + /> + </g> + ); + } +} + +SupportHold.propTypes = { + loc: PropTypes.string.isRequired, + dstLoc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired, + colors: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/supportMove.js b/diplomacy/web/src/gui/maps/common/supportMove.js new file mode 100644 index 0000000..e52e37f --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/supportMove.js @@ -0,0 +1,61 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {ARMY, coloredStrokeWidth, getUnitCenter} from "./common"; +import PropTypes from "prop-types"; + +export class SupportMove extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const Colors = this.props.colors; + const loc = this.props.loc; + const src_loc = this.props.srcLoc; + const dest_loc = this.props.dstLoc; + const [loc_x, loc_y] = getUnitCenter(Coordinates, SymbolSizes, loc, false); + const [src_loc_x, src_loc_y] = getUnitCenter(Coordinates, SymbolSizes, src_loc, false); + let [dest_loc_x, dest_loc_y] = getUnitCenter(Coordinates, SymbolSizes, dest_loc, false); + + // Adjusting destination + const delta_x = dest_loc_x - src_loc_x; + const delta_y = dest_loc_y - src_loc_y; + const vector_length = Math.sqrt(delta_x * delta_x + delta_y * delta_y); + const delta_dec = parseFloat(SymbolSizes[ARMY].width) / 2 + 2 * coloredStrokeWidth(SymbolSizes); + dest_loc_x = '' + Math.round((parseFloat(src_loc_x) + (vector_length - delta_dec) / vector_length * delta_x) * 100.) / 100.; + dest_loc_y = '' + Math.round((parseFloat(src_loc_y) + (vector_length - delta_dec) / vector_length * delta_y) * 100.) / 100.; + return ( + <g> + <path className={'shadowdash'} + d={`M ${loc_x},${loc_y} C ${src_loc_x},${src_loc_y} ${src_loc_x},${src_loc_y} ${dest_loc_x},${dest_loc_y}`}/> + <path className={'supportorder'} + markerEnd={'url(#arrow)'} + stroke={Colors[this.props.powerName]} + d={`M ${loc_x},${loc_y} C ${src_loc_x},${src_loc_y} ${src_loc_x},${src_loc_y} ${dest_loc_x},${dest_loc_y}`}/> + </g> + ); + } +} + +SupportMove.propTypes = { + loc: PropTypes.string.isRequired, + srcLoc: PropTypes.string.isRequired, + dstLoc: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired, + colors: PropTypes.object.isRequired +}; diff --git a/diplomacy/web/src/gui/maps/common/unit.js b/diplomacy/web/src/gui/maps/common/unit.js new file mode 100644 index 0000000..277a591 --- /dev/null +++ b/diplomacy/web/src/gui/maps/common/unit.js @@ -0,0 +1,50 @@ +// ============================================================================== +// Copyright (C) 2019 - Philip Paquette, Steven Bocco +// +// This program is free software: you can redistribute it and/or modify it under +// the terms of the GNU Affero General Public License as published by the Free +// Software Foundation, either version 3 of the License, or (at your option) any +// later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +// details. +// +// You should have received a copy of the GNU Affero General Public License along +// with this program. If not, see <https://www.gnu.org/licenses/>. +// ============================================================================== +import React from "react"; +import {ARMY, FLEET} from "./common"; +import PropTypes from "prop-types"; + +export class Unit extends React.Component { + render() { + const Coordinates = this.props.coordinates; + const SymbolSizes = this.props.symbolSizes; + const split_unit = this.props.unit.split(/ +/); + const unit_type = split_unit[0]; + const loc = split_unit[1]; + const dislogged_type = this.props.isDislodged ? 'disl' : 'unit'; + const symbol = unit_type === 'F' ? FLEET : ARMY; + const loc_x = Coordinates[loc][dislogged_type][0]; + const loc_y = Coordinates[loc][dislogged_type][1]; + return ( + <use href={`#${this.props.isDislodged ? 'Dislodged' : ''}${symbol}`} + x={loc_x} + y={loc_y} + id={`${this.props.isDislodged ? 'dislodged_' : ''}unit_${loc}`} + width={SymbolSizes[symbol].width} + height={SymbolSizes[symbol].height} + className={`unit${this.props.powerName.toLowerCase()}`}/> + ); + } +} + +Unit.propTypes = { + unit: PropTypes.string.isRequired, + powerName: PropTypes.string.isRequired, + isDislodged: PropTypes.bool.isRequired, + coordinates: PropTypes.object.isRequired, + symbolSizes: PropTypes.object.isRequired +}; |