From b76e17f4b0366faf6c628e5ba32ec4a3fbf29aef Mon Sep 17 00:00:00 2001 From: Darius Williams <dswilliams@contractor.usgs.gov> Date: Mon, 1 Aug 2022 15:55:15 -0500 Subject: [PATCH] Removing old files, adding new tests --- assets/src/scripts/d3-rendering/legend.js | 102 ------------- .../src/scripts/d3-rendering/legend.test.js | 83 ----------- .../components/hydrograph/HydrographApp.vue | 11 +- .../components/hydrograph/index.test.js | 2 +- .../components/hydrograph/legend.js | 18 --- .../components/hydrograph/legend.test.js | 68 --------- .../hydrograph/vue-components/legend.test.js | 71 ++++++--- .../hydrograph/vue-components/legend.vue | 136 +++++++++--------- 8 files changed, 124 insertions(+), 367 deletions(-) delete mode 100644 assets/src/scripts/d3-rendering/legend.js delete mode 100644 assets/src/scripts/d3-rendering/legend.test.js delete mode 100644 assets/src/scripts/monitoring-location/components/hydrograph/legend.js delete mode 100644 assets/src/scripts/monitoring-location/components/hydrograph/legend.test.js diff --git a/assets/src/scripts/d3-rendering/legend.js b/assets/src/scripts/d3-rendering/legend.js deleted file mode 100644 index 1065fc979..000000000 --- a/assets/src/scripts/d3-rendering/legend.js +++ /dev/null @@ -1,102 +0,0 @@ -import config from 'ui/config'; -import {mediaQuery} from 'ui/utils'; - -const RECTANGLE_MARKER_WIDTH = 20; -const RECTANGLE_MARKER_HEIGHT = 10; -const LINE_MARKER_WIDTH = 20; -const MARKER_GROUP_X_OFFSET = 15; -const VERTICAL_ROW_OFFSET = 18; - -/** - * Create a simple legend - * - * @param {Object} div - d3 selector where legend should be created - * @param {Object} legendMarkerRows - Array of rows. Each row should be an array of legend markers. - * @param {Object} layout - width and height of svg. - */ -export const drawSimpleLegend = function(div, {legendMarkerRows, layout}) { - div.selectAll('.legend-svg').remove(); - - const svg = div.append('svg') - .attr('class', 'legend-svg'); - if (!legendMarkerRows.length || !layout) { - return; - } - const legend = svg - .append('g') - .attr('class', 'legend') - .attr('transform', `translate(${mediaQuery(config.USWDS_MEDIUM_SCREEN) ? layout.margin.left : 0}, 0)`); - - let yPosition = VERTICAL_ROW_OFFSET; - legendMarkerRows.forEach((rowMarkers) => { - let xPosition = 0; - let markerArgs; - let markerGroup; - let lastMarker; - - const getNewXPosition = function(markerGroup, lastXPosition) { - // Long story short, firefox is unable to get the bounding box if - // the svg element isn't actually taking up space and visible. Folks on the - // internet seem to have gotten around this by setting `visibility:hidden` - // to hide things, but that would still mean the elements will take up space. - // which we don't want. So, here's some error handling for getBBox failures. - // This handling ends up not creating the legend, but that's okay because the - // graph is being shown anyway. A more detailed discussion of this can be found at: - // https://bugzilla.mozilla.org/show_bug.cgi?id=612118 and - // https://stackoverflow.com/questions/28282295/getbbox-of-svg-when-hidden. - try { - const markerGroupBBox = markerGroup.node().getBBox(); - return markerGroupBBox.x + markerGroupBBox.width + MARKER_GROUP_X_OFFSET; - } catch (error) { - // See above explanation - return lastXPosition; - } - }; - - const repositionLastMarkerWhenNeeded = function() { - if (xPosition - MARKER_GROUP_X_OFFSET > layout.width) { - // Need to remove the last marker and draw it on the next row. - markerGroup.remove(); - xPosition = 0; - yPosition = yPosition + VERTICAL_ROW_OFFSET; - markerArgs.x = xPosition; - markerArgs.y = yPosition; - markerGroup = lastMarker.type(legend, markerArgs); - xPosition = getNewXPosition(markerGroup, xPosition); - } - }; - - rowMarkers.forEach((marker) => { - repositionLastMarkerWhenNeeded(); - - markerArgs = { - x: xPosition, - y: yPosition, - text: marker.text, - domId: marker.domId, - domClass: marker.domClass, - width: RECTANGLE_MARKER_WIDTH, - height: RECTANGLE_MARKER_HEIGHT, - length: LINE_MARKER_WIDTH, - r: marker.radius, - fill: marker.fill - }; - - lastMarker = marker; - markerGroup = marker.type(legend, markerArgs); - xPosition = getNewXPosition(markerGroup, xPosition); - }); - repositionLastMarkerWhenNeeded(); - //start new reow - yPosition = yPosition = yPosition + VERTICAL_ROW_OFFSET; - }); - - // Set the size of the containing svg node to the size of the legend. - let bBox; - try { - bBox = legend.node().getBBox(); - } catch (error) { - return; - } - svg.attr('viewBox', `0 0 ${layout.width} ${bBox.height + 10}`); -}; \ No newline at end of file diff --git a/assets/src/scripts/d3-rendering/legend.test.js b/assets/src/scripts/d3-rendering/legend.test.js deleted file mode 100644 index 3cd27c5ce..000000000 --- a/assets/src/scripts/d3-rendering/legend.test.js +++ /dev/null @@ -1,83 +0,0 @@ -import {select} from 'd3-selection'; - -import * as utils from 'ui/utils'; - -import {drawSimpleLegend} from './legend'; -import {circleMarker, lineMarker, rectangleMarker, textOnlyMarker} from './markers'; - -describe('Legend module', () => { - - utils.mediaQuery = jest.fn().mockReturnValue(true); - describe('drawSimpleLegend', () => { - let container; - - const legendMarkerRows = [ - [{ - type: lineMarker, - length: 20, - domId: 'some-id', - domClass: 'some-class', - text: 'Some Text' - }, { - type: rectangleMarker, - domId: 'some-rectangle-id', - domClass: 'some-rectangle-class', - text: 'Rectangle Marker' - }], - [{ - type: textOnlyMarker, - domId: 'text-id', - domClass: 'text-class', - text: 'Label' - }, { - type: lineMarker, - domId: null, - domClass: 'some-other-class', - text: 'Median Label' - }, { - type: circleMarker, - domId: null, - domClass: 'circle-marker-class', - text: 'Circle Marker label', - radius: 5 - }] - ]; - const layout = { - width: 100, - height: 100, - margin: { - top: 0, - right: 0, - bottom: 0, - left: 0 - } - }; - - beforeEach(() => { - container = select('body').append('div'); - }); - - afterEach(() => { - container.remove(); - }); - - it('If no markers are provided legend-svg will contain no groups', () => { - drawSimpleLegend(container, { - legendMarkerRows: [], - layout: layout - }); - - expect(container.select('svg g').size()).toBe(0); - }); - - it('Adds a legend when width is provided', () => { - drawSimpleLegend(container, {legendMarkerRows, layout}); - - expect(container.select('svg').size()).toBe(1); - expect(container.selectAll('line').size()).toBe(2); - expect(container.selectAll('rect').size()).toBe(1); - expect(container.selectAll('text').size()).toBe(5); - expect(container.selectAll('circle').size()).toBe(1); - }); - }); -}); diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/HydrographApp.vue b/assets/src/scripts/monitoring-location/components/hydrograph/HydrographApp.vue index c12507eb1..57c5a5467 100644 --- a/assets/src/scripts/monitoring-location/components/hydrograph/HydrographApp.vue +++ b/assets/src/scripts/monitoring-location/components/hydrograph/HydrographApp.vue @@ -2,7 +2,12 @@ <div> <CursorSlider /> <GraphBrush /> - <Legend /> + <div class="ts-legend-controls-container"> + <Legend /> + <div class="graph-controls-container"> + <GraphControls /> + </div> + </div> </div> </template> @@ -10,12 +15,14 @@ import GraphBrush from './vue-components/graph-brush.vue'; import CursorSlider from './vue-components/cursor-slider.vue'; import Legend from './vue-components/legend.vue' +import GraphControls from './vue-components/graph-controls.vue'; export default { name: 'HydrographApp', components: { GraphBrush, CursorSlider, - Legend + Legend, + GraphControls } }; </script> \ No newline at end of file diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/index.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/index.test.js index b24c602a4..f019eb341 100644 --- a/assets/src/scripts/monitoring-location/components/hydrograph/index.test.js +++ b/assets/src/scripts/monitoring-location/components/hydrograph/index.test.js @@ -430,7 +430,7 @@ describe('monitoring-location/components/hydrograph module', () => { }); it('should render the correct number of svg nodes', () => { - expect(selectAll('svg').size()).toBe(2); + expect(selectAll('svg').size()).toBe(1); }); it('should have a title div', () => { diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/legend.js b/assets/src/scripts/monitoring-location/components/hydrograph/legend.js deleted file mode 100644 index bb05f6765..000000000 --- a/assets/src/scripts/monitoring-location/components/hydrograph/legend.js +++ /dev/null @@ -1,18 +0,0 @@ -import {createStructuredSelector} from 'reselect'; - -import {drawSimpleLegend} from 'd3render/legend'; -import {link} from 'ui/lib/d3-redux'; - -import {getMainLayout} from './selectors/layout'; -import {getLegendMarkerRows} from './selectors/legend-data'; - - -export const drawTimeSeriesLegend = function(elem, store) { - elem.append('div') - .classed('hydrograph-container', true) - .call(link(store, drawSimpleLegend, createStructuredSelector({ - legendMarkerRows: getLegendMarkerRows, - layout: getMainLayout - }))); -}; - diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/legend.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/legend.test.js deleted file mode 100644 index 6347641a7..000000000 --- a/assets/src/scripts/monitoring-location/components/hydrograph/legend.test.js +++ /dev/null @@ -1,68 +0,0 @@ -import {select, selectAll} from 'd3-selection'; - -import config from 'ui/config'; -import * as utils from 'ui/utils'; - -import {configureStore} from 'ml/store'; - -import {drawTimeSeriesLegend} from './legend'; -import {TEST_PRIMARY_IV_DATA, TEST_GW_LEVELS} from './mock-hydrograph-state'; - -describe('monitoring-location/components/hydrograph/legend module', () => { - utils.mediaQuery = jest.fn().mockReturnValue(true); - config.ivPeriodOfRecord = { - '72019': {} - }; - config.gwPeriodOfRecord = { - '72019': {} - }; - const TEST_STATE = { - hydrographData: { - currentTimeRange: { - start: 1582560000000, - end: 1600700000000 - }, - primaryIVData: TEST_PRIMARY_IV_DATA - }, - groundwaterLevelData: { - all: [TEST_GW_LEVELS] - }, - hydrographState: { - showCompareIVData: false, - showMedianData: false, - selectedIVMethodID: '90649', - selectedParameterCode: '72019' - } - }; - - describe('legends should render', () => { - - let graphNode; - let store; - - beforeEach(() => { - let body = select('body'); - let component = body.append('div') - .attr('id', 'hydrograph'); - component.append('div').attr('class', 'loading-indicator-container'); - component.append('div').attr('class', 'graph-container'); - component.append('div').attr('class', 'select-time-series-container'); - - graphNode = document.getElementById('hydrograph'); - - store = configureStore(TEST_STATE); - select(graphNode) - .call(drawTimeSeriesLegend, store); - - }); - - afterEach(() => { - select('#hydrograph').remove(); - }); - - - it('Should have the correct number of legend markers', () => { - expect(selectAll('.legend g').size()).toBe(9); - }); - }); -}); diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.test.js index db74ea9f2..abbfa1068 100644 --- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.test.js +++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.test.js @@ -1,13 +1,17 @@ -import {select, selectAll} from 'd3-selection'; +import {mount} from '@vue/test-utils'; +import {bindActionCreators} from 'redux'; +import ReduxConnectVue from 'redux-connect-vue'; +import {createStructuredSelector} from 'reselect'; import config from 'ui/config'; import * as utils from 'ui/utils'; import {configureStore} from 'ml/store'; -import {drawTimeSeriesLegend} from './legend'; import {TEST_PRIMARY_IV_DATA, TEST_GW_LEVELS} from '../mock-hydrograph-state'; +import Legend from './legend.vue' + describe('monitoring-location/components/hydrograph/legend module', () => { utils.mediaQuery = jest.fn().mockReturnValue(true); config.ivPeriodOfRecord = { @@ -35,35 +39,58 @@ describe('monitoring-location/components/hydrograph/legend module', () => { } }; - describe('legends should render', () => { - - let graphNode; + utils.mediaQuery = jest.fn().mockReturnValue(true); + describe('drawSimpleLegend', () => { let store; + let wrapper; beforeEach(() => { - let body = select('body'); - let component = body.append('div') - .attr('id', 'hydrograph'); - component.append('div').attr('class', 'loading-indicator-container'); - component.append('div').attr('class', 'graph-container'); - component.append('div').attr('class', 'select-time-series-container'); - - graphNode = document.getElementById('hydrograph'); - store = configureStore(TEST_STATE); - select(graphNode) - .call(drawTimeSeriesLegend, store); + wrapper = mount(Legend, { + global: { + plugins: [ + [ReduxConnectVue, { + store, + mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch), + mapStateToPropsFactory: createStructuredSelector + }] + ] + } + }); }); - afterEach(() => { - select('#hydrograph').remove(); + it('Should have the correct number of legend markers', () => { + expect(wrapper.findAll('.legend g')).toHaveLength(9); }); + it('If no markers are provided legend-svg will contain no groups', () => { + wrapper = mount(Legend, { + global: { + plugins: [ + [ReduxConnectVue, { + store: configureStore({}), + mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch), + mapStateToPropsFactory: createStructuredSelector + }] + ] + } + }); - it('Should have the correct number of legend markers', () => { - expect(selectAll('.legend g').size()).toBe(9); + expect(wrapper.findAll('svg g')).toHaveLength(0); + }); + + it('Adds the correct number of legend elements', () => { + expect(wrapper.findAll('svg')).toHaveLength(1); + expect(wrapper.findAll('line')).toHaveLength(3); + expect(wrapper.findAll('rect')).toHaveLength(2); + expect(wrapper.findAll('text')).toHaveLength(9); + expect(wrapper.findAll('circle')).toHaveLength(3); + }); + + it('Expects that the legend has the expected text', () => { + let text = wrapper.findAll('text'); + }); }); -}); -z \ No newline at end of file +}); \ No newline at end of file diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.vue b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.vue index 00006944a..406734dd8 100644 --- a/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.vue +++ b/assets/src/scripts/monitoring-location/components/hydrograph/vue-components/legend.vue @@ -13,15 +13,10 @@ /> </svg> </div> - <div class="graph-controls-container"> - <GraphControls /> - </div> </div> </template> <script> -import GraphControls from './graph-controls.vue'; - import {useState} from 'redux-connect-vue'; import {computed, ref, watchEffect} from 'vue'; import {select} from 'd3-selection'; @@ -33,9 +28,6 @@ import config from 'ui/config'; export default { name: 'Legend', - components: { - GraphControls - }, setup() { const legend = ref(null); @@ -45,41 +37,29 @@ export default { const MARKER_GROUP_X_OFFSET = 15; const VERTICAL_ROW_OFFSET = 18; - let yPosition = VERTICAL_ROW_OFFSET; - const state = useState({ legendMarkerRows: getLegendMarkerRows, layout: getMainLayout }); - // Set the size of the containing svg node to the size of the legend. - const bBox = computed(() => { - try { - return select(legend.value).node().getBBox(); - } catch (error) { - return null; - } - }) - const legendTransform = computed(() => { return `translate(${mediaQuery(config.USWDS_MEDIUM_SCREEN) ? state.layout.value.margin.left : 0}, 0)`; }); - const svgViewBox = computed(() => { - if (bBox.value) { - return `0 0 ${state.layout.value.width} ${bBox.value.height + 10}`; - } - return '' - }); + let svgViewBox; watchEffect(() => { - state.legendMarkerRows.value.forEach((rowMarkers) => { - let xPosition = 0; - let markerArgs; - let markerGroup; - let lastMarker; + if (legend.value) { + select(legend.value).selectChildren().remove(); + let yPosition = VERTICAL_ROW_OFFSET; + + state.legendMarkerRows.value.forEach((rowMarkers) => { + let xPosition = 0; + let markerArgs; + let markerGroup; + let lastMarker; - const getNewXPosition = function(markerGroup, lastXPosition) { + const getNewXPosition = function(markerGroup, lastXPosition) { // Long story short, firefox is unable to get the bounding box if // the svg element isn't actually taking up space and visible. Folks on the // internet seem to have gotten around this by setting `visibility:hidden` @@ -96,48 +76,62 @@ export default { // See above explanation return lastXPosition; } - }; - - const repositionLastMarkerWhenNeeded = function() { - if (xPosition - MARKER_GROUP_X_OFFSET > state.layout.value.width && legend.value) { - // Need to remove the last marker and draw it on the next row. - markerGroup.remove(); - xPosition = 0; - yPosition = yPosition + VERTICAL_ROW_OFFSET; - markerArgs.x = xPosition; - markerArgs.y = yPosition; - markerGroup = lastMarker.type(legend.value, markerArgs); - xPosition = getNewXPosition(markerGroup, xPosition); - } - }; - - rowMarkers.forEach((marker) => { - if (legend.value) { - repositionLastMarkerWhenNeeded(); - - markerArgs = { - x: xPosition, - y: yPosition, - text: marker.text, - domId: marker.domId, - domClass: marker.domClass, - width: RECTANGLE_MARKER_WIDTH, - height: RECTANGLE_MARKER_HEIGHT, - length: LINE_MARKER_WIDTH, - r: marker.radius, - fill: marker.fill - }; - - lastMarker = marker; - markerGroup = marker.type(select(legend.value), markerArgs); - xPosition = getNewXPosition(markerGroup, xPosition); + }; + + const repositionLastMarkerWhenNeeded = function() { + if (xPosition - MARKER_GROUP_X_OFFSET > state.layout.value.width) { + // Need to remove the last marker and draw it on the next row. + markerGroup.remove(); + xPosition = 0; + yPosition = yPosition + VERTICAL_ROW_OFFSET; + markerArgs.x = xPosition; + markerArgs.y = yPosition; + markerGroup = lastMarker.type(legend.value, markerArgs); + xPosition = getNewXPosition(markerGroup, xPosition); + } + }; + + rowMarkers.forEach((marker) => { + repositionLastMarkerWhenNeeded(); + + markerArgs = { + x: xPosition, + y: yPosition, + text: marker.text, + domId: marker.domId, + domClass: marker.domClass, + width: RECTANGLE_MARKER_WIDTH, + height: RECTANGLE_MARKER_HEIGHT, + length: LINE_MARKER_WIDTH, + r: marker.radius, + fill: marker.fill + }; + + lastMarker = marker; + markerGroup = marker.type(select(legend.value), markerArgs); + xPosition = getNewXPosition(markerGroup, xPosition); + + }); + repositionLastMarkerWhenNeeded(); + //start new row + yPosition = yPosition = yPosition + VERTICAL_ROW_OFFSET; + }); + + // Set the size of the containing svg node to the size of the legend. + let bBox; + try { + bBox = select(legend.value).node().getBBox(); + } catch (error) { + return; + } + + svgViewBox = computed(() => { + if (bBox.value) { + return `0 0 ${state.layout.value.width} ${bBox.height + 10}`; } - + return '' }); - repositionLastMarkerWhenNeeded(); - //start new row - yPosition = yPosition = yPosition + VERTICAL_ROW_OFFSET; - }); + } }); return { -- GitLab