From 41dd564fcc740e99fa4a1a58ba707b22a877a7b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Benitte?= Date: Thu, 28 Mar 2019 06:13:13 +0900 Subject: [PATCH] fix(legends): fix legends unit tests --- packages/core/src/theming/defaultTheme.js | 4 +- packages/geo/src/Choropleth.js | 201 +++++++------ packages/geo/src/ChoroplethCanvas.js | 277 ++++++++++-------- packages/geo/src/hooks.js | 2 +- packages/legends/src/svg/LegendSvgItem.js | 8 +- .../legends/tests/svg/LegendSvgItem.test.js | 21 +- 6 files changed, 289 insertions(+), 224 deletions(-) diff --git a/packages/core/src/theming/defaultTheme.js b/packages/core/src/theming/defaultTheme.js index 5fc1f09474..408d0cd2b2 100644 --- a/packages/core/src/theming/defaultTheme.js +++ b/packages/core/src/theming/defaultTheme.js @@ -36,7 +36,9 @@ export const defaultTheme = { }, }, legends: { - text: {}, + text: { + fill: '#333333', + }, }, labels: { text: {}, diff --git a/packages/geo/src/Choropleth.js b/packages/geo/src/Choropleth.js index 830458adb0..3a682fe106 100644 --- a/packages/geo/src/Choropleth.js +++ b/packages/geo/src/Choropleth.js @@ -14,114 +14,135 @@ import GeoGraticule from './GeoGraticule' import GeoMapFeature from './GeoMapFeature' import { useGeoMap, useChoropleth } from './hooks' -const Choropleth = memo(({ width, height, margin: partialMargin, - features, data, match, label, value, valueFormat, - projectionType, projectionScale, projectionTranslation, projectionRotation, - colors, unknownColor, borderWidth, borderColor, - enableGraticule, graticuleLineWidth, graticuleLineColor, - layers, - legends, - isInteractive, onClick, tooltip: Tooltip }) => { - const { margin, outerWidth, outerHeight } = useDimensions(width, height, partialMargin) - const { graticule, path, getBorderWidth, getBorderColor } = useGeoMap({ +const Choropleth = memo( + ({ width, height, - projectionType, - projectionScale, - projectionTranslation, - projectionRotation, - fillColor: () => {}, - borderWidth, - borderColor, - }) - const { getFillColor, boundFeatures, legendData } = useChoropleth({ + margin: partialMargin, features, data, match, label, value, valueFormat, + projectionType, + projectionScale, + projectionTranslation, + projectionRotation, colors, unknownColor, - }) + borderWidth, + borderColor, + enableGraticule, + graticuleLineWidth, + graticuleLineColor, + layers, + legends, + isInteractive, + onClick, + tooltip: Tooltip, + }) => { + const { margin, outerWidth, outerHeight } = useDimensions(width, height, partialMargin) + const { graticule, path, getBorderWidth, getBorderColor } = useGeoMap({ + width, + height, + projectionType, + projectionScale, + projectionTranslation, + projectionRotation, + fillColor: () => {}, + borderWidth, + borderColor, + }) + const { getFillColor, boundFeatures, legendData } = useChoropleth({ + features, + data, + match, + label, + value, + valueFormat, + colors, + unknownColor, + }) - const theme = useTheme() + const theme = useTheme() - const [showTooltip, hideTooltip] = useTooltip() - const handleClick = useCallback( - (feature, event) => isInteractive && onClick && onClick(feature, event), - [isInteractive, onClick] - ) - const handleMouseEnter = useCallback( - (feature, event) => - isInteractive && Tooltip && showTooltip(, event), - [isInteractive, showTooltip, Tooltip] - ) - const handleMouseMove = useCallback( - (feature, event) => - isInteractive && Tooltip && showTooltip(, event), - [isInteractive, showTooltip, Tooltip] - ) - const handleMouseLeave = useCallback(() => isInteractive && hideTooltip(), [ - isInteractive, - hideTooltip, - ]) + const [showTooltip, hideTooltip] = useTooltip() + const handleClick = useCallback( + (feature, event) => isInteractive && onClick && onClick(feature, event), + [isInteractive, onClick] + ) + const handleMouseEnter = useCallback( + (feature, event) => + isInteractive && Tooltip && showTooltip(, event), + [isInteractive, showTooltip, Tooltip] + ) + const handleMouseMove = useCallback( + (feature, event) => + isInteractive && Tooltip && showTooltip(, event), + [isInteractive, showTooltip, Tooltip] + ) + const handleMouseLeave = useCallback(() => isInteractive && hideTooltip(), [ + isInteractive, + hideTooltip, + ]) - return ( - - {layers.map((layer, i) => { - if (layer === 'graticule') { - if (enableGraticule !== true) return null + return ( + + {layers.map((layer, i) => { + if (layer === 'graticule') { + if (enableGraticule !== true) return null - return ( - - ) - } - if (layer === 'features') { - return ( - - {boundFeatures.map(feature => ( - - ))} - - ) - } - if (layer === 'legends') { - return legends.map((legend, i) => { return ( - ) - }) - } + } + if (layer === 'features') { + return ( + + {boundFeatures.map(feature => ( + + ))} + + ) + } + if (layer === 'legends') { + return legends.map((legend, i) => { + return ( + + ) + }) + } - return {layer({})} - })} - - ) -}) + return {layer({})} + })} + + ) + } +) Choropleth.displayName = 'Choropleth' Choropleth.propTypes = ChoroplethPropTypes diff --git a/packages/geo/src/ChoroplethCanvas.js b/packages/geo/src/ChoroplethCanvas.js index e451768cca..c34893b137 100644 --- a/packages/geo/src/ChoroplethCanvas.js +++ b/packages/geo/src/ChoroplethCanvas.js @@ -19,150 +19,183 @@ const getFeatureFromMouseEvent = (event, el, features, projection) => { return features.find(f => geoContains(f, projection.invert([x, y]))) } -const ChoroplethCanvas = memo(({ width, height, margin: partialMargin, pixelRatio, - features, data, match, label, value, valueFormat, - projectionType, projectionScale, projectionTranslation, projectionRotation, - colors, unknownColor, borderWidth, borderColor, - enableGraticule, graticuleLineWidth, graticuleLineColor, - layers, - legends, - isInteractive, onClick, onMouseMove, tooltip: Tooltip }) => { - const canvasEl = useRef(null) - const theme = useTheme() - const { margin, outerWidth, outerHeight } = useDimensions(width, height, partialMargin) - const { projection, graticule, path, getBorderWidth, getBorderColor } = useGeoMap({ +const ChoroplethCanvas = memo( + ({ width, height, - projectionType, - projectionScale, - projectionTranslation, - projectionRotation, - fillColor: () => {}, - borderWidth, - borderColor, - }) - const { getFillColor, boundFeatures, legendData } = useChoropleth({ + margin: partialMargin, + pixelRatio, features, data, match, label, value, valueFormat, + projectionType, + projectionScale, + projectionTranslation, + projectionRotation, colors, unknownColor, - }) + borderWidth, + borderColor, + enableGraticule, + graticuleLineWidth, + graticuleLineColor, + layers, + legends, + isInteractive, + onClick, + onMouseMove, + tooltip: Tooltip, + }) => { + const canvasEl = useRef(null) + const theme = useTheme() + const { margin, outerWidth, outerHeight } = useDimensions(width, height, partialMargin) + const { projection, graticule, path, getBorderWidth, getBorderColor } = useGeoMap({ + width, + height, + projectionType, + projectionScale, + projectionTranslation, + projectionRotation, + fillColor: () => {}, + borderWidth, + borderColor, + }) + const { getFillColor, boundFeatures, legendData } = useChoropleth({ + features, + data, + match, + label, + value, + valueFormat, + colors, + unknownColor, + }) - useEffect(() => { - if (!canvasEl) return + useEffect(() => { + if (!canvasEl) return - canvasEl.current.width = outerWidth * pixelRatio - canvasEl.current.height = outerHeight * pixelRatio + canvasEl.current.width = outerWidth * pixelRatio + canvasEl.current.height = outerHeight * pixelRatio - const ctx = canvasEl.current.getContext('2d') + const ctx = canvasEl.current.getContext('2d') - ctx.scale(pixelRatio, pixelRatio) + ctx.scale(pixelRatio, pixelRatio) - ctx.fillStyle = theme.background - ctx.fillRect(0, 0, outerWidth, outerHeight) - ctx.translate(margin.left, margin.top) + ctx.fillStyle = theme.background + ctx.fillRect(0, 0, outerWidth, outerHeight) + ctx.translate(margin.left, margin.top) - path.context(ctx) + path.context(ctx) - layers.forEach(layer => { - if (layer === 'graticule') { - if (enableGraticule === true) { - ctx.lineWidth = graticuleLineWidth - ctx.strokeStyle = graticuleLineColor - ctx.beginPath() - path(graticule()) - ctx.stroke() - } - } else if (layer === 'features') { - boundFeatures.forEach(feature => { - ctx.beginPath() - path(feature) - ctx.fillStyle = getFillColor(feature) - ctx.fill() - - const borderWidth = getBorderWidth(feature) - if (borderWidth > 0) { - ctx.strokeStyle = getBorderColor(feature) - ctx.lineWidth = borderWidth + layers.forEach(layer => { + if (layer === 'graticule') { + if (enableGraticule === true) { + ctx.lineWidth = graticuleLineWidth + ctx.strokeStyle = graticuleLineColor + ctx.beginPath() + path(graticule()) ctx.stroke() } - }) - } else if (layer === 'legends') { - legends.forEach(legend => { - renderLegendToCanvas(ctx, { - ...legend, - data: legendData, - containerWidth: width, - containerHeight: height, - theme, + } else if (layer === 'features') { + boundFeatures.forEach(feature => { + ctx.beginPath() + path(feature) + ctx.fillStyle = getFillColor(feature) + ctx.fill() + + const borderWidth = getBorderWidth(feature) + if (borderWidth > 0) { + ctx.strokeStyle = getBorderColor(feature) + ctx.lineWidth = borderWidth + ctx.stroke() + } + }) + } else if (layer === 'legends') { + legends.forEach(legend => { + renderLegendToCanvas(ctx, { + ...legend, + data: legendData, + containerWidth: width, + containerHeight: height, + theme, + }) }) - }) + } else { + // layer(ctx, {}) + } + }) + }, [ + canvasEl, + outerWidth, + outerHeight, + margin, + pixelRatio, + theme, + path, + graticule, + getFillColor, + getBorderWidth, + getBorderColor, + boundFeatures, + legends, + layers, + ]) + + const [showTooltip, hideTooltip] = useTooltip() + const handleMouseMove = useCallback(() => { + if (!isInteractive || !Tooltip) return + + const feature = getFeatureFromMouseEvent( + event, + canvasEl.current, + boundFeatures, + projection + ) + if (feature) { + showTooltip(, event) } else { - layer(ctx, props) + hideTooltip() } - }) - }, [ - canvasEl, - outerWidth, - outerHeight, - margin, - pixelRatio, - theme, - path, - graticule, - getFillColor, - getBorderWidth, - getBorderColor, - boundFeatures, - legends, - layers, - ]) - - const [showTooltip, hideTooltip] = useTooltip() - const handleMouseMove = useCallback(() => { - if (!isInteractive || !Tooltip) return - - const feature = getFeatureFromMouseEvent(event, canvasEl.current, boundFeatures, projection) - if (feature) { - showTooltip(, event) - } else { - hideTooltip() - } - onMouseMove && onMouseMove(feature || null, event) - }, [showTooltip, hideTooltip, isInteractive, Tooltip, canvasEl, boundFeatures, projection]) - const handleMouseLeave = useCallback(() => isInteractive && hideTooltip(), [ - isInteractive, - hideTooltip, - ]) - const handleClick = useCallback(() => { - if (!isInteractive || !onClick) return - - const feature = getFeatureFromMouseEvent(event, canvasEl.current, boundFeatures, projection) - if (feature) { - onClick(feature, event) - } - }, [isInteractive, canvasEl, boundFeatures, projection, onClick]) - - return ( - - ) -}) + onMouseMove && onMouseMove(feature || null, event) + }, [showTooltip, hideTooltip, isInteractive, Tooltip, canvasEl, boundFeatures, projection]) + const handleMouseLeave = useCallback(() => isInteractive && hideTooltip(), [ + isInteractive, + hideTooltip, + ]) + const handleClick = useCallback(() => { + if (!isInteractive || !onClick) return + + const feature = getFeatureFromMouseEvent( + event, + canvasEl.current, + boundFeatures, + projection + ) + if (feature) { + onClick(feature, event) + } + }, [isInteractive, canvasEl, boundFeatures, projection, onClick]) + + return ( + + ) + } +) ChoroplethCanvas.displayName = 'ChoroplethCanvas' ChoroplethCanvas.propTypes = ChoroplethCanvasPropTypes diff --git a/packages/geo/src/hooks.js b/packages/geo/src/hooks.js index d26b8a44e4..aca0372b02 100644 --- a/packages/geo/src/hooks.js +++ b/packages/geo/src/hooks.js @@ -24,7 +24,7 @@ import { geoGraticule, } from 'd3-geo' import { guessQuantizeColorScale } from '@nivo/core' -import { useQuantizeColorScaleLegendData, BoxLegendSvg } from '@nivo/legends' +import { useQuantizeColorScaleLegendData } from '@nivo/legends' export const projectionById = { azimuthalEqualArea: geoAzimuthalEqualArea, diff --git a/packages/legends/src/svg/LegendSvgItem.js b/packages/legends/src/svg/LegendSvgItem.js index 7aa388efc3..1e9ebccbca 100644 --- a/packages/legends/src/svg/LegendSvgItem.js +++ b/packages/legends/src/svg/LegendSvgItem.js @@ -165,12 +165,8 @@ LegendSvgItem.propTypes = { background: PropTypes.string, opacity: PropTypes.number, - direction: PropTypes.oneOf([ - 'left-to-right', - 'right-top-left', - 'top-to-bottom', - 'bottom-to-top', - ]).isRequired, + direction: PropTypes.oneOf(['left-to-right', 'right-to-left', 'top-to-bottom', 'bottom-to-top']) + .isRequired, justify: PropTypes.bool.isRequired, ...symbolPropTypes, diff --git a/packages/legends/tests/svg/LegendSvgItem.test.js b/packages/legends/tests/svg/LegendSvgItem.test.js index e5e7019d0b..54b4a32e51 100644 --- a/packages/legends/tests/svg/LegendSvgItem.test.js +++ b/packages/legends/tests/svg/LegendSvgItem.test.js @@ -6,11 +6,11 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ -import React from 'react' +import React, { Component } from 'react' import renderer from 'react-test-renderer' import { mount } from 'enzyme' -import { defaultTheme } from '@nivo/core' -import LegendSvgItem from '../../src/svg/LegendSvgItem' +import { defaultTheme, themeContext } from '@nivo/core' +import { default as BaseLegendSvgItem } from '../../src/svg/LegendSvgItem' import * as shapes from '../../src/svg/symbols' import { DIRECTION_LEFT_TO_RIGHT, @@ -24,7 +24,6 @@ const commonProps = { y: 0, width: 200, height: 36, - theme: defaultTheme, data: { id: 'testing', label: 'testing', @@ -39,6 +38,20 @@ const directions = [ DIRECTION_BOTTOM_TO_TOP, ] +const withTheme = WrappedComponent => { + return class ThemedLegendSvgItem extends Component { + render() { + return ( + + + + ) + } + } +} + +const LegendSvgItem = withTheme(BaseLegendSvgItem) + directions.forEach(direction => { it(`should support ${direction} direction`, () => { const component = renderer.create()