mirror of
https://github.com/n8n-io/n8n.git
synced 2025-02-21 02:56:40 -08:00
⚡ Improve zooming (#1903)
* implement import
* set name, remove console log
* add validation and such
* remove monday.com package for testing
* clean up code
* await new name
* refactor api requests
* remove unnessary import
* build
* add zoom button
* update positions on loading template
* update error handling
* build
* update zoom to center
* set state to dirty upon leaving
* clean up pr
* refactor func
* refactor redir
* fix lint issue
* refactor func out
* use new endpoint
* revert error changes
* revert error changes
* update logic to find top left node
* zoom to fit when opening workflow
* revert testing change
* update zoom buttons to focus on origin
* update zoom shortcut
* update shortcuts
* update case
* remove debounce
* add secondary mappings
* fix reset
* add semicolon
* split func
* address comments
* refactor out
* refactor out
* reset zoom when opening new workflow
* move interface to common file
* remove duplicate
* fix import sort
* clean up pr
* clean up pr
* ⚡ Ignore keyboard shortcuts in select fields
Co-authored-by: Jan Oberhauser <jan.oberhauser@gmail.com>
This commit is contained in:
parent
427f25d3d0
commit
69a013d719
|
@ -611,3 +611,8 @@ export interface IRestApiContext {
|
|||
baseUrl: string;
|
||||
sessionId: string;
|
||||
}
|
||||
|
||||
export interface IZoomConfig {
|
||||
scale: number;
|
||||
offset: XYPositon;
|
||||
}
|
||||
|
|
|
@ -42,15 +42,15 @@
|
|||
<button @click="zoomToFit" class="button-white" title="Zoom to Fit">
|
||||
<font-awesome-icon icon="expand"/>
|
||||
</button>
|
||||
<button @click="setZoom('in')" class="button-white" title="Zoom In">
|
||||
<button @click="zoomIn()" class="button-white" title="Zoom In">
|
||||
<font-awesome-icon icon="search-plus"/>
|
||||
</button>
|
||||
<button @click="setZoom('out')" class="button-white" title="Zoom Out">
|
||||
<button @click="zoomOut()" class="button-white" title="Zoom Out">
|
||||
<font-awesome-icon icon="search-minus"/>
|
||||
</button>
|
||||
<button
|
||||
v-if="nodeViewScale !== 1"
|
||||
@click="setZoom('reset')"
|
||||
@click="resetZoom()"
|
||||
class="button-white"
|
||||
title="Reset Zoom"
|
||||
>
|
||||
|
@ -136,7 +136,7 @@ import NodeCreator from '@/components/NodeCreator/NodeCreator.vue';
|
|||
import NodeSettings from '@/components/NodeSettings.vue';
|
||||
import RunData from '@/components/RunData.vue';
|
||||
|
||||
import { getLeftmostTopNode, getWorkflowCorners } from './helpers';
|
||||
import { getLeftmostTopNode, getWorkflowCorners, scaleSmaller, scaleBigger, scaleReset } from './helpers';
|
||||
|
||||
import mixins from 'vue-typed-mixins';
|
||||
import { v4 as uuidv4} from 'uuid';
|
||||
|
@ -486,9 +486,9 @@ export default mixins(
|
|||
//* Control + scroll zoom
|
||||
if (e.ctrlKey) {
|
||||
if (e.deltaY > 0) {
|
||||
this.setZoom('out');
|
||||
this.zoomOut();
|
||||
} else {
|
||||
this.setZoom('in');
|
||||
this.zoomIn();
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
|
@ -509,7 +509,9 @@ export default mixins(
|
|||
// else which should ignore the default keybindings
|
||||
for (let index = 0; index < path.length; index++) {
|
||||
if (path[index].className && typeof path[index].className === 'string' && (
|
||||
path[index].className.includes('el-message-box') || path[index].className.includes('ignore-key-press')
|
||||
path[index].className.includes('el-message-box') ||
|
||||
path[index].className.includes('el-select') ||
|
||||
path[index].className.includes('ignore-key-press')
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
@ -539,12 +541,14 @@ export default mixins(
|
|||
if (lastSelectedNode !== null) {
|
||||
this.callDebounced('renameNodePrompt', 1500, lastSelectedNode.name);
|
||||
}
|
||||
} else if (e.key === '+') {
|
||||
this.callDebounced('setZoom', 300, 'in');
|
||||
} else if (e.key === '-') {
|
||||
this.callDebounced('setZoom', 300, 'out');
|
||||
} else if ((e.key === '0') && (this.isCtrlKeyPressed(e) === true)) {
|
||||
this.callDebounced('setZoom', 300, 'reset');
|
||||
} else if ((e.key === '=' || e.key === '+') && !this.isCtrlKeyPressed(e)) {
|
||||
this.zoomIn();
|
||||
} else if ((e.key === '_' || e.key === '-') && !this.isCtrlKeyPressed(e)) {
|
||||
this.zoomOut();
|
||||
} else if ((e.key === '0') && !this.isCtrlKeyPressed(e)) {
|
||||
this.resetZoom();
|
||||
} else if ((e.key === '1') && !this.isCtrlKeyPressed(e)) {
|
||||
this.zoomToFit();
|
||||
} else if ((e.key === 'a') && (this.isCtrlKeyPressed(e) === true)) {
|
||||
// Select all nodes
|
||||
e.stopPropagation();
|
||||
|
@ -778,16 +782,25 @@ export default mixins(
|
|||
});
|
||||
},
|
||||
|
||||
setZoom (zoom: string) {
|
||||
let scale = this.nodeViewScale;
|
||||
if (zoom === 'in') {
|
||||
scale *= 1.25;
|
||||
} else if (zoom === 'out') {
|
||||
scale /= 1.25;
|
||||
} else {
|
||||
scale = 1;
|
||||
}
|
||||
resetZoom () {
|
||||
const { scale, offset } = scaleReset({scale: this.nodeViewScale, offset: this.$store.getters.getNodeViewOffsetPosition});
|
||||
|
||||
this.setZoomLevel(scale);
|
||||
this.$store.commit('setNodeViewOffsetPosition', {newOffset: offset});
|
||||
},
|
||||
|
||||
zoomIn() {
|
||||
const { scale, offset: [xOffset, yOffset] } = scaleBigger({scale: this.nodeViewScale, offset: this.$store.getters.getNodeViewOffsetPosition});
|
||||
|
||||
this.setZoomLevel(scale);
|
||||
this.$store.commit('setNodeViewOffsetPosition', {newOffset: [xOffset, yOffset]});
|
||||
},
|
||||
|
||||
zoomOut() {
|
||||
const { scale, offset: [xOffset, yOffset] } = scaleSmaller({scale: this.nodeViewScale, offset: this.$store.getters.getNodeViewOffsetPosition});
|
||||
|
||||
this.setZoomLevel(scale);
|
||||
this.$store.commit('setNodeViewOffsetPosition', {newOffset: [xOffset, yOffset]});
|
||||
},
|
||||
|
||||
setZoomLevel (zoomLevel: number) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { INodeUi } from "@/Interface";
|
||||
import { INodeUi, IZoomConfig } from "@/Interface";
|
||||
|
||||
interface ICorners {
|
||||
minX: number;
|
||||
|
@ -40,3 +40,46 @@ export const getWorkflowCorners = (nodes: INodeUi[]): ICorners => {
|
|||
maxY: nodes[0].position[1],
|
||||
});
|
||||
};
|
||||
|
||||
export const scaleSmaller = ({scale, offset: [xOffset, yOffset]}: IZoomConfig): IZoomConfig => {
|
||||
scale /= 1.25;
|
||||
xOffset /= 1.25;
|
||||
yOffset /= 1.25;
|
||||
xOffset += window.innerWidth / 10;
|
||||
yOffset += window.innerHeight / 10;
|
||||
|
||||
return {
|
||||
scale,
|
||||
offset: [xOffset, yOffset],
|
||||
};
|
||||
};
|
||||
|
||||
export const scaleBigger = ({scale, offset: [xOffset, yOffset]}: IZoomConfig): IZoomConfig => {
|
||||
scale *= 1.25;
|
||||
xOffset -= window.innerWidth / 10;
|
||||
yOffset -= window.innerHeight / 10;
|
||||
xOffset *= 1.25;
|
||||
yOffset *= 1.25;
|
||||
|
||||
return {
|
||||
scale,
|
||||
offset: [xOffset, yOffset],
|
||||
};
|
||||
};
|
||||
|
||||
export const scaleReset = (config: IZoomConfig): IZoomConfig => {
|
||||
if (config.scale > 1) { // zoomed in
|
||||
while (config.scale > 1) {
|
||||
config = scaleSmaller(config);
|
||||
}
|
||||
}
|
||||
else {
|
||||
while (config.scale < 1) {
|
||||
config = scaleBigger(config);
|
||||
}
|
||||
}
|
||||
|
||||
config.scale = 1;
|
||||
|
||||
return config;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue