Add onElementClick and export sceneCoordsToViewportCoords

This commit is contained in:
ad1992 2022-03-24 17:24:54 +05:30
parent 47498796e0
commit 5f4a5b1789
4 changed files with 71 additions and 9 deletions

View File

@ -3091,15 +3091,13 @@ class App extends React.Component<AppProps, AppState> {
event: React.PointerEvent<HTMLCanvasElement>,
) => {
this.lastPointerUp = event;
if (this.deviceType.isTouchScreen) {
let hitElement;
if (this.deviceType.isTouchScreen || this.props.onElementClick) {
const scenePointer = viewportCoordsToSceneCoords(
{ clientX: event.clientX, clientY: event.clientY },
this.state,
);
const hitElement = this.getElementAtPosition(
scenePointer.x,
scenePointer.y,
);
hitElement = this.getElementAtPosition(scenePointer.x, scenePointer.y);
this.hitLinkElement = this.getElementLinkAtPosition(
scenePointer,
hitElement,
@ -3112,6 +3110,23 @@ class App extends React.Component<AppProps, AppState> {
this.redirectToLink(event, this.deviceType.isTouchScreen);
}
if (
this.state.elementType === "selection" &&
this.props.onElementClick &&
hitElement
) {
const threshold = 5;
const isSinglePointClick =
distance2d(
this.lastPointerDown!.clientX,
this.lastPointerDown!.clientY,
this.lastPointerUp!.clientX,
this.lastPointerUp!.clientY,
) <= threshold;
if (isSinglePointClick) {
this.props.onElementClick(hitElement, event);
}
}
this.removePointer(event);
};
@ -4517,6 +4532,7 @@ class App extends React.Component<AppProps, AppState> {
// Code below handles selection when element(s) weren't
// drag or added to selection on pointer down phase.
const hitElement = pointerDownState.hit.element;
if (isEraserActive(this.state)) {
const draggedDistance = distance2d(
this.lastPointerDown!.clientX,
@ -4550,7 +4566,6 @@ class App extends React.Component<AppProps, AppState> {
} else if (Object.keys(pointerDownState.elementIdsToErase).length) {
this.restoreReadyToEraseElements(pointerDownState);
}
if (
hitElement &&
!pointerDownState.drag.hasOccurred &&

View File

@ -9,7 +9,12 @@ import { MIME_TYPES } from "../../../constants";
// This is so that we use the bundled excalidraw.development.js file instead
// of the actual source code
const { exportToCanvas, exportToSvg, exportToBlob } = window.Excalidraw;
const {
exportToCanvas,
exportToSvg,
exportToBlob,
sceneCoordsToViewportCoords,
} = window.Excalidraw;
const Excalidraw = window.Excalidraw.default;
const STAR_SVG = (
@ -56,7 +61,7 @@ const renderFooter = () => {
export default function App() {
const excalidrawRef = useRef(null);
const excalidrawWrapperRef = useRef(null);
const [viewModeEnabled, setViewModeEnabled] = useState(false);
const [zenModeEnabled, setZenModeEnabled] = useState(false);
const [gridModeEnabled, setGridModeEnabled] = useState(false);
@ -200,6 +205,39 @@ export default function App() {
},
];
};
const onElementClick = (element) => {
if (element.type === "custom" && element.customType === "comment") {
const { x: viewPortX, y: viewPortY } = sceneCoordsToViewportCoords(
{
sceneX: element.x,
sceneY: element.y,
},
excalidrawRef.current.getAppState(),
);
const textarea = document.createElement("textarea");
Object.assign(textarea.style, {
position: "absolute",
display: "inline-block",
left: `${viewPortX + element.width / 2}px`,
top: `${viewPortY + element.height / 2}px`,
height: `${100}px`,
width: `${100}px`,
zIndex: 10,
className: "comment-textarea",
whiteSpace: "pre-wrap",
fontSize: "13px",
});
textarea.placeholder = "Start typing your comments";
textarea.onblur = () => {
textarea.remove();
};
excalidrawWrapperRef.current
.querySelector(".excalidraw")
.append(textarea);
textarea.focus();
}
};
return (
<div className="App">
<h1> Excalidraw Example</h1>
@ -273,7 +311,7 @@ export default function App() {
Switch to Dark Theme
</label>
</div>
<div className="excalidraw-wrapper">
<div className="excalidraw-wrapper" ref={excalidrawWrapperRef}>
<Excalidraw
ref={excalidrawRef}
initialData={initialStatePromiseRef.current.promise}
@ -295,6 +333,7 @@ export default function App() {
onLinkOpen={onLinkOpen}
renderCustomElementWidget={renderCustomElementWidget}
customElementsConfig={getCustomElementsConfig()}
onElementClick={onElementClick}
/>
</div>

View File

@ -40,6 +40,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
generateIdForFile,
onLinkOpen,
renderCustomElementWidget,
onElementClick,
} = props;
const canvasActions = props.UIOptions?.canvasActions;
@ -109,6 +110,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
onLinkOpen={onLinkOpen}
renderCustomElementWidget={renderCustomElementWidget}
customElementsConfig={customElementsConfig}
onElementClick={onElementClick}
/>
</InitializeApp>
);
@ -207,3 +209,5 @@ export {
newElementWith,
bumpVersion,
} from "../../element/mutateElement";
export { sceneCoordsToViewportCoords } from "../../utils";

View File

@ -263,6 +263,10 @@ export interface ExcalidrawProps {
) => void;
renderCustomElementWidget?: (appState: AppState) => void;
customElementsConfig?: CustomElementConfig[];
onElementClick: (
element: NonDeleted<ExcalidrawElement>,
event: React.PointerEvent<HTMLCanvasElement>,
) => void;
}
export type SceneData = {