選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

index.tsx 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {
  2. Bounds,
  3. BoundsSnapshot,
  4. Shape,
  5. Shapes,
  6. ShapeType,
  7. TransformCorner,
  8. TransformEdge,
  9. } from "types"
  10. import circle from "./circle"
  11. import dot from "./dot"
  12. import polyline from "./polyline"
  13. import rectangle from "./rectangle"
  14. import ellipse from "./ellipse"
  15. import line from "./line"
  16. import ray from "./ray"
  17. /*
  18. Shape Utiliies
  19. A shape utility is an object containing utility methods for each type of shape
  20. in the application. While shapes may be very different, each shape must support
  21. a common set of utility methods, such as hit tests or translations, that
  22. Operations throughout the app will call these utility methods
  23. when performing tests (such as hit tests) or mutations, such as translations.
  24. */
  25. export interface ShapeUtility<K extends Shape> {
  26. // A cache for the computed bounds of this kind of shape.
  27. boundsCache: WeakMap<K, Bounds>
  28. // Create a new shape.
  29. create(props: Partial<K>): K
  30. // Get the bounds of the a shape.
  31. getBounds(this: ShapeUtility<K>, shape: K): Bounds
  32. // Get the routated bounds of the a shape.
  33. getRotatedBounds(this: ShapeUtility<K>, shape: K): Bounds
  34. // Get the center of the shape
  35. getCenter(this: ShapeUtility<K>, shape: K): number[]
  36. // Test whether a point lies within a shape.
  37. hitTest(this: ShapeUtility<K>, shape: K, test: number[]): boolean
  38. // Test whether bounds collide with or contain a shape.
  39. hitTestBounds(this: ShapeUtility<K>, shape: K, bounds: Bounds): boolean
  40. // Apply a rotation to a shape.
  41. rotate(this: ShapeUtility<K>, shape: K): K
  42. // Apply a translation to a shape.
  43. translate(this: ShapeUtility<K>, shape: K, delta: number[]): K
  44. // Transform to fit a new bounding box.
  45. transform(
  46. this: ShapeUtility<K>,
  47. shape: K,
  48. bounds: Bounds,
  49. info: {
  50. type: TransformEdge | TransformCorner
  51. boundsRotation: number
  52. initialShape: K
  53. initialShapeBounds: BoundsSnapshot
  54. initialBounds: Bounds
  55. isFlippedX: boolean
  56. isFlippedY: boolean
  57. isSingle: boolean
  58. anchor: TransformEdge | TransformCorner
  59. }
  60. ): K
  61. // Apply a scale to a shape.
  62. scale(this: ShapeUtility<K>, shape: K, scale: number): K
  63. // Render a shape to JSX.
  64. render(this: ShapeUtility<K>, shape: K): JSX.Element
  65. // Whether to show transform controls when this shape is selected.
  66. canTransform: boolean
  67. }
  68. // A mapping of shape types to shape utilities.
  69. const shapeUtilityMap: { [key in ShapeType]: ShapeUtility<Shapes[key]> } = {
  70. [ShapeType.Circle]: circle,
  71. [ShapeType.Dot]: dot,
  72. [ShapeType.Polyline]: polyline,
  73. [ShapeType.Rectangle]: rectangle,
  74. [ShapeType.Ellipse]: ellipse,
  75. [ShapeType.Line]: line,
  76. [ShapeType.Ray]: ray,
  77. }
  78. /**
  79. * A helper to retrieve a shape utility based on a shape object.
  80. * @param shape
  81. * @returns
  82. */
  83. export function getShapeUtils(shape: Shape): ShapeUtility<typeof shape> {
  84. return shapeUtilityMap[shape.type]
  85. }
  86. /**
  87. * A factory of shape utilities, with typing enforced.
  88. * @param shape
  89. * @returns
  90. */
  91. export function createShape<T extends Shape>(
  92. shape: ShapeUtility<T>
  93. ): ShapeUtility<T> {
  94. return Object.freeze(shape)
  95. }
  96. export default shapeUtilityMap