Skip to content
Snippets Groups Projects
Commit b76e17f4 authored by Williams, Darius Shamar's avatar Williams, Darius Shamar
Browse files

Removing old files, adding new tests

parent 91953229
No related branches found
No related tags found
1 merge request!421Wdfn 768 - Convert the legend component to vue
This commit is part of merge request !421. Comments created here will be created in the context of that merge request.
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
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);
});
});
});
......@@ -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
......@@ -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', () => {
......
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
})));
};
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);
});
});
});
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
......@@ -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 {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment