Add button when scrolled outside of visible area (#643)
With the infinite scroll behavior, it's easy to scroll super far away from where the content is and have a hard time getting back. This PR adds a button to refocus on the center of the scene when no elements are visible anymore.
This commit is contained in:
parent
7c9e6dd3f1
commit
be97bd980e
@ -24,6 +24,7 @@ export function getDefaultAppState(): AppState {
|
||||
scrollY: 0,
|
||||
cursorX: 0,
|
||||
cursorY: 0,
|
||||
scrolledOutside: false,
|
||||
name: DEFAULT_PROJECT_NAME,
|
||||
};
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import {
|
||||
importFromBackend,
|
||||
addToLoadedScenes,
|
||||
loadedScenes,
|
||||
calculateScrollCenter,
|
||||
} from "./scene";
|
||||
|
||||
import { renderScene } from "./renderer";
|
||||
@ -1764,6 +1765,16 @@ export class App extends React.Component<any, AppState> {
|
||||
currentLanguage={getLanguage()}
|
||||
/>
|
||||
{this.renderIdsDropdown()}
|
||||
{this.state.scrolledOutside && (
|
||||
<button
|
||||
className="scroll-back-to-content"
|
||||
onClick={() => {
|
||||
this.setState({ ...calculateScrollCenter(elements) });
|
||||
}}
|
||||
>
|
||||
{t("buttons.scrollBackToContent")}
|
||||
</button>
|
||||
)}
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
@ -1872,11 +1883,20 @@ export class App extends React.Component<any, AppState> {
|
||||
}, 300);
|
||||
|
||||
componentDidUpdate() {
|
||||
renderScene(elements, this.rc!, this.canvas!, {
|
||||
const atLeastOneVisibleElement = renderScene(
|
||||
elements,
|
||||
this.rc!,
|
||||
this.canvas!,
|
||||
{
|
||||
scrollX: this.state.scrollX,
|
||||
scrollY: this.state.scrollY,
|
||||
viewBackgroundColor: this.state.viewBackgroundColor,
|
||||
});
|
||||
},
|
||||
);
|
||||
const scrolledOutside = !atLeastOneVisibleElement && elements.length > 0;
|
||||
if (this.state.scrolledOutside !== scrolledOutside) {
|
||||
this.setState({ scrolledOutside: scrolledOutside });
|
||||
}
|
||||
this.saveDebounced();
|
||||
if (history.isRecording()) {
|
||||
history.pushEntry(
|
||||
|
@ -52,7 +52,8 @@
|
||||
"getShareableLink": "Get shareable link",
|
||||
"close": "Close",
|
||||
"selectLanguage": "Select Language",
|
||||
"previouslyLoadedScenes": "Previously loaded scenes"
|
||||
"previouslyLoadedScenes": "Previously loaded scenes",
|
||||
"scrollBackToContent": "Scroll back to content"
|
||||
},
|
||||
"alerts": {
|
||||
"clearReset": "This will clear the whole canvas. Are you sure?",
|
||||
|
@ -32,7 +32,7 @@ export function renderScene(
|
||||
renderSelection?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
if (!canvas) return;
|
||||
if (!canvas) return false;
|
||||
const context = canvas.getContext("2d")!;
|
||||
|
||||
const fillStyle = context.fillStyle;
|
||||
@ -57,6 +57,7 @@ export function renderScene(
|
||||
scrollY: typeof offsetY === "number" ? offsetY : sceneState.scrollY,
|
||||
};
|
||||
|
||||
let atLeastOneVisibleElement = false;
|
||||
elements.forEach(element => {
|
||||
if (
|
||||
!isVisibleElement(
|
||||
@ -71,6 +72,7 @@ export function renderScene(
|
||||
) {
|
||||
return;
|
||||
}
|
||||
atLeastOneVisibleElement = true;
|
||||
context.translate(
|
||||
element.x + sceneState.scrollX,
|
||||
element.y + sceneState.scrollY,
|
||||
@ -141,6 +143,8 @@ export function renderScene(
|
||||
context.strokeStyle = strokeStyle;
|
||||
context.fillStyle = fillStyle;
|
||||
}
|
||||
|
||||
return atLeastOneVisibleElement;
|
||||
}
|
||||
|
||||
function isVisibleElement(
|
||||
|
@ -46,7 +46,7 @@ export function serializeAsJSON(
|
||||
);
|
||||
}
|
||||
|
||||
function calculateScrollCenter(
|
||||
export function calculateScrollCenter(
|
||||
elements: readonly ExcalidrawElement[],
|
||||
): { scrollX: number; scrollY: number } {
|
||||
let [x1, y1, x2, y2] = getCommonBounds(elements);
|
||||
|
@ -17,6 +17,7 @@ export {
|
||||
importFromBackend,
|
||||
addToLoadedScenes,
|
||||
loadedScenes,
|
||||
calculateScrollCenter,
|
||||
} from "./data";
|
||||
export {
|
||||
hasBackground,
|
||||
|
@ -256,3 +256,11 @@ button,
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
white-space: nowrap; /* added line */
|
||||
}
|
||||
|
||||
.scroll-back-to-content {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 20px;
|
||||
transform: translateX(-50%);
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ export type AppState = {
|
||||
scrollY: number;
|
||||
cursorX: number;
|
||||
cursorY: number;
|
||||
scrolledOutside: boolean;
|
||||
name: string;
|
||||
selectedId?: string;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user