-
Notifications
You must be signed in to change notification settings - Fork 90
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c898450
commit 5251275
Showing
8 changed files
with
453 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
<template> | ||
<div ref="gridWrapper" class="grid-wrapper"> | ||
<grid-layout | ||
:layout="currentLayout" | ||
:col-num="columns" | ||
:cols="cols" | ||
:breakpoints="breakpoints" | ||
:row-height="rowHeight" | ||
:is-draggable="false" | ||
:is-resizable="false" | ||
:is-mirrored="false" | ||
:responsive="true" | ||
:vertical-compact="verticalCompact" | ||
:prevent-collision="true" | ||
:margin="[margin, margin]" | ||
:use-css-transforms="true" | ||
@layout-ready="onReady" | ||
> | ||
<grid-item | ||
v-for="item in currentLayout" | ||
:key="item.i" | ||
:x="item.x" | ||
:y="item.y" | ||
:w="item.w" | ||
:h="item.h" | ||
:i="item.i" | ||
class="grid-item" | ||
> | ||
<template v-if="ready"> | ||
<slot v-bind="widgets[item.i]" /> | ||
</template> | ||
</grid-item> | ||
</grid-layout> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts"> | ||
import debounce from 'lodash.debounce'; | ||
import { GridLayout, GridItem } from 'vue-grid-layout'; | ||
import { Component, Prop, Ref, Vue, Watch } from 'vue-property-decorator'; | ||
import { Breakpoint } from '@/consts'; | ||
import { compactItems } from './utils'; | ||
const DEFAULT_BREAKPOINT = 'lg'; | ||
const DEFAULT_BREAKPOINTS = { | ||
lg: Breakpoint.HugeDesktop, // 2092 | ||
md: Breakpoint.LargeDesktop, // 1440 | ||
sm: Breakpoint.Desktop, // 1024 | ||
xs: Breakpoint.LargeMobile, // 528 | ||
xss: 0, | ||
}; | ||
const DEFAULT_COLS = { | ||
lg: 12, | ||
md: 8, | ||
sm: 8, | ||
xs: 4, | ||
xss: 4, | ||
}; | ||
@Component({ | ||
components: { | ||
GridLayout, | ||
GridItem, | ||
}, | ||
}) | ||
export default class WidgetsGrid extends Vue { | ||
@Prop({ required: true, type: Array }) readonly widgets!: any; | ||
@Prop({ default: 12, type: Number }) readonly columns!: number; | ||
@Prop({ default: 100, type: Number }) readonly rowHeight!: number; | ||
@Prop({ default: 16, type: Number }) readonly margin!: number; | ||
@Prop({ default: true, type: Boolean }) readonly verticalCompact!: boolean; | ||
@Prop({ default: () => DEFAULT_COLS, type: Object }) readonly cols!: any; | ||
@Prop({ default: () => DEFAULT_BREAKPOINTS, type: Object }) readonly breakpoints!: any; | ||
@Ref('gridWrapper') readonly gridWrapper!: HTMLDivElement; | ||
// @Watch('breakpoint', { immediate: true }) | ||
// private calculateBreakpointLayout() { | ||
// const { gridLayouts, originalLayout, breakpoint, cols, verticalCompact } = this; | ||
// if (gridLayouts[breakpoint]) return; | ||
// const columnsCount = cols[breakpoint]; | ||
// const compactLayout = compactItems(originalLayout, columnsCount, verticalCompact); | ||
// gridLayouts[breakpoint] = compactLayout; | ||
// } | ||
ready = false; | ||
onReady = debounce(this.setReady); | ||
gridLayouts = {}; | ||
breakpoint = DEFAULT_BREAKPOINT; | ||
originalLayout = []; | ||
created() { | ||
this.originalLayout = this.widgets.map((widget, i) => ({ | ||
i, | ||
x: widget.spatialData.x, | ||
y: widget.spatialData.y, | ||
w: widget.spatialData.w, | ||
h: widget.spatialData.h, | ||
})); | ||
} | ||
mounted(): void { | ||
this.updateCurrentBreakpoint(); | ||
window.addEventListener('resize', this.updateCurrentBreakpoint); | ||
} | ||
beforeDestroy(): void { | ||
window.removeEventListener('resize', this.updateCurrentBreakpoint); | ||
} | ||
get currentLayout() { | ||
return this.gridLayouts[this.breakpoint] ?? this.originalLayout; | ||
} | ||
updateCurrentBreakpoint(): void { | ||
const { breakpoints, gridWrapper } = this; | ||
if (!gridWrapper) return; | ||
const { clientWidth } = gridWrapper; | ||
const currentBreakpoint = Object.keys(breakpoints).find((key) => clientWidth >= breakpoints[key]); | ||
this.breakpoint = currentBreakpoint ?? DEFAULT_BREAKPOINT; | ||
} | ||
setReady(): void { | ||
this.ready = true; | ||
this.$emit('init'); | ||
} | ||
} | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
// Implementation of new responsive grid | ||
// Function taken from: | ||
// vue-grid-layout/src/helpers/utils.js | ||
// vue-grid-layout/src/helpers/responsiveUtils.js | ||
|
||
// original | ||
const getFirstCollision = (layout, layoutItem) => { | ||
for (let i = 0, len = layout.length; i < len; i++) { | ||
if (collides(layout[i], layoutItem)) return layout[i]; | ||
} | ||
}; | ||
|
||
// original | ||
const getStatics = (layout) => { | ||
return layout.filter((l) => l.static); | ||
}; | ||
|
||
// changed | ||
const sortLayoutItemsByRowCol = (layout) => { | ||
return [].concat(layout).sort(function (a, b) { | ||
if (a.y > b.y || (a.y === b.y && a.x > b.x)) { | ||
return 1; | ||
} | ||
if (a.y === b.y && a.x === b.x) return 0; | ||
return -1; | ||
}); | ||
}; | ||
|
||
// original | ||
const collides = (l1, l2) => { | ||
if (l1 === l2) return false; // same element | ||
if (l1.x + l1.w <= l2.x) return false; // l1 is left of l2 | ||
if (l1.x >= l2.x + l2.w) return false; // l1 is right of l2 | ||
if (l1.y + l1.h <= l2.y) return false; // l1 is above l2 | ||
if (l1.y >= l2.y + l2.h) return false; // l1 is below l2 | ||
return true; // boxes overlap | ||
}; | ||
|
||
// changed | ||
const compactItem = (compareWith, l, verticalCompact, cols) => { | ||
let collide; | ||
while ((collide = getFirstCollision(compareWith, l))) { | ||
l.x = collide.x + collide.w; | ||
if (l.x + l.w > cols) { | ||
l.x = 0; | ||
l.y = collide.y + collide.h; | ||
} | ||
} | ||
|
||
if (verticalCompact) { | ||
do { | ||
l.y--; | ||
} while (l.y > 0 && !getFirstCollision(compareWith, l)); | ||
l.y++; | ||
} | ||
|
||
return l; | ||
}; | ||
|
||
// changed | ||
const correctBounds = (layout, cols) => { | ||
const collidesWith = getStatics(layout); | ||
for (let i = 0, len = layout.length; i < len; i++) { | ||
const l = layout[i]; | ||
if (l.x + l.w > cols) l.x = 0; | ||
if (l.w > cols) { | ||
l.w = cols; | ||
} | ||
|
||
let collide; | ||
while ((collide = getFirstCollision(collidesWith, l))) { | ||
l.x = collide.x + collide.w; | ||
if (l.x + l.w > cols) { | ||
l.x = 0; | ||
l.y = collide.y + collide.h; | ||
} | ||
} | ||
|
||
if (!l.static) collidesWith.push(l); | ||
} | ||
return layout; | ||
}; | ||
|
||
// changed | ||
const compact = (layout, cols, verticalCompact) => { | ||
const compareWith = getStatics(layout); | ||
const sorted = sortLayoutItemsByRowCol(layout); | ||
const out = Array(layout.length); | ||
|
||
for (let i = 0, len = sorted.length; i < len; i++) { | ||
let l = sorted[i]; | ||
|
||
if (!l.static) { | ||
l = compactItem(compareWith, l, verticalCompact, cols); | ||
|
||
compareWith.push(l); | ||
} | ||
|
||
out[layout.indexOf(l)] = l; | ||
|
||
l.moved = false; | ||
} | ||
|
||
return out; | ||
}; | ||
|
||
// original | ||
const cloneLayoutItem = (layoutItem) => { | ||
return JSON.parse(JSON.stringify(layoutItem)); | ||
}; | ||
|
||
// original | ||
const cloneLayout = (layout) => { | ||
const newLayout = Array(layout.length); | ||
for (let i = 0, len = layout.length; i < len; i++) { | ||
newLayout[i] = cloneLayoutItem(layout[i]); | ||
} | ||
return newLayout; | ||
}; | ||
|
||
// new | ||
export const compactItems = (layout, cols, verticalCompact) => { | ||
const clone = cloneLayout(layout); | ||
const correctedBounds = correctBounds(clone, cols); | ||
return compact(correctedBounds, cols, verticalCompact); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.