You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rectangle.tsx 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { v4 as uuid } from "uuid"
  2. import * as vec from "utils/vec"
  3. import { RectangleShape, ShapeType } from "types"
  4. import { createShape } from "./index"
  5. import { boundsCollidePolygon, boundsContainPolygon } from "utils/bounds"
  6. import { getBoundsFromPoints, rotateBounds, translateBounds } from "utils/utils"
  7. const rectangle = createShape<RectangleShape>({
  8. boundsCache: new WeakMap([]),
  9. create(props) {
  10. return {
  11. id: uuid(),
  12. type: ShapeType.Rectangle,
  13. isGenerated: false,
  14. name: "Rectangle",
  15. parentId: "page0",
  16. childIndex: 0,
  17. point: [0, 0],
  18. size: [1, 1],
  19. rotation: 0,
  20. style: {
  21. fill: "rgba(142, 143, 142, 1.000)",
  22. stroke: "#000",
  23. },
  24. ...props,
  25. }
  26. },
  27. render({ id, size }) {
  28. return <rect id={id} width={size[0]} height={size[1]} />
  29. },
  30. getBounds(shape) {
  31. if (!this.boundsCache.has(shape)) {
  32. const [width, height] = shape.size
  33. const bounds = {
  34. minX: 0,
  35. maxX: width,
  36. minY: 0,
  37. maxY: height,
  38. width,
  39. height,
  40. }
  41. this.boundsCache.set(shape, bounds)
  42. }
  43. return translateBounds(this.boundsCache.get(shape), shape.point)
  44. },
  45. getRotatedBounds(shape) {
  46. const b = this.getBounds(shape)
  47. const center = [b.minX + b.width / 2, b.minY + b.height / 2]
  48. // Rotate corners of the shape, then find the minimum among those points.
  49. const rotatedCorners = [
  50. [b.minX, b.minY],
  51. [b.maxX, b.minY],
  52. [b.maxX, b.maxY],
  53. [b.minX, b.maxY],
  54. ].map((point) => vec.rotWith(point, center, shape.rotation))
  55. return getBoundsFromPoints(rotatedCorners)
  56. },
  57. getCenter(shape) {
  58. const bounds = this.getRotatedBounds(shape)
  59. return [bounds.minX + bounds.width / 2, bounds.minY + bounds.height / 2]
  60. },
  61. hitTest(shape) {
  62. return true
  63. },
  64. hitTestBounds(shape, brushBounds) {
  65. const b = this.getBounds(shape)
  66. const center = [b.minX + b.width / 2, b.minY + b.height / 2]
  67. const rotatedCorners = [
  68. [b.minX, b.minY],
  69. [b.maxX, b.minY],
  70. [b.maxX, b.maxY],
  71. [b.minX, b.maxY],
  72. ].map((point) => vec.rotWith(point, center, shape.rotation))
  73. return (
  74. boundsContainPolygon(brushBounds, rotatedCorners) ||
  75. boundsCollidePolygon(brushBounds, rotatedCorners)
  76. )
  77. },
  78. rotate(shape) {
  79. return shape
  80. },
  81. translate(shape, delta) {
  82. shape.point = vec.add(shape.point, delta)
  83. return shape
  84. },
  85. scale(shape, scale) {
  86. return shape
  87. },
  88. transform(shape, bounds) {
  89. shape.point = [bounds.minX, bounds.minY]
  90. shape.size = [bounds.width, bounds.height]
  91. return shape
  92. },
  93. canTransform: true,
  94. })
  95. export default rectangle