diff --git a/src/renderer/ol/style/linestring-placement.js b/src/renderer/ol/style/linestring-placement.js new file mode 100644 index 00000000..c2a8e7a0 --- /dev/null +++ b/src/renderer/ol/style/linestring-placement.js @@ -0,0 +1,49 @@ +import * as R from 'ramda' + +export const placement = ({ TS, geometry }) => { + const segments = TS.segments(geometry) + const line = TS.lengthIndexedLine(geometry) + const endIndex = line.getEndIndex() + const coordAt = (fraction, offset = 0) => line.extractPoint(endIndex * fraction + offset) + const pointAt = (fraction, offset = 0) => TS.point(coordAt(fraction, offset)) + const numPoints = geometry.getNumPoints() + + const segment = fraction => TS.segment([ + coordAt(fraction, -0.05), + coordAt(fraction, +0.05) + ]) + + const angle = anchor => { + if (!anchor) return segment(0.5).angle() + if (isNaN(anchor)) { + if (anchor.includes('center')) return segment(0.5).angle() + else if (anchor.includes('left')) return R.head(segments).angle() + else if (anchor.includes('right')) return R.last(segments).angle() + } else return segment(anchor).angle() + } + + const anchors = anchor => { + if (isNaN(anchor)) { + if (anchor.includes('center')) return pointAt(0.5) + else if (anchor.includes('left')) return geometry.getPointN(0) + else if (anchor.includes('right')) return geometry.getPointN(numPoints - 1) + else return pointAt(0.5) + } else return pointAt(anchor) + } + + const normalize = angle => TS.Angle.normalize(TS.Angle.PI_TIMES_2 - angle) + + return props => { + const rotate = props['text-field'] ? 'text-rotate' : 'icon-rotate' + const anchor = props['text-anchor'] || + props['icon-anchor'] || + props['symbol-anchor'] || + (props['text-field'] ? 'center' : null) + + return { + geometry: anchors(anchor), + ...props, + [rotate]: normalize(angle(anchor)) + } + } +} \ No newline at end of file diff --git a/src/renderer/ol/style/linestring-styles/labels.js b/src/renderer/ol/style/linestring-styles/labels.js new file mode 100644 index 00000000..06cf3826 --- /dev/null +++ b/src/renderer/ol/style/linestring-styles/labels.js @@ -0,0 +1,82 @@ +/** + * Line string position mnemonics: + * + * LEFT | LEFT CENTER RIGHT | RIGHT (ANCHOR) + * END | START CENTER END | START (JUSTFY) + * + * + * WNW | NNW N NNE | ENE (ABOVE) + * W |----------------|----------------| E + * WSW | SSW S SSE | ESE (BELOW) + * + * EW := E + W + * NNEW := NNE + NNW + * SSEW := SSE + SSW + * EWNEW := ENE + WNW + * EWSEW := ESE + WSW + */ + +const ABOVE = -20 +const BELOW = 20 + +const W = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'end', 'text-offset': [-10, 0], 'text-padding': 5 } +const E = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'start', 'text-offset': [10, 0], 'text-padding': 5 } +const NNW = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'start', 'text-padding': 5, 'text-offset': [0, ABOVE] } +const NNE = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'end', 'text-padding': 5, 'text-offset': [0, ABOVE] } +const SSW = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'start', 'text-padding': 5, 'text-offset': [0, BELOW] } +const SSE = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'end', 'text-padding': 5, 'text-offset': [0, BELOW] } +const NNEW = (text, options) => [NNE, NNW].map(props => ({ 'text-field': text, ...props, ...options })) + +const MT = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, ABOVE], 'text-clipping': 'none' }] +const MB = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, BELOW], 'text-clipping': 'none' }] +const MM = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5 }] +const SE = text => [W, E].map(props => ({ 'text-field': text, ...props })) +const CFL_1 = { id: 'style:default-text', 'text-field': '"CFL" + (modifiers.t ? " " + modifiers.t : "")', 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, ABOVE] } +const CFL_2 = { id: 'style:default-text', 'text-field': ['modifiers.w', 'modifiers.w1'], 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, BELOW] } +const CFL = [CFL_1, CFL_2] +const PL_1 = T => [W, E].map(props => ({ 'text-field': `${T} ? "PL " + ${T} : null`, ...props })) +const PL_2 = (T1, T2) => [NNW, NNE].map(props => ({ 'text-field': `(${T1} ? ${T1} : "") + ((${T1} || ${T2}) ? " " : "") + (${T2} ? ${T2} : "")`, ...props })) +const PL_3 = [SSW, SSE].map(props => ({ 'text-field': ['modifiers.w', 'modifiers.w1'], ...props })) +const PL = (T1, T2) => T1 ? [PL_1('modifiers.t1'), PL_2(T1, T2), PL_3] : [PL_1('modifiers.t'), PL_3] +const MFP_1 = { id: 'style:default-text', 'text-field': '"MFP"', 'text-anchor': 'center', 'text-padding': 5 } +const MFP = [MFP_1] +const BND_1 = { id: 'style:default-text', 'text-field': 'modifiers.t', 'text-anchor': 0.5, 'text-clipping': 'none', 'text-offset': [0, ABOVE], 'text-rotation-anchor': 'fix' } +const BND_2 = { id: 'style:default-text', 'text-field': 'modifiers.t1', 'text-anchor': 0.5, 'text-clipping': 'none', 'text-offset': [0, BELOW], 'text-rotation-anchor': 'fix' } +const BND_3 = { id: 'style:default-text', 'text-field': 'echelon', 'text-anchor': 'center', 'text-rotation-anchor': 'fix', 'text-padding': 5 } + +const BND = [BND_1, BND_2, BND_3] + +export const labels = {} +labels['G*T*A-----'] = [{ 'text-field': 'modifiers.t', 'text-anchor': 0.15, 'text-clipping': 'none' }] // FOLLOW AND ASSUME +labels['G*T*AS----'] = [{ 'text-field': 'modifiers.t', 'text-anchor': 0.15, 'text-clipping': 'none' }] // FOLLOW AND SUPPORT +labels['G*G*GLB---'] = BND // BOUNDARIES +labels['G*G*GLP---'] = PL() // PHASE LINE +labels['G*G*GLL---'] = PL('"LL"', 'modifiers.t') // LIGHT LINE +labels['G*G*PF----'] = MT('t') // DIRECTION OF ATTACK FOR FEINT +labels['G*G*DLF---'] = SE('"FEBA"') // FORWARD EDGE OF BATTLE AREA (FEBA) +labels['G*G*OLF---'] = PL('"FCL"', 'modifiers.t') // FINAL COORDINATION LINE +labels['G*G*OLL---'] = PL('"LOA"', 'modifiers.t') // LIMIT OF ADVANCE +labels['G*G*OLT---'] = PL('"LD"', 'modifiers.t') // LINE OF DEPARTURE +labels['G*G*OLC---'] = PL('"LD/LC"', 'modifiers.t') // LINE OF DEPARTURE/LINE OF CONTACT (LD/LC) +labels['G*G*OLP---'] = PL('"PLD"', 'modifiers.t') // PROBABLE LINE OF DEPLOYMENT (PLD) +labels['G*G*SLH---'] = NNEW('"HL"', { 'text-offset': [0, -10] }) // HOLDING LINE +labels['G*G*SLR---'] = PL('"RL"', 'modifiers.t') // RELEASE LINE +labels['G*G*SLB---'] = NNEW('"BL"', { 'text-offset': [0, -10] }) // BRIDGEHEAD +labels['G*F*LT----'] = MT('modifiers.t') // LINEAR TARGET +labels['G*F*LTS---'] = [MT('modifiers.t'), MB('"SMOKE"')] // LINEAR SMOKE TARGET +labels['G*F*LTF---'] = [MT('modifiers.t'), MB('"FPF" + (modifiers.t1 ? "\n" + modifiers.t1 : "")')] // FINAL PROTECTIVE FIRE (FPF) +labels['G*F*LCF---'] = PL('modifiers.t', '"FSCL"') // FIRE SUPPORT COORDINATION LINE (FSCL) +labels['G*F*LCC---'] = CFL // COORDINATED FIRE LINE (CFL) +labels['G*F*LCN---'] = PL("'NFL'", 'modifiers.t') // NO-FIRE LINE (NFL) +labels['G*F*LCR---'] = PL('"RFL"', 'modifiers.t') // RESTRICTIVE FIRE LINE (RFL) +labels['G*F*LCM---'] = MFP // MUNITION FLIGHT PATH (MFP) +labels['G*S*LRM---'] = MT('"MSR" + (modifiers.t ? " " + modifiers.t : "")') // MAIN SUPPLY ROUTE +labels['G*S*LRA---'] = MT('"ASR" + (modifiers.t ? " " + modifiers.t : "")') // ALTERNATE SUPPLY ROUTE +labels['G*S*LRO---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(ONE-WAY)"']) // MSR: ONE-WAY TRAFFIC +labels['G*S*LRT---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(ALTERNATING)"']) // MSR: ALTERNATING TRAFFIC +labels['G*S*LRW---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(TWO-WAY)"']) // MSR: TWO-WAY TRAFFIC +labels['G*O*B-----'] = MM('"B"') // BEARING LINE +labels['G*O*BE----'] = MM('"E"') // BEARING LINE / ELECTRONIC +labels['G*O*BA----'] = MM('"A"') // BEARING LINE / ACOUSTIC +labels['G*O*BT----'] = MM('"T"') // BEARING LINE / TORPEDO +labels['G*O*BO----'] = MM('"O"') // BEARING LINE / ELECTRO-OPTICAL INTERCEPT diff --git a/src/renderer/ol/style/linestring.js b/src/renderer/ol/style/linestring.js index f829d3ae..3597d6bc 100644 --- a/src/renderer/ol/style/linestring.js +++ b/src/renderer/ol/style/linestring.js @@ -1,6 +1,7 @@ -import * as R from 'ramda' import * as shared from './shared' import styles from './linestring-styles' +import { placement } from './linestring-placement' +import { labels } from './linestring-styles/labels' /** * dynamicStyle @@ -37,133 +38,5 @@ export default [ // ==> label specifications and placement -const placement = ({ TS, geometry }) => { - const segments = TS.segments(geometry) - const line = TS.lengthIndexedLine(geometry) - const endIndex = line.getEndIndex() - const coordAt = (fraction, offset = 0) => line.extractPoint(endIndex * fraction + offset) - const pointAt = (fraction, offset = 0) => TS.point(coordAt(fraction, offset)) - const numPoints = geometry.getNumPoints() - const segment = fraction => TS.segment([ - coordAt(fraction, -0.05), - coordAt(fraction, +0.05) - ]) - const angle = anchor => { - if (!anchor) return segment(0.5).angle() - if (isNaN(anchor)) { - if (anchor.includes('center')) return segment(0.5).angle() - else if (anchor.includes('left')) return R.head(segments).angle() - else if (anchor.includes('right')) return R.last(segments).angle() - } else return segment(anchor).angle() - } - - const anchors = anchor => { - if (isNaN(anchor)) { - if (anchor.includes('center')) return pointAt(0.5) - else if (anchor.includes('left')) return geometry.getPointN(0) - else if (anchor.includes('right')) return geometry.getPointN(numPoints - 1) - else return pointAt(0.5) - } else return pointAt(anchor) - } - - const normalize = angle => TS.Angle.normalize(TS.Angle.PI_TIMES_2 - angle) - - return props => { - const rotate = props['text-field'] ? 'text-rotate' : 'icon-rotate' - const anchor = props['text-anchor'] || - props['icon-anchor'] || - props['symbol-anchor'] || - (props['text-field'] ? 'center' : null) - - return { - geometry: anchors(anchor), - ...props, - [rotate]: normalize(angle(anchor)) - } - } -} - -/** - * Line string position mnemonics: - * - * LEFT | LEFT CENTER RIGHT | RIGHT (ANCHOR) - * END | START CENTER END | START (JUSTFY) - * - * - * WNW | NNW N NNE | ENE (ABOVE) - * W |----------------|----------------| E - * WSW | SSW S SSE | ESE (BELOW) - * - * EW := E + W - * NNEW := NNE + NNW - * SSEW := SSE + SSW - * EWNEW := ENE + WNW - * EWSEW := ESE + WSW - */ - -const ABOVE = -20 -const BELOW = 20 - -const W = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'end', 'text-offset': [-10, 0], 'text-padding': 5 } -const E = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'start', 'text-offset': [10, 0], 'text-padding': 5 } -const NNW = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'start', 'text-padding': 5, 'text-offset': [0, ABOVE] } -const NNE = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'end', 'text-padding': 5, 'text-offset': [0, ABOVE] } -const SSW = { id: 'style:default-text', 'text-anchor': 'left', 'text-justify': 'start', 'text-padding': 5, 'text-offset': [0, BELOW] } -const SSE = { id: 'style:default-text', 'text-anchor': 'right', 'text-justify': 'end', 'text-padding': 5, 'text-offset': [0, BELOW] } -const NNEW = (text, options) => [NNE, NNW].map(props => ({ 'text-field': text, ...props, ...options })) - -const MT = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, ABOVE], 'text-clipping': 'none' }] -const MB = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, BELOW], 'text-clipping': 'none' }] -const MM = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-padding': 5 }] -const SE = text => [W, E].map(props => ({ 'text-field': text, ...props })) -const CFL_1 = { id: 'style:default-text', 'text-field': '"CFL" + (modifiers.t ? " " + modifiers.t : "")', 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, ABOVE] } -const CFL_2 = { id: 'style:default-text', 'text-field': ['modifiers.w', 'modifiers.w1'], 'text-anchor': 'center', 'text-padding': 5, 'text-offset': [0, BELOW] } -const CFL = [CFL_1, CFL_2] -const PL_1 = T => [W, E].map(props => ({ 'text-field': `${T} ? "PL " + ${T} : null`, ...props })) -const PL_2 = (T1, T2) => [NNW, NNE].map(props => ({ 'text-field': `(${T1} ? ${T1} : "") + ((${T1} || ${T2}) ? " " : "") + (${T2} ? ${T2} : "")`, ...props })) -const PL_3 = [SSW, SSE].map(props => ({ 'text-field': ['modifiers.w', 'modifiers.w1'], ...props })) -const PL = (T1, T2) => T1 ? [PL_1('modifiers.t1'), PL_2(T1, T2), PL_3] : [PL_1('modifiers.t'), PL_3] -const MFP_1 = { id: 'style:default-text', 'text-field': '"MFP"', 'text-anchor': 'center', 'text-padding': 5 } -const MFP = [MFP_1] -const BND_1 = { id: 'style:default-text', 'text-field': 'modifiers.t', 'text-anchor': 0.5, 'text-clipping': 'none', 'text-offset': [0, ABOVE], 'text-rotation-anchor': 'fix' } -const BND_2 = { id: 'style:default-text', 'text-field': 'modifiers.t1', 'text-anchor': 0.5, 'text-clipping': 'none', 'text-offset': [0, BELOW], 'text-rotation-anchor': 'fix' } -const BND_3 = { id: 'style:default-text', 'text-field': 'echelon', 'text-anchor': 'center', 'text-rotation-anchor': 'fix', 'text-padding': 5 } - -const BND = [BND_1, BND_2, BND_3] - -const labels = {} -labels['G*T*A-----'] = [{ 'text-field': 'modifiers.t', 'text-anchor': 0.15, 'text-clipping': 'none' }] // FOLLOW AND ASSUME -labels['G*T*AS----'] = [{ 'text-field': 'modifiers.t', 'text-anchor': 0.15, 'text-clipping': 'none' }] // FOLLOW AND SUPPORT -labels['G*G*GLB---'] = BND // BOUNDARIES -labels['G*G*GLP---'] = PL() // PHASE LINE -labels['G*G*GLL---'] = PL('"LL"', 'modifiers.t') // LIGHT LINE -labels['G*G*PF----'] = MT('t') // DIRECTION OF ATTACK FOR FEINT -labels['G*G*DLF---'] = SE('"FEBA"') // FORWARD EDGE OF BATTLE AREA (FEBA) -labels['G*G*OLF---'] = PL('"FCL"', 'modifiers.t') // FINAL COORDINATION LINE -labels['G*G*OLL---'] = PL('"LOA"', 'modifiers.t') // LIMIT OF ADVANCE -labels['G*G*OLT---'] = PL('"LD"', 'modifiers.t') // LINE OF DEPARTURE -labels['G*G*OLC---'] = PL('"LD/LC"', 'modifiers.t') // LINE OF DEPARTURE/LINE OF CONTACT (LD/LC) -labels['G*G*OLP---'] = PL('"PLD"', 'modifiers.t') // PROBABLE LINE OF DEPLOYMENT (PLD) -labels['G*G*SLH---'] = NNEW('"HL"', { 'text-offset': [0, -10] }) // HOLDING LINE -labels['G*G*SLR---'] = PL('"RL"', 'modifiers.t') // RELEASE LINE -labels['G*G*SLB---'] = NNEW('"BL"', { 'text-offset': [0, -10] }) // BRIDGEHEAD -labels['G*F*LT----'] = MT('modifiers.t') // LINEAR TARGET -labels['G*F*LTS---'] = [MT('modifiers.t'), MB('"SMOKE"')] // LINEAR SMOKE TARGET -labels['G*F*LTF---'] = [MT('modifiers.t'), MB('"FPF" + (modifiers.t1 ? "\n" + modifiers.t1 : "")')] // FINAL PROTECTIVE FIRE (FPF) -labels['G*F*LCF---'] = PL('modifiers.t', '"FSCL"') // FIRE SUPPORT COORDINATION LINE (FSCL) -labels['G*F*LCC---'] = CFL // COORDINATED FIRE LINE (CFL) -labels['G*F*LCN---'] = PL("'NFL'", 'modifiers.t') // NO-FIRE LINE (NFL) -labels['G*F*LCR---'] = PL('"RFL"', 'modifiers.t') // RESTRICTIVE FIRE LINE (RFL) -labels['G*F*LCM---'] = MFP // MUNITION FLIGHT PATH (MFP) -labels['G*S*LRM---'] = MT('"MSR" + (modifiers.t ? " " + modifiers.t : "")') // MAIN SUPPLY ROUTE -labels['G*S*LRA---'] = MT('"ASR" + (modifiers.t ? " " + modifiers.t : "")') // ALTERNATE SUPPLY ROUTE -labels['G*S*LRO---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(ONE-WAY)"']) // MSR: ONE-WAY TRAFFIC -labels['G*S*LRT---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(ALTERNATING)"']) // MSR: ALTERNATING TRAFFIC -labels['G*S*LRW---'] = MT(['"MSR" + (modifiers.t ? " " + modifiers.t : "")', '"(TWO-WAY)"']) // MSR: TWO-WAY TRAFFIC -labels['G*O*B-----'] = MM('"B"') // BEARING LINE -labels['G*O*BE----'] = MM('"E"') // BEARING LINE / ELECTRONIC -labels['G*O*BA----'] = MM('"A"') // BEARING LINE / ACOUSTIC -labels['G*O*BT----'] = MM('"T"') // BEARING LINE / TORPEDO -labels['G*O*BO----'] = MM('"O"') // BEARING LINE / ELECTRO-OPTICAL INTERCEPT diff --git a/src/renderer/ol/style/multipoint-styles/labels.js b/src/renderer/ol/style/multipoint-styles/labels.js new file mode 100644 index 00000000..a3668fc9 --- /dev/null +++ b/src/renderer/ol/style/multipoint-styles/labels.js @@ -0,0 +1,25 @@ +const HALO = { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 } +const C = (text, options) => [{ id: 'style:default-text', 'text-field': text, 'text-clipping': 'none', ...options }] +const B = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-padding': 5, 'text-clipping': 'line' }] +const DTG_LINE = '(modifiers.w || modifiers.w1) ? (modifiers.w ? modifiers.w : "") + "—" + (modifiers.w1 ? modifiers.w1 : "") : null' +const ALT_LINE = '(modifiers.x || modifiers.x1) ? (modifiers.x ? modifiers.x : "") + "—" + (modifiers.x1 ? modifiers.x1 : "") : null' +const ALL_LINES = title => title + ? [`"${title}"`, 'modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] + : ['modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] + +export const labels = { + 'G*F*ATC---': C(ALL_LINES()), // CIRCULAR TARGET + 'G*F*ACSC--': C(ALL_LINES('FSA')), // FIRE SUPPORT AREA (FSA) CIRCULAR + 'G*F*ACAC--': C(ALL_LINES('ACA')), // AIRSPACE COORDINATION AREA (ACA) CIRCULAR + 'G*F*ACFC--': C(ALL_LINES('FFA')), // FREE FIRE AREA (FFA) CIRCULAR + 'G*F*ACNC--': C(ALL_LINES('NFA'), HALO), // NO-FIRE AREA (NFA) CIRCULAR + 'G*F*ACRC--': C(ALL_LINES('RFA')), // RESTRICTIVE FIRE AREA (RFA) CIRCULAR + 'G*F*ACPC--': B('"PAA"'), // POSITION AREA FOR ARTILLERY (PAA) CIRCULAR + 'G*F*ACEC--': C(ALL_LINES('SENSOR ZONE')), // SENSOR ZONE CIRCULAR + 'G*F*ACDC--': C(ALL_LINES('DA')), // DEAD SPACE AREA (DA) CIRCULAR + 'G*F*ACZC--': C(ALL_LINES('ZOR')), // ZONE OF RESPONSIBILITY (ZOR) CIRCULAR + 'G*F*ACBC--': C(ALL_LINES('TBA')), // TARGET BUILD-UP AREA (TBA) CIRCULAR + 'G*F*ACVC--': C(ALL_LINES('TVAR')), // TARGET VALUE AREA (TVAR) CIRCULAR + 'G*F*AKBC--': C(ALL_LINES('BKB'), HALO), // KILL BOX BLUE CIRCULAR + 'G*F*AKPC--': C(ALL_LINES('PKB'), HALO) // KILL BOX PURPLE CIRCULAR +} diff --git a/src/renderer/ol/style/multipoint.js b/src/renderer/ol/style/multipoint.js index 1a9bfaeb..05de8182 100644 --- a/src/renderer/ol/style/multipoint.js +++ b/src/renderer/ol/style/multipoint.js @@ -4,7 +4,8 @@ import * as shared from './shared' import styles from './multipoint-styles' import { transform } from '../../model/geometry' -import { placement } from './polygon' +import { placement } from './polygon-placement' +import { labels } from './multipoint-styles/labels' /** * dynamicStyle @@ -64,33 +65,3 @@ export default [ shared.styles, shared.style ] - - - -// => label specifications for circular features with polygon placement - -const HALO = { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 } -const C = (text, options) => [{ id: 'style:default-text', 'text-field': text, 'text-clipping': 'none', ...options }] -const B = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-padding': 5, 'text-clipping': 'line' }] -const DTG_LINE = '(modifiers.w || modifiers.w1) ? (modifiers.w ? modifiers.w : "") + "—" + (modifiers.w1 ? modifiers.w1 : "") : null' -const ALT_LINE = '(modifiers.x || modifiers.x1) ? (modifiers.x ? modifiers.x : "") + "—" + (modifiers.x1 ? modifiers.x1 : "") : null' -const ALL_LINES = title => title - ? [`"${title}"`, 'modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] - : ['modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] - -const labels = { - 'G*F*ATC---': C(ALL_LINES()), // CIRCULAR TARGET - 'G*F*ACSC--': C(ALL_LINES('FSA')), // FIRE SUPPORT AREA (FSA) CIRCULAR - 'G*F*ACAC--': C(ALL_LINES('ACA')), // AIRSPACE COORDINATION AREA (ACA) CIRCULAR - 'G*F*ACFC--': C(ALL_LINES('FFA')), // FREE FIRE AREA (FFA) CIRCULAR - 'G*F*ACNC--': C(ALL_LINES('NFA'), HALO), // NO-FIRE AREA (NFA) CIRCULAR - 'G*F*ACRC--': C(ALL_LINES('RFA')), // RESTRICTIVE FIRE AREA (RFA) CIRCULAR - 'G*F*ACPC--': B('"PAA"'), // POSITION AREA FOR ARTILLERY (PAA) CIRCULAR - 'G*F*ACEC--': C(ALL_LINES('SENSOR ZONE')), // SENSOR ZONE CIRCULAR - 'G*F*ACDC--': C(ALL_LINES('DA')), // DEAD SPACE AREA (DA) CIRCULAR - 'G*F*ACZC--': C(ALL_LINES('ZOR')), // ZONE OF RESPONSIBILITY (ZOR) CIRCULAR - 'G*F*ACBC--': C(ALL_LINES('TBA')), // TARGET BUILD-UP AREA (TBA) CIRCULAR - 'G*F*ACVC--': C(ALL_LINES('TVAR')), // TARGET VALUE AREA (TVAR) CIRCULAR - 'G*F*AKBC--': C(ALL_LINES('BKB'), HALO), // KILL BOX BLUE CIRCULAR - 'G*F*AKPC--': C(ALL_LINES('PKB'), HALO) // KILL BOX PURPLE CIRCULAR -} diff --git a/src/renderer/ol/style/polygon-placement.js b/src/renderer/ol/style/polygon-placement.js new file mode 100644 index 00000000..f8b5a449 --- /dev/null +++ b/src/renderer/ol/style/polygon-placement.js @@ -0,0 +1,56 @@ + +const lazy = function (fn) { + let evaluated = false + let value + + return function () { + if (evaluated) return value + value = fn.apply(this, arguments) + evaluated = true + return value + } +} + +export const placement = ({ TS, geometry }) => { + const ring = geometry.getExteriorRing() + const envelope = ring.getEnvelopeInternal() + const centroid = TS.centroid(ring) + const [minX, maxX] = [envelope.getMinX(), envelope.getMaxX()] + const [minY, maxY] = [envelope.getMinY(), envelope.getMaxY()] + + const xIntersection = lazy(() => { + const coord = x => TS.coordinate(x, centroid.y) + const axis = TS.lineString([minX, maxX].map(coord)) + return TS.intersection([geometry, axis]).getCoordinates() + }) + + const yIntersection = lazy(() => { + const coord = y => TS.coordinate(centroid.x, y) + const axis = TS.lineString([minY, maxY].map(coord)) + return TS.intersection([geometry, axis]).getCoordinates() + }) + + const fraction = factor => { + const lengthIndexedLine = TS.lengthIndexedLine(ring) + const length = lengthIndexedLine.getEndIndex() + const coord = lengthIndexedLine.extractPoint(factor * length) + return TS.point(coord) + } + + const anchors = { + center: lazy(() => TS.point(centroid)), + bottom: lazy(() => TS.point(yIntersection()[0])), + top: lazy(() => TS.point(yIntersection()[1])), + left: lazy(() => TS.point(xIntersection()[0])), + right: lazy(() => TS.point(xIntersection()[1])) + } + + return props => { + const anchor = props['text-anchor'] + const geometry = Number.isFinite(anchor) + ? fraction(anchor) + : anchors[anchor || 'center']() + + return { geometry, ...props } + } +} diff --git a/src/renderer/ol/style/polygon-styles/labels.js b/src/renderer/ol/style/polygon-styles/labels.js new file mode 100644 index 00000000..b397b544 --- /dev/null +++ b/src/renderer/ol/style/polygon-styles/labels.js @@ -0,0 +1,111 @@ +import G_G_GAZ from '../resources/G_G_GAZ.png' + +const HALO = { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 } +const C = (text, options) => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-clipping': 'none', ...options }] +const T = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'top', 'text-padding': 5, 'text-clipping': 'line' }] +const B = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-padding': 5, 'text-clipping': 'line' }] +const F = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-offset': [0, 20] }] +const LR = text => ['left', 'right'].map(anchor => ({ id: 'style:default-text', 'text-field': text, 'text-anchor': anchor, 'text-padding': 5, 'text-clipping': 'line' })) +const TLBR = text => ['top', 'left', 'bottom', 'right'].map(anchor => ({ id: 'style:default-text', 'text-field': text, 'text-anchor': anchor, 'text-padding': 5, 'text-clipping': 'line' })) +const DTG_LINE = '(modifiers.w || modifiers.w1) ? (modifiers.w ? modifiers.w : "") + "—" + (modifiers.w1 ? modifiers.w1 : "") : null' +const ALT_LINE = '(modifiers.x || modifiers.x1) ? (modifiers.x ? modifiers.x : "") + "—" + (modifiers.x1 ? modifiers.x1 : "") : null' +const ALL_LINES = title => title + ? [`"${title}"`, 'modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] + : ['modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] + +const G_G_PM = [ + ...TLBR('"M"'), + { 'symbol-code': 'GFGPPD----', 'symbol-anchor': 'center', 'symbol-size': 100 } +] + +export const labels = {} +labels['G*G*GAG---'] = C(ALL_LINES()) // GENERAL AREA +labels['G*G*GAA---'] = C(ALL_LINES('AA')) // ASSEMBLY AREA +labels['G*G*GAE---'] = C(ALL_LINES('EA')) // ENGAGEMENT AREA +labels['G*G*GAF---'] = C(ALL_LINES('')) // FORTIFIED AREA +labels['G*G*GAD---'] = C(ALL_LINES('DZ')) // DROP ZONE +labels['G*G*GAX---'] = C(ALL_LINES('EZ')) // EXTRACTION ZONE (EZ) +labels['G*G*GAL---'] = C(ALL_LINES('LZ')) // LANDING ZONE (LZ) +labels['G*G*GAP---'] = C(ALL_LINES('PZ')) // PICKUP ZONE (PZ) +labels['G*G*GAY---'] = C('h', { 'text-halo-color': 'white', 'text-halo-width': 5 }) // LIMITED ACCESS AREA +labels['G*G*GAZ---'] = [{ 'icon-url': G_G_GAZ, 'icon-anchor': 'center', 'icon-scale': 0.8 }] // AIRFIELD ZONE +labels['G*G*AAR---'] = C(ALL_LINES('ROZ')) // RESTRICTED OPERATIONS ZONE (ROZ) +labels['G*G*AAF---'] = C(ALL_LINES('SHORADEZ')) // SHORT-RANGE AIR DEFENSE ENGAGEMENT ZONE (SHORADEZ) +labels['G*G*AAH---'] = C(ALL_LINES('HIDACZ')) // HIGH DENSITY AIRSPACE CONTROL ZONE (HIDACZ) +labels['G*G*AAM---'] = C(ALL_LINES('MEZ')) // MISSILE ENGAGEMENT ZONE (MEZ) +labels['G*G*AAML--'] = C(ALL_LINES('LOMEZ')) // LOW ALTITUDE MEZ +labels['G*G*AAMH--'] = C(ALL_LINES('HIMEZ')) // HIGH ALTITUDE MEZ +labels['G*G*AAW---'] = C(ALL_LINES('WFZ'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // WEAPONS FREE ZONE +labels['G*G*PM----'] = G_G_PM // DECOY MINED AREA +labels['G*G*PY----'] = G_G_PM // DECOY MINED AREA, FENCED +// G*G*PC---- : DUMMY MINEFIELD (DYNAMIC) +labels['G*G*DAB---'] = C(ALL_LINES()) // BATTLE POSITION +labels['G*G*DABP--'] = C('modifiers.t ? "(P) " + modifiers.t : (P)') // BATTLE POSITION / PREPARED BUT NOT OCCUPIED +labels['G*G*DAE---'] = C(ALL_LINES('EA')) // ENGAGEMENT AREA (DEFENSE) +labels['G*G*OAA---'] = C(ALL_LINES('ASLT\nPSN')) // ASSAULT POSITION +labels['G*G*OAK---'] = C(ALL_LINES('ATK')) // ATTACK POSITION +labels['G*G*OAO---'] = C(ALL_LINES('OBJ')) // OBJECTIVE (OFFENSE) +labels['G*G*OAP---'] = [] // PENETRATION BOX +labels['G*G*SAO---'] = C(ALL_LINES('AO')) // AREA OF OPERATIONS (AO) +labels['G*G*SAA---'] = F(['"AIRHEAD LINE"', 'modifiers.t ? "(PL " + modifiers.t + ")" : null']) // AIRHEAD +labels['G*G*SAE---'] = C(ALL_LINES()) // ENCIRCLEMENT +labels['G*G*SAN---'] = C(ALL_LINES('NAI')) // NAMED AREA OF INTEREST (NAI) +labels['G*G*SAT---'] = C(ALL_LINES('TAI')) // TARGETED AREA OF INTEREST (TAI) +labels['G*M*OGB---'] = C(['t', 't1']) // BELT (OBSTACLES) +labels['G*M*OGZ---'] = C(ALL_LINES()) // GENERAL ZONE (OBSTACLES) +labels['G*M*OGF---'] = C(ALL_LINES('FREE')) // OBSTACLE FREE AREA +labels['G*M*OGR---'] = C(ALL_LINES(), { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 }) // OBSTACLE RESTRICTED AREA +// G*M*OFD--- : MINEFIELDS / DYNAMIC DEPICTION +labels['G*M*OFA---'] = TLBR('"M"') // MINED AREA +labels['G*M*OU----'] = LR('"UXO"') // UNEXPLODED ORDNANCE AREA (UXO) +labels['G*M*SP----'] = C('t') // STRONG POINT +labels['G*M*NL----'] = T('t') // DOSE RATE CONTOUR LINES +labels['G*F*ACSR--'] = C(ALL_LINES('FSA')) // FIRE SUPPORT AREA (FSA) +labels['G*F*ACAR--'] = C(ALL_LINES('ACA')) // AIRSPACE COORDINATION AREA (ACA) +labels['G*F*ACFR--'] = C(ALL_LINES('FFA')) // FREE FIRE AREA (FFA) +labels['G*F*ACNR--'] = C(ALL_LINES('NFA'), HALO) // NO-FIRE AREA (NFA) +labels['G*F*ACRR--'] = C(ALL_LINES('RFA')) // RESTRICTIVE FIRE AREA (RFA) +labels['G*F*ACPR--'] = B('"PAA"') // POSITION AREA FOR ARTILLERY (PAA) +labels['G*F*ACER--'] = C(ALL_LINES('SENSOR ZONE')) // SENSOR ZONE +labels['G*F*ACDR--'] = C(ALL_LINES('DA')) // DEAD SPACE AREA (DA) +labels['G*F*ACZR--'] = C(ALL_LINES('ZOR')) // ZONE OF RESPONSIBILITY (ZOR) +labels['G*F*ACBR--'] = C(ALL_LINES('TBA')) // TARGET BUILD-UP AREA (TBA) +labels['G*F*ACVR--'] = C(ALL_LINES('TVAR')) // TARGET VALUE AREA (TVAR) +labels['G*F*AT----'] = C(ALL_LINES()) // AREA TARGET +labels['G*F*ATG---'] = T('t') // SERIES OR GROUP OF TARGETS +labels['G*F*ATR---'] = C(ALL_LINES()) // RECTANGULAR TARGET +labels['G*F*ATS---'] = C(ALL_LINES('SMOKE')) // AREA TARGET / SMOKE +labels['G*F*ATB---'] = C(ALL_LINES('BOMB')) // BOMB AREA +labels['G*F*ACSI--'] = C(ALL_LINES('FSA')) // FIRE SUPPORT AREA (FSA) +labels['G*F*ACAI--'] = C(ALL_LINES('ACA')) // AIRSPACE COORDINATION AREA (ACA) +labels['G*F*ACFI--'] = C(ALL_LINES('FFA')) // FREE FIRE AREA (FFA) +labels['G*F*ACNI--'] = C(ALL_LINES('NFA'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // NO-FIRE AREA (NFA) +labels['G*F*ACRI--'] = C(ALL_LINES('RFA')) // RESTRICTIVE FIRE AREA (RFA) +labels['G*F*ACEI--'] = C(ALL_LINES('SENSOR ZONE')) // SENSOR ZONE +labels['G*F*ACDI--'] = C(ALL_LINES('DA')) // DEAD SPACE AREA (DA) +labels['G*F*ACZI--'] = C(ALL_LINES('ZOR')) // ZONE OF RESPONSIBILITY (ZOR) +labels['G*F*ACBI--'] = C(ALL_LINES('TBA')) // TARGET BUILD-UP AREA (TBA) +labels['G*F*ACVI--'] = C(ALL_LINES('TVAR')) // TARGET VALUE AREA (TVAR) +labels['G*F*ACT---'] = C(ALL_LINES('TGMF')) // TERMINALLY GUIDED MUNITION FOOTPRINT (TGMF) +labels['G*F*AKBR--'] = C(ALL_LINES('BKB'), HALO) // KILL BOX/BLUE +labels['G*F*AKPR--'] = C(ALL_LINES('PKB'), HALO) // KILL BOX/PURPLE +labels['G*F*AZII--'] = C(ALL_LINES('ATI ZONE')) // ARTILLERY TARGET INTELLIGENCE (ATI) ZONE +labels['G*F*AZIR--'] = C(ALL_LINES('ATI ZONE')) // ARTILLERY TARGET INTELLIGENCE (ATI) ZONE +labels['G*F*AZXI--'] = C(ALL_LINES('CFF ZONE')) // CALL FOR FIRE ZONE (CFFZ) +labels['G*F*AZXR--'] = C(ALL_LINES('CFF ZONE')) // CALL FOR FIRE ZONE (CFFZ) +labels['G*F*AZCI--'] = C(ALL_LINES('CENSOR ZONE')) // CENSOR ZONE +labels['G*F*AZCR--'] = C(ALL_LINES('CENSOR ZONE')) // CENSOR ZONE +labels['G*F*AZFI--'] = C(ALL_LINES('CF ZONE')) // CRITICAL FRIENDLY ZONE (CFZ) +labels['G*F*AZFR--'] = C(ALL_LINES('CF ZONE')) // CRITICAL FRIENDLY ZONE (CFZ) +labels['G*F*AKBI--'] = C(ALL_LINES('BKB'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // KILL BOX / BLUE +labels['G*F*AKPI--'] = C(ALL_LINES('PKB'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // KILL BOX / PURPLE +labels['G*S*AD----'] = C(ALL_LINES('DETAINEE\nHOLDING\nAREA')) // DETAINEE HOLDING AREA +labels['G*S*AE----'] = C(ALL_LINES('EPW\nHOLDING\nAREA')) // ENEMY PRISONER OF WAR (EPW) HOLDING AREA +labels['G*S*AR----'] = C(ALL_LINES('FARP')) // FORWARD ARMING AND REFUELING AREA (FARP) +labels['G*S*AH----'] = C(ALL_LINES('REFUGEE\nHOLDING\nAREA')) // REFUGEE HOLDING AREA +labels['G*S*ASB---'] = C(ALL_LINES('BSA')) // SUPPORT AREAS / BRIGADE (BSA) +labels['G*S*ASD---'] = C(ALL_LINES('DSA')) // SUPPORT AREAS / DIVISON (DSA) +labels['G*S*ASR---'] = C(ALL_LINES('RSA')) // SUPPORT AREAS / REGIMENTAL (DSA) +labels['G*M*NR----'] = [{ 'symbol-code': 'GFMPNZ----', 'symbol-anchor': 'center' }] // RADIOACTIVE AREA +labels['G*M*NB----'] = [{ 'symbol-code': 'GFMPNEB---', 'symbol-anchor': 'center' }] // BIOLOGICALLY CONTAMINATED AREA +labels['G*M*NC----'] = [{ 'symbol-code': 'GFMPNEC---', 'symbol-anchor': 'center' }] // CHEMICALLY CONTAMINATED AREA diff --git a/src/renderer/ol/style/polygon.js b/src/renderer/ol/style/polygon.js index f04430f8..632ca65d 100644 --- a/src/renderer/ol/style/polygon.js +++ b/src/renderer/ol/style/polygon.js @@ -1,8 +1,8 @@ /* eslint-disable camelcase */ import * as shared from './shared' import styles from './polygon-styles' -import G_G_GAZ from './resources/G_G_GAZ.png' - +import { placement } from './polygon-placement' +import { labels } from './polygon-styles/labels' /** * dynamicStyle @@ -43,173 +43,3 @@ export default [ error, shared.style ] - - -// ==> label specifications and placement - -const lazy = function (fn) { - let evaluated = false - let value - - return function () { - if (evaluated) return value - value = fn.apply(this, arguments) - evaluated = true - return value - } -} - -export const placement = ({ TS, geometry }) => { - const ring = geometry.getExteriorRing() - const envelope = ring.getEnvelopeInternal() - const centroid = TS.centroid(ring) - const [minX, maxX] = [envelope.getMinX(), envelope.getMaxX()] - const [minY, maxY] = [envelope.getMinY(), envelope.getMaxY()] - - const xIntersection = lazy(() => { - const coord = x => TS.coordinate(x, centroid.y) - const axis = TS.lineString([minX, maxX].map(coord)) - return TS.intersection([geometry, axis]).getCoordinates() - }) - - const yIntersection = lazy(() => { - const coord = y => TS.coordinate(centroid.x, y) - const axis = TS.lineString([minY, maxY].map(coord)) - return TS.intersection([geometry, axis]).getCoordinates() - }) - - const fraction = factor => { - const lengthIndexedLine = TS.lengthIndexedLine(ring) - const length = lengthIndexedLine.getEndIndex() - const coord = lengthIndexedLine.extractPoint(factor * length) - return TS.point(coord) - } - - const anchors = { - center: lazy(() => TS.point(centroid)), - bottom: lazy(() => TS.point(yIntersection()[0])), - top: lazy(() => TS.point(yIntersection()[1])), - left: lazy(() => TS.point(xIntersection()[0])), - right: lazy(() => TS.point(xIntersection()[1])) - } - - return props => { - const anchor = props['text-anchor'] - const geometry = Number.isFinite(anchor) - ? fraction(anchor) - : anchors[anchor || 'center']() - - return { geometry, ...props } - } -} - - -const HALO = { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 } -const C = (text, options) => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'center', 'text-clipping': 'none', ...options }] -const T = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'top', 'text-padding': 5, 'text-clipping': 'line' }] -const B = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-padding': 5, 'text-clipping': 'line' }] -const F = text => [{ id: 'style:default-text', 'text-field': text, 'text-anchor': 'bottom', 'text-offset': [0, 20] }] -const LR = text => ['left', 'right'].map(anchor => ({ id: 'style:default-text', 'text-field': text, 'text-anchor': anchor, 'text-padding': 5, 'text-clipping': 'line' })) -const TLBR = text => ['top', 'left', 'bottom', 'right'].map(anchor => ({ id: 'style:default-text', 'text-field': text, 'text-anchor': anchor, 'text-padding': 5, 'text-clipping': 'line' })) -const DTG_LINE = '(modifiers.w || modifiers.w1) ? (modifiers.w ? modifiers.w : "") + "—" + (modifiers.w1 ? modifiers.w1 : "") : null' -const ALT_LINE = '(modifiers.x || modifiers.x1) ? (modifiers.x ? modifiers.x : "") + "—" + (modifiers.x1 ? modifiers.x1 : "") : null' -const ALL_LINES = title => title - ? [`"${title}"`, 'modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] - : ['modifiers.t', 'modifiers.h', ALT_LINE, DTG_LINE] - -const G_G_PM = [ - ...TLBR('"M"'), - { 'symbol-code': 'GFGPPD----', 'symbol-anchor': 'center', 'symbol-size': 100 } -] - -const labels = {} -labels['G*G*GAG---'] = C(ALL_LINES()) // GENERAL AREA -labels['G*G*GAA---'] = C(ALL_LINES('AA')) // ASSEMBLY AREA -labels['G*G*GAE---'] = C(ALL_LINES('EA')) // ENGAGEMENT AREA -labels['G*G*GAF---'] = C(ALL_LINES('')) // FORTIFIED AREA -labels['G*G*GAD---'] = C(ALL_LINES('DZ')) // DROP ZONE -labels['G*G*GAX---'] = C(ALL_LINES('EZ')) // EXTRACTION ZONE (EZ) -labels['G*G*GAL---'] = C(ALL_LINES('LZ')) // LANDING ZONE (LZ) -labels['G*G*GAP---'] = C(ALL_LINES('PZ')) // PICKUP ZONE (PZ) -labels['G*G*GAY---'] = C('h', { 'text-halo-color': 'white', 'text-halo-width': 5 }) // LIMITED ACCESS AREA -labels['G*G*GAZ---'] = [{ 'icon-url': G_G_GAZ, 'icon-anchor': 'center', 'icon-scale': 0.8 }] // AIRFIELD ZONE -labels['G*G*AAR---'] = C(ALL_LINES('ROZ')) // RESTRICTED OPERATIONS ZONE (ROZ) -labels['G*G*AAF---'] = C(ALL_LINES('SHORADEZ')) // SHORT-RANGE AIR DEFENSE ENGAGEMENT ZONE (SHORADEZ) -labels['G*G*AAH---'] = C(ALL_LINES('HIDACZ')) // HIGH DENSITY AIRSPACE CONTROL ZONE (HIDACZ) -labels['G*G*AAM---'] = C(ALL_LINES('MEZ')) // MISSILE ENGAGEMENT ZONE (MEZ) -labels['G*G*AAML--'] = C(ALL_LINES('LOMEZ')) // LOW ALTITUDE MEZ -labels['G*G*AAMH--'] = C(ALL_LINES('HIMEZ')) // HIGH ALTITUDE MEZ -labels['G*G*AAW---'] = C(ALL_LINES('WFZ'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // WEAPONS FREE ZONE -labels['G*G*PM----'] = G_G_PM // DECOY MINED AREA -labels['G*G*PY----'] = G_G_PM // DECOY MINED AREA, FENCED -// G*G*PC---- : DUMMY MINEFIELD (DYNAMIC) -labels['G*G*DAB---'] = C(ALL_LINES()) // BATTLE POSITION -labels['G*G*DABP--'] = C('modifiers.t ? "(P) " + modifiers.t : (P)') // BATTLE POSITION / PREPARED BUT NOT OCCUPIED -labels['G*G*DAE---'] = C(ALL_LINES('EA')) // ENGAGEMENT AREA (DEFENSE) -labels['G*G*OAA---'] = C(ALL_LINES('ASLT\nPSN')) // ASSAULT POSITION -labels['G*G*OAK---'] = C(ALL_LINES('ATK')) // ATTACK POSITION -labels['G*G*OAO---'] = C(ALL_LINES('OBJ')) // OBJECTIVE (OFFENSE) -labels['G*G*OAP---'] = [] // PENETRATION BOX -labels['G*G*SAO---'] = C(ALL_LINES('AO')) // AREA OF OPERATIONS (AO) -labels['G*G*SAA---'] = F(['"AIRHEAD LINE"', 'modifiers.t ? "(PL " + modifiers.t + ")" : null']) // AIRHEAD -labels['G*G*SAE---'] = C(ALL_LINES()) // ENCIRCLEMENT -labels['G*G*SAN---'] = C(ALL_LINES('NAI')) // NAMED AREA OF INTEREST (NAI) -labels['G*G*SAT---'] = C(ALL_LINES('TAI')) // TARGETED AREA OF INTEREST (TAI) -labels['G*M*OGB---'] = C(['t', 't1']) // BELT (OBSTACLES) -labels['G*M*OGZ---'] = C(ALL_LINES()) // GENERAL ZONE (OBSTACLES) -labels['G*M*OGF---'] = C(ALL_LINES('FREE')) // OBSTACLE FREE AREA -labels['G*M*OGR---'] = C(ALL_LINES(), { 'text-clipping': 'none', 'text-halo-color': 'white', 'text-halo-width': 5 }) // OBSTACLE RESTRICTED AREA -// G*M*OFD--- : MINEFIELDS / DYNAMIC DEPICTION -labels['G*M*OFA---'] = TLBR('"M"') // MINED AREA -labels['G*M*OU----'] = LR('"UXO"') // UNEXPLODED ORDNANCE AREA (UXO) -labels['G*M*SP----'] = C('t') // STRONG POINT -labels['G*M*NL----'] = T('t') // DOSE RATE CONTOUR LINES -labels['G*F*ACSR--'] = C(ALL_LINES('FSA')) // FIRE SUPPORT AREA (FSA) -labels['G*F*ACAR--'] = C(ALL_LINES('ACA')) // AIRSPACE COORDINATION AREA (ACA) -labels['G*F*ACFR--'] = C(ALL_LINES('FFA')) // FREE FIRE AREA (FFA) -labels['G*F*ACNR--'] = C(ALL_LINES('NFA'), HALO) // NO-FIRE AREA (NFA) -labels['G*F*ACRR--'] = C(ALL_LINES('RFA')) // RESTRICTIVE FIRE AREA (RFA) -labels['G*F*ACPR--'] = B('"PAA"') // POSITION AREA FOR ARTILLERY (PAA) -labels['G*F*ACER--'] = C(ALL_LINES('SENSOR ZONE')) // SENSOR ZONE -labels['G*F*ACDR--'] = C(ALL_LINES('DA')) // DEAD SPACE AREA (DA) -labels['G*F*ACZR--'] = C(ALL_LINES('ZOR')) // ZONE OF RESPONSIBILITY (ZOR) -labels['G*F*ACBR--'] = C(ALL_LINES('TBA')) // TARGET BUILD-UP AREA (TBA) -labels['G*F*ACVR--'] = C(ALL_LINES('TVAR')) // TARGET VALUE AREA (TVAR) -labels['G*F*AT----'] = C(ALL_LINES()) // AREA TARGET -labels['G*F*ATG---'] = T('t') // SERIES OR GROUP OF TARGETS -labels['G*F*ATR---'] = C(ALL_LINES()) // RECTANGULAR TARGET -labels['G*F*ATS---'] = C(ALL_LINES('SMOKE')) // AREA TARGET / SMOKE -labels['G*F*ATB---'] = C(ALL_LINES('BOMB')) // BOMB AREA -labels['G*F*ACSI--'] = C(ALL_LINES('FSA')) // FIRE SUPPORT AREA (FSA) -labels['G*F*ACAI--'] = C(ALL_LINES('ACA')) // AIRSPACE COORDINATION AREA (ACA) -labels['G*F*ACFI--'] = C(ALL_LINES('FFA')) // FREE FIRE AREA (FFA) -labels['G*F*ACNI--'] = C(ALL_LINES('NFA'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // NO-FIRE AREA (NFA) -labels['G*F*ACRI--'] = C(ALL_LINES('RFA')) // RESTRICTIVE FIRE AREA (RFA) -labels['G*F*ACEI--'] = C(ALL_LINES('SENSOR ZONE')) // SENSOR ZONE -labels['G*F*ACDI--'] = C(ALL_LINES('DA')) // DEAD SPACE AREA (DA) -labels['G*F*ACZI--'] = C(ALL_LINES('ZOR')) // ZONE OF RESPONSIBILITY (ZOR) -labels['G*F*ACBI--'] = C(ALL_LINES('TBA')) // TARGET BUILD-UP AREA (TBA) -labels['G*F*ACVI--'] = C(ALL_LINES('TVAR')) // TARGET VALUE AREA (TVAR) -labels['G*F*ACT---'] = C(ALL_LINES('TGMF')) // TERMINALLY GUIDED MUNITION FOOTPRINT (TGMF) -labels['G*F*AKBR--'] = C(ALL_LINES('BKB'), HALO) // KILL BOX/BLUE -labels['G*F*AKPR--'] = C(ALL_LINES('PKB'), HALO) // KILL BOX/PURPLE -labels['G*F*AZII--'] = C(ALL_LINES('ATI ZONE')) // ARTILLERY TARGET INTELLIGENCE (ATI) ZONE -labels['G*F*AZIR--'] = C(ALL_LINES('ATI ZONE')) // ARTILLERY TARGET INTELLIGENCE (ATI) ZONE -labels['G*F*AZXI--'] = C(ALL_LINES('CFF ZONE')) // CALL FOR FIRE ZONE (CFFZ) -labels['G*F*AZXR--'] = C(ALL_LINES('CFF ZONE')) // CALL FOR FIRE ZONE (CFFZ) -labels['G*F*AZCI--'] = C(ALL_LINES('CENSOR ZONE')) // CENSOR ZONE -labels['G*F*AZCR--'] = C(ALL_LINES('CENSOR ZONE')) // CENSOR ZONE -labels['G*F*AZFI--'] = C(ALL_LINES('CF ZONE')) // CRITICAL FRIENDLY ZONE (CFZ) -labels['G*F*AZFR--'] = C(ALL_LINES('CF ZONE')) // CRITICAL FRIENDLY ZONE (CFZ) -labels['G*F*AKBI--'] = C(ALL_LINES('BKB'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // KILL BOX / BLUE -labels['G*F*AKPI--'] = C(ALL_LINES('PKB'), { 'text-halo-color': 'white', 'text-halo-width': 5 }) // KILL BOX / PURPLE -labels['G*S*AD----'] = C(ALL_LINES('DETAINEE\nHOLDING\nAREA')) // DETAINEE HOLDING AREA -labels['G*S*AE----'] = C(ALL_LINES('EPW\nHOLDING\nAREA')) // ENEMY PRISONER OF WAR (EPW) HOLDING AREA -labels['G*S*AR----'] = C(ALL_LINES('FARP')) // FORWARD ARMING AND REFUELING AREA (FARP) -labels['G*S*AH----'] = C(ALL_LINES('REFUGEE\nHOLDING\nAREA')) // REFUGEE HOLDING AREA -labels['G*S*ASB---'] = C(ALL_LINES('BSA')) // SUPPORT AREAS / BRIGADE (BSA) -labels['G*S*ASD---'] = C(ALL_LINES('DSA')) // SUPPORT AREAS / DIVISON (DSA) -labels['G*S*ASR---'] = C(ALL_LINES('RSA')) // SUPPORT AREAS / REGIMENTAL (DSA) -labels['G*M*NR----'] = [{ 'symbol-code': 'GFMPNZ----', 'symbol-anchor': 'center' }] // RADIOACTIVE AREA -labels['G*M*NB----'] = [{ 'symbol-code': 'GFMPNEB---', 'symbol-anchor': 'center' }] // BIOLOGICALLY CONTAMINATED AREA -labels['G*M*NC----'] = [{ 'symbol-code': 'GFMPNEC---', 'symbol-anchor': 'center' }] // CHEMICALLY CONTAMINATED AREA diff --git a/src/renderer/ol/style/rules.js b/src/renderer/ol/style/rules.js index edc2a093..3bfc372f 100644 --- a/src/renderer/ol/style/rules.js +++ b/src/renderer/ol/style/rules.js @@ -44,7 +44,10 @@ export const reduce = (state, facts, rank = 0) => { const isStale = rule => deps(rule).some(key => changed.includes(key)) const isFulfilled = rule => deps(rule).every(key => !R.isNil(next[key])) const head = state.rules[rank] - const catcher = (err, next) => reduce(state, { ...next, err }, ++rank) + const catcher = (err, next) => { + console.error(err) + return reduce(state, { ...next, err }, ++rank) + } const tryer = next => isStale(head) && isFulfilled(head) ? reduce(state, { ...next, ...fn(head)(next) }, ++rank) : reduce(state, next, ++rank)