diff --git a/packages/vx-demo/src/components/gallery.js b/packages/vx-demo/src/components/gallery.js index 25f3d08ff0..e2dcbbe0ea 100644 --- a/packages/vx-demo/src/components/gallery.js +++ b/packages/vx-demo/src/components/gallery.js @@ -35,8 +35,8 @@ import Pack from './tiles/Pack.tsx'; import Treemap from './tiles/Treemap.tsx'; import Radar from './tiles/radar'; import Responsive from './tiles/Responsive.tsx'; -import DragI from './tiles/drag-i'; -import DragII from './tiles/drag-ii'; +import DragI from './tiles/Drag-i.tsx'; +import DragII from './tiles/Drag-ii.tsx'; import LinkTypes from './tiles/LinkTypes.tsx'; import Threshold from './tiles/Threshold.tsx'; import Chord from './tiles/Chord.tsx'; diff --git a/packages/vx-demo/src/components/tiles/Drag-i.tsx b/packages/vx-demo/src/components/tiles/Drag-i.tsx new file mode 100644 index 0000000000..f7898efe64 --- /dev/null +++ b/packages/vx-demo/src/components/tiles/Drag-i.tsx @@ -0,0 +1,131 @@ +import React, { useMemo, useState } from 'react'; +import { scaleOrdinal } from '@vx/scale'; +import { LinearGradient } from '@vx/gradient'; +import { Drag, raise } from '@vx/drag'; +import { WidthAndHeight, ShowProvidedProps } from '../../types'; + +const colors = [ + '#025aac', + '#02cff9', + '#02efff', + '#03aeed', + '#0384d7', + '#edfdff', + '#ab31ff', + '#5924d7', + '#d145ff', + '#1a02b1', + '#e582ff', + '#ff00d4', + '#270eff', + '#827ce2', +]; + +const generateCircles = ({ num, width, height }: { num: number } & WidthAndHeight) => + new Array(num).fill(1).map((d, i) => { + const radius = 25 - Math.random() * 20; + return { + id: `${i}`, + radius, + x: Math.round(Math.random() * (width - radius * 2) + radius), + y: Math.round(Math.random() * (height - radius * 2) + radius), + }; + }); + +const generateItems = ({ width, height }: WidthAndHeight) => + generateCircles({ + num: width < 360 ? 40 : 185, + width, + height, + }); + +export default function DragI({ width, height }: ShowProvidedProps) { + const memoizedItems = useMemo(() => generateItems({ width, height }), [width, height]); + const [draggingItems, setDraggingItems] = useState(memoizedItems); + + const colorScale = useMemo( + () => + scaleOrdinal({ + range: colors, + domain: draggingItems.map(d => d.id), + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [width, height], + ); + + if (width < 10) return null; + + return ( +
+ + + + + {draggingItems.map((d, i) => ( + { + // svg follows the painter model + // so we need to move the data item + // to end of the array for it to be drawn + // "on top of" the other data items + setDraggingItems(raise(draggingItems, i)); + }} + > + {({ dragStart, dragEnd, dragMove, isDragging, dx, dy }) => + (false && isDragging && console.log(d.id, d.x, dx)) || ( + + ) + } + + ))} + +
+
+ Based on Mike Bostock's{' '} + + Circle Dragging II + +
+
+ + +
+ ); +} diff --git a/packages/vx-demo/src/components/tiles/Drag-ii.tsx b/packages/vx-demo/src/components/tiles/Drag-ii.tsx new file mode 100644 index 0000000000..d9ff12f477 --- /dev/null +++ b/packages/vx-demo/src/components/tiles/Drag-ii.tsx @@ -0,0 +1,124 @@ +import React, { useState } from 'react'; +import { LinePath } from '@vx/shape'; +import { Drag } from '@vx/drag'; +import { curveBasis } from '@vx/curve'; +import { LinearGradient } from '@vx/gradient'; +import { ShowProvidedProps } from '../../types'; + +type Lines = { x: number; y: number }[][]; + +export default function DragII({ width, height }: ShowProvidedProps) { + const [lines, setLines] = useState([]); + + if (width < 10) return null; + return ( +
+ + + + {lines.map((line, i) => ( + d.x} + y={d => d.y} + /> + ))} + { + // add the new line with the starting point + setLines(currLines => [...currLines, [{ x, y }]]); + }} + onDragMove={({ x = 0, y = 0, dx, dy }) => { + // add the new point to the current line + setLines(currLines => { + const nextLines = [...currLines]; + const newPoint = { x: x + dx, y: y + dy }; + const lastIndex = nextLines.length - 1; + nextLines[lastIndex] = [...(nextLines[lastIndex] || []), newPoint]; + return nextLines; + }); + }} + > + {({ x = 0, y = 0, dx, dy, isDragging, dragStart, dragEnd, dragMove }) => ( + + {/* decorate the currently drawing line */} + {isDragging && ( + + + + + )} + {/* create the drawing area */} + + + )} + + +
+
+ Based on Mike Bostock's{' '} + Line Drawing +
+
+ + +
+ ); +} diff --git a/packages/vx-demo/src/components/tiles/Geo-Mercator.tsx b/packages/vx-demo/src/components/tiles/Geo-Mercator.tsx index 0f72dca880..68d5137f37 100644 --- a/packages/vx-demo/src/components/tiles/Geo-Mercator.tsx +++ b/packages/vx-demo/src/components/tiles/Geo-Mercator.tsx @@ -35,7 +35,6 @@ export default ({ width, height, events = false }: ShowProvidedProps) => { const centerX = width / 2; const centerY = height / 2; const scale = (width / 630) * 100; - console.warn({ width, height }); return ( diff --git a/packages/vx-demo/src/components/tiles/drag-i.js b/packages/vx-demo/src/components/tiles/drag-i.js deleted file mode 100644 index 0772b66ffc..0000000000 --- a/packages/vx-demo/src/components/tiles/drag-i.js +++ /dev/null @@ -1,146 +0,0 @@ -import React from 'react'; -import { scaleOrdinal } from '@vx/scale'; -import { LinearGradient } from '@vx/gradient'; -import { Drag, raise } from '@vx/drag'; - -const colors = [ - '#025aac', - '#02cff9', - '#02efff', - '#03aeed', - '#0384d7', - '#edfdff', - '#ab31ff', - '#5924d7', - '#d145ff', - '#1a02b1', - '#e582ff', - '#ff00d4', - '#270eff', - '#827ce2', -]; - -function genCircles({ num, width, height }) { - return new Array(num).fill(1).map((d, i) => { - const radius = 25 - Math.random() * 20; - return { - id: i, - radius, - x: Math.round(Math.random() * (width - radius * 2) + radius), - y: Math.round(Math.random() * (height - radius * 2) + radius), - }; - }); -} - -const genItems = ({ width, height }) => - genCircles({ - num: width < 360 ? 40 : 185, - width, - height, - }); - -export default class DragI extends React.Component { - constructor(props) { - super(props); - this.state = { - items: genItems({ ...props }), - }; - this.colorScale = scaleOrdinal({ - range: colors, - domain: this.state.items.map(d => d.id), - }); - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillReceiveProps(nextProps) { - const { width } = nextProps; - if (width !== this.props.width) { - this.setState(() => { - return { - items: genItems({ ...nextProps }), - }; - }); - } - } - - render() { - const { width, height } = this.props; - if (width < 10) return null; - return ( -
- - - - {this.state.items.map((d, i) => ( - { - // svg follows the painter model - // so we need to move the data item - // to end of the array for it to be drawn - // "on top of" the other data items - this.setState(state => { - return { - items: raise(state.items, i), - }; - }); - }} - > - {({ dragStart, dragEnd, dragMove, isDragging, dx, dy }) => { - return ( - - ); - }} - - ))} - -
-
- Based on Mike Bostock's{' '} - - Circle Dragging II - -
-
- - -
- ); - } -} diff --git a/packages/vx-demo/src/components/tiles/drag-ii.js b/packages/vx-demo/src/components/tiles/drag-ii.js deleted file mode 100644 index c3b6a4cd22..0000000000 --- a/packages/vx-demo/src/components/tiles/drag-ii.js +++ /dev/null @@ -1,133 +0,0 @@ -import React from 'react'; -import { LinePath } from '@vx/shape'; -import { Drag } from '@vx/drag'; -import { curveBasis } from '@vx/curve'; -import { LinearGradient } from '@vx/gradient'; - -export default class DragII extends React.Component { - constructor(props) { - super(props); - this.state = { - data: props.data || [], - }; - } - - render() { - const { width, height } = this.props; - if (width < 10) return null; - return ( -
- - - - {this.state.data.map((datum, i) => { - return ( - d.x} - y={d => d.y} - /> - ); - })} - { - // add the new line with the starting point - this.setState(state => { - const newLine = [{ x, y }]; - return { - data: state.data.concat([newLine]), - }; - }); - }} - onDragMove={({ x, y, dx, dy }) => { - // add the new point to the current line - this.setState(state => { - const nextData = [...state.data]; - const point = [{ x: x + dx, y: y + dy }]; - const i = nextData.length - 1; - nextData[i] = nextData[i].concat(point); - return { data: nextData }; - }); - }} - > - {({ x, y, dx, dy, isDragging, dragStart, dragEnd, dragMove }) => { - return ( - - {/* decorate the currently drawing line */} - {isDragging && ( - - - - - )} - {/* create the drawing area */} - - - ); - }} - - -
-
- Based on Mike Bostock's{' '} - Line Drawing -
-
- - -
- ); - } -} diff --git a/packages/vx-demo/src/next.config.js b/packages/vx-demo/src/next.config.js new file mode 100644 index 0000000000..3fcd1554bc --- /dev/null +++ b/packages/vx-demo/src/next.config.js @@ -0,0 +1,7 @@ +// eslint-disable-next-line no-undef +module.exports = { + typescript: { + ignoreDevErrors: true, + ignoreBuildErrors: true, + }, +}; diff --git a/packages/vx-demo/src/pages/Drag-i.tsx b/packages/vx-demo/src/pages/Drag-i.tsx new file mode 100644 index 0000000000..9f477b2df8 --- /dev/null +++ b/packages/vx-demo/src/pages/Drag-i.tsx @@ -0,0 +1,142 @@ +import React from 'react'; +import Show from '../components/Show'; +import DragI from '../components/tiles/Drag-i'; + +export default () => { + return ( + + {`import React, { useMemo, useState } from 'react'; +import { scaleOrdinal } from '@vx/scale'; +import { LinearGradient } from '@vx/gradient'; +import { Drag, raise } from '@vx/drag'; +import { WidthAndHeight, ShowProvidedProps } from '../../types'; + +const colors = [ + '#025aac', + '#02cff9', + '#02efff', + '#03aeed', + '#0384d7', + '#edfdff', + '#ab31ff', + '#5924d7', + '#d145ff', + '#1a02b1', + '#e582ff', + '#ff00d4', + '#270eff', + '#827ce2', +]; + +const generateCircles = ({ num, width, height }: { num: number } & WidthAndHeight) => + new Array(num).fill(1).map((d, i) => { + const radius = 25 - Math.random() * 20; + return { + id: \`\${i}\`, + radius, + x: Math.round(Math.random() * (width - radius * 2) + radius), + y: Math.round(Math.random() * (height - radius * 2) + radius), + }; + }); + +const generateItems = ({ width, height }: WidthAndHeight) => + generateCircles({ + num: width < 360 ? 40 : 185, + width, + height, + }); + +export default function DragI({ width, height }: ShowProvidedProps) { + const memoizedItems = useMemo(() => generateItems({ width, height }), [width, height]); + const [draggingItems, setDraggingItems] = useState(memoizedItems); + + const colorScale = useMemo( + () => + scaleOrdinal({ + range: colors, + domain: draggingItems.map(d => d.id), + }), + // eslint-disable-next-line react-hooks/exhaustive-deps + [width, height], + ); + + if (width < 10) return null; + + return ( +
+ + + + + {draggingItems.map((d, i) => ( + { + // svg follows the painter model + // so we need to move the data item + // to end of the array for it to be drawn + // "on top of" the other data items + setDraggingItems(raise(draggingItems, i)); + }} + > + {({ dragStart, dragEnd, dragMove, isDragging, dx, dy }) => + (false && isDragging && console.log(d.id, d.x, dx)) || ( + + ) + } + + ))} + +
+
+ Based on Mike Bostock's{' '} + + Circle Dragging II + +
+
+ + +
+ ); +} +`} +
+ ); +}; diff --git a/packages/vx-demo/src/pages/Drag-ii.tsx b/packages/vx-demo/src/pages/Drag-ii.tsx new file mode 100644 index 0000000000..833146df79 --- /dev/null +++ b/packages/vx-demo/src/pages/Drag-ii.tsx @@ -0,0 +1,136 @@ +import React from 'react'; +import Show from '../components/Show'; +import DragII from '../components/tiles/Drag-ii'; + +export default () => { + return ( + + {`import React, { useState } from 'react'; +import { LinePath } from '@vx/shape'; +import { Drag } from '@vx/drag'; +import { curveBasis } from '@vx/curve'; +import { LinearGradient } from '@vx/gradient'; +import { ShowProvidedProps } from '../../types'; + +type Lines = { x: number; y: number }[][]; + +export default function DragII({ width, height }: ShowProvidedProps) { + const [lines, setLines] = useState([]); + + if (width < 10) return null; + return ( +
+ + + + {lines.map((line, i) => ( + d.x} + y={d => d.y} + /> + ))} + { + // add the new line with the starting point + setLines(currLines => [...currLines, [{ x, y }]]); + }} + onDragMove={({ x = 0, y = 0, dx, dy }) => { + // add the new point to the current line + setLines(currLines => { + const nextLines = [...currLines]; + const newPoint = { x: x + dx, y: y + dy }; + const lastIndex = nextLines.length - 1; + nextLines[lastIndex] = [...(nextLines[lastIndex] || []), newPoint]; + return nextLines; + }); + }} + > + {({ x = 0, y = 0, dx, dy, isDragging, dragStart, dragEnd, dragMove }) => ( + + {/* decorate the currently drawing line */} + {isDragging && ( + + + + + )} + {/* create the drawing area */} + + + )} + + +
+
+ Based on Mike Bostock's{' '} + Line Drawing +
+
+ + +
+ ); +} + +`} +
+ ); +}; diff --git a/packages/vx-demo/src/pages/drag-i.js b/packages/vx-demo/src/pages/drag-i.js deleted file mode 100644 index 73fa3f20e4..0000000000 --- a/packages/vx-demo/src/pages/drag-i.js +++ /dev/null @@ -1,145 +0,0 @@ -import React from 'react'; -import Show from '../components/Show.tsx'; -import DragI from '../components/tiles/drag-i'; - -export default () => { - return ( - - {`import React from 'react'; -import { scaleOrdinal } from '@vx/scale'; -import { LinearGradient } from '@vx/gradient'; -import { Drag, raise } from '@vx/drag'; - -const colors = [ - '#025aac', - '#02cff9', - '#02efff', - '#03aeed', - '#0384d7', - '#edfdff', - '#ab31ff', - '#5924d7', - '#d145ff', - '#1a02b1', - '#e582ff', - '#ff00d4', - '#270eff', - '#827ce2', -]; - -function genCircles({ num, width, height }) { - return Array(num) - .fill(1) - .map((d, i) => { - const radius = 25 - Math.random() * 20; - return { - id: i, - radius, - x: Math.round(Math.random() * (width - radius * 2) + radius), - y: Math.round(Math.random() * (height - radius * 2) + radius), - }; - }); -} - -const genItems = ({ width, height }) => - genCircles({ - num: width < 360 ? 40 : 185, - width, - height, - }); - -export default class DragI extends React.Component { - constructor(props) { - super(props); - this.state = { - items: genItems({ ...props }), - }; - this.colorScale = scaleOrdinal({ - range: colors, - domain: this.state.items.map(d => d.id), - }); - } - - UNSAFE_componentWillReceiveProps(nextProps) { - const { width, height } = nextProps; - if (width !== this.props.width) { - this.setState(() => { - return { - items: genItems({ ...nextProps }), - }; - }); - } - } - - render() { - const { width, height } = this.props; - return ( -
- - - - {this.state.items.map((d, i) => ( - { - // svg follows the painter model - // so we need to move the data item - // to end of the array for it to be drawn - // "on top of" the other data items - this.setState((state, props) => { - return { - items: raise(state.items, i), - }; - }); - }} - > - {({ - dragStart, - dragEnd, - dragMove, - isDragging, - dx, - dy, - }) => { - return ( - - ); - }} - - ))} - -
- ); - } -} -`} -
- ); -}; diff --git a/packages/vx-demo/src/pages/drag-ii.js b/packages/vx-demo/src/pages/drag-ii.js deleted file mode 100644 index 0c08b801d6..0000000000 --- a/packages/vx-demo/src/pages/drag-ii.js +++ /dev/null @@ -1,129 +0,0 @@ -import React from 'react'; -import Show from '../components/Show.tsx'; -import DragII from '../components/tiles/drag-ii'; - -export default () => { - return ( - - {`import React from 'react'; -import { LinePath } from '@vx/shape'; -import { Drag } from '@vx/drag'; -import { curveBasis } from '@vx/curve'; -import { LinearGradient } from '@vx/gradient'; - -export default class DragII extends React.Component { - constructor(props) { - super(props); - this.state = { - data: props.data || [], - }; - } - - render() { - const { width, height } = this.props; - return ( -
- - - - {this.state.data.map((d, i) => { - return ( - d.x} - y={d => d.y} - /> - ); - })} - { - // add the new line with the starting point - this.setState((state, props) => { - const newLine = [{ x, y }]; - return { - data: state.data.concat([newLine]), - }; - }); - }} - onDragMove={({ x, y, dx, dy }) => { - // add the new point to the current line - this.setState((state, props) => { - const nextData = [...state.data]; - const point = [{ x: x + dx, y: y + dy }]; - const i = nextData.length - 1; - nextData[i] = nextData[i].concat(point); - return { data: nextData }; - }); - }} - > - {({ - x, - y, - dx, - dy, - isDragging, - dragStart, - dragEnd, - dragMove, - }) => { - return ( - - {/* decorate the currently drawing line */} - {isDragging && ( - - - - - )} - {/* create the drawing area */} - - - ); - }} - - -
- ); - } -} -`} -
- ); -}; diff --git a/packages/vx-demo/src/types/index.ts b/packages/vx-demo/src/types/index.ts index e2e85e43bb..b6710a3e5a 100644 --- a/packages/vx-demo/src/types/index.ts +++ b/packages/vx-demo/src/types/index.ts @@ -5,6 +5,11 @@ export interface MarginShape { left: number; } +export interface WidthAndHeight { + width: number; + height: number; +} + export type ShowProvidedProps = { width: number; height: number; diff --git a/packages/vx-drag/src/Drag.tsx b/packages/vx-drag/src/Drag.tsx index b18abee099..acc05edea6 100644 --- a/packages/vx-drag/src/Drag.tsx +++ b/packages/vx-drag/src/Drag.tsx @@ -63,8 +63,8 @@ export default class Drag extends React.Component { isDragging: true, dx: resetOnStart ? 0 : dx, dy: resetOnStart ? 0 : dy, - x: resetOnStart ? point.x : -dx + point.x, - y: resetOnStart ? point.y : -dy + point.y, + x: resetOnStart ? point.x : point.x - dx, + y: resetOnStart ? point.y : point.y - dy, }; }, onDragStart && @@ -84,8 +84,8 @@ export default class Drag extends React.Component { return isDragging ? { isDragging: true, - dx: -((x || 0) - point.x), - dy: -((y || 0) - point.y), + dx: point.x - (x || 0), + dy: point.y - (y || 0), } : null; }, diff --git a/packages/vx-event/src/localPoint.ts b/packages/vx-event/src/localPoint.ts index 3f497e1081..f9fa7cbce9 100644 --- a/packages/vx-event/src/localPoint.ts +++ b/packages/vx-event/src/localPoint.ts @@ -2,13 +2,17 @@ import localPointGeneric from './localPointGeneric'; import { EventType } from './types'; import { isElement, isEvent } from './typeGuards'; +/** Handles two signatures for backwards compatibility. */ export default function localPoint(nodeOrEvent: Element | EventType, maybeEvent?: EventType) { + // localPoint(node, event) if (isElement(nodeOrEvent) && maybeEvent) { return localPointGeneric(nodeOrEvent, maybeEvent); } + // localPoint(event) if (isEvent(nodeOrEvent)) { - const node = nodeOrEvent.target as Element; - if (node) return localPointGeneric(node, nodeOrEvent); + const event = nodeOrEvent; + const node = event.target as Element; + if (node) return localPointGeneric(node, event); } return null; } diff --git a/packages/vx-event/src/localPointGeneric.ts b/packages/vx-event/src/localPointGeneric.ts index 4138627c3d..1a1ccb343f 100644 --- a/packages/vx-event/src/localPointGeneric.ts +++ b/packages/vx-event/src/localPointGeneric.ts @@ -10,7 +10,7 @@ export default function localPoint(node: Element, event: EventType) { // find top-most SVG const svg = isSVGElement(node) ? node.ownerSVGElement : node; - const screenCTM = isSVGGraphicsElement(node) ? node.getScreenCTM() : null; + const screenCTM = isSVGGraphicsElement(svg) ? svg.getScreenCTM() : null; if (isSVGSVGElement(svg) && screenCTM) { let point = svg.createSVGPoint();