feat: 添加topology轮播类型

This commit is contained in:
zhangyu
2021-12-14 18:56:50 +08:00
parent f571f9d6c9
commit dccf99f3eb
11 changed files with 113 additions and 1676 deletions

View File

@@ -1,837 +0,0 @@
<template>
<div ref="item"
class="vue-grid-item"
:class="classObj"
:style="style"
>
<slot></slot>
<span v-if="resizableAndNotStatic" ref="handle" :class="resizableHandleClass"></span>
<!--<span v-if="draggable" ref="dragHandle" class="vue-draggable-handle"></span>-->
</div>
</template>
<style>
.vue-grid-item {
transition: all 200ms ease;
transition-property: left, top, right;
/* add right for rtl */
}
.vue-grid-item.no-touch {
-ms-touch-action: none;
touch-action: none;
}
.vue-grid-item.cssTransforms {
transition-property: transform;
left: 0;
right: auto;
}
.vue-grid-item.cssTransforms.render-rtl {
left: auto;
right: 0;
}
.vue-grid-item.resizing {
opacity: 0.6;
z-index: 3;
}
.vue-grid-item.vue-draggable-dragging {
transition:none;
z-index: 3;
}
.vue-grid-item.vue-grid-placeholder {
background: red;
opacity: 0.2;
transition-duration: 100ms;
z-index: 2;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
.vue-grid-item > .vue-resizable-handle {
position: absolute;
width: 20px;
height: 20px;
bottom: 0;
right: 0;
background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
background-position: bottom right;
padding: 0 3px 3px 0;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
cursor: se-resize;
}
.vue-grid-item > .vue-rtl-resizable-handle {
bottom: 0;
left: 0;
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAuMDAwMDAwMDAwMDAwMDAyIiBoZWlnaHQ9IjEwLjAwMDAwMDAwMDAwMDAwMiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KIDwhLS0gQ3JlYXRlZCB3aXRoIE1ldGhvZCBEcmF3IC0gaHR0cDovL2dpdGh1Yi5jb20vZHVvcGl4ZWwvTWV0aG9kLURyYXcvIC0tPgogPGc+CiAgPHRpdGxlPmJhY2tncm91bmQ8L3RpdGxlPgogIDxyZWN0IGZpbGw9Im5vbmUiIGlkPSJjYW52YXNfYmFja2dyb3VuZCIgaGVpZ2h0PSIxMiIgd2lkdGg9IjEyIiB5PSItMSIgeD0iLTEiLz4KICA8ZyBkaXNwbGF5PSJub25lIiBvdmVyZmxvdz0idmlzaWJsZSIgeT0iMCIgeD0iMCIgaGVpZ2h0PSIxMDAlIiB3aWR0aD0iMTAwJSIgaWQ9ImNhbnZhc0dyaWQiPgogICA8cmVjdCBmaWxsPSJ1cmwoI2dyaWRwYXR0ZXJuKSIgc3Ryb2tlLXdpZHRoPSIwIiB5PSIwIiB4PSIwIiBoZWlnaHQ9IjEwMCUiIHdpZHRoPSIxMDAlIi8+CiAgPC9nPgogPC9nPgogPGc+CiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPgogIDxsaW5lIGNhbnZhcz0iI2ZmZmZmZiIgY2FudmFzLW9wYWNpdHk9IjEiIHN0cm9rZS1saW5lY2FwPSJ1bmRlZmluZWQiIHN0cm9rZS1saW5lam9pbj0idW5kZWZpbmVkIiBpZD0ic3ZnXzEiIHkyPSItNzAuMTc4NDA3IiB4Mj0iMTI0LjQ2NDE3NSIgeTE9Ii0zOC4zOTI3MzciIHgxPSIxNDQuODIxMjg5IiBzdHJva2Utd2lkdGg9IjEuNSIgc3Ryb2tlPSIjMDAwIiBmaWxsPSJub25lIi8+CiAgPGxpbmUgc3Ryb2tlPSIjNjY2NjY2IiBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z181IiB5Mj0iOS4xMDY5NTciIHgyPSIwLjk0NzI0NyIgeTE9Ii0wLjAxODEyOCIgeDE9IjAuOTQ3MjQ3IiBzdHJva2Utd2lkdGg9IjIiIGZpbGw9Im5vbmUiLz4KICA8bGluZSBzdHJva2UtbGluZWNhcD0idW5kZWZpbmVkIiBzdHJva2UtbGluZWpvaW49InVuZGVmaW5lZCIgaWQ9InN2Z183IiB5Mj0iOSIgeDI9IjEwLjA3MzUyOSIgeTE9IjkiIHgxPSItMC42NTU2NCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM2NjY2NjYiIGZpbGw9Im5vbmUiLz4KIDwvZz4KPC9zdmc+);
background-position: bottom left;
padding-left: 3px;
background-repeat: no-repeat;
background-origin: content-box;
cursor: sw-resize;
right: auto;
}
.vue-grid-item.disable-userselect {
user-select: none;
}
</style>
<script>
import { setTopLeft, setTopRight, setTransformRtl, setTransform } from './gridItemUtils'
import { getControlPosition, createCoreData } from 'vue-grid-layout/src/helpers/draggableUtils'
import { getDocumentDir } from './gridItemDOM'
// var eventBus = require('./eventBus');
const interact = require('interactjs')
export default {
name: 'GridItem',
props: {
/* cols: {
type: Number,
required: true
}, */
/* containerWidth: {
type: Number,
required: true
},
rowHeight: {
type: Number,
required: true
},
margin: {
type: Array,
required: true
},
maxRows: {
type: Number,
required: true
}, */
isDraggable: {
type: Boolean,
required: false,
default: null
},
isResizable: {
type: Boolean,
required: false,
default: null
},
/* useCssTransforms: {
type: Boolean,
required: true
},
*/
static: {
type: Boolean,
required: false,
default: false
},
minH: {
type: Number,
required: false,
default: 1
},
minW: {
type: Number,
required: false,
default: 1
},
maxH: {
type: Number,
required: false,
default: Infinity
},
maxW: {
type: Number,
required: false,
default: Infinity
},
x: {
type: Number,
required: true
},
y: {
type: Number,
required: true
},
w: {
type: Number,
required: true
},
h: {
type: Number,
required: true
},
i: {
required: true
},
dragIgnoreFrom: {
type: String,
required: false,
default: 'a, button'
},
dragAllowFrom: {
type: String,
required: false,
default: null
},
resizeIgnoreFrom: {
type: String,
required: false,
default: 'a, button'
}
},
inject: ['eventBus'],
data: function () {
return {
cols: 1,
containerWidth: 100,
rowHeight: 30,
margin: [10, 10],
maxRows: Infinity,
draggable: null,
resizable: null,
useCssTransforms: true,
isDragging: false,
dragging: null,
isResizing: false,
resizing: null,
lastX: NaN,
lastY: NaN,
lastW: NaN,
lastH: NaN,
style: {},
rtl: false,
dragEventSet: false,
resizeEventSet: false,
previousW: null,
previousH: null,
previousX: null,
previousY: null,
innerX: this.x,
innerY: this.y,
innerW: this.w,
innerH: this.h
}
},
created () {
const self = this
// Accessible refernces of functions for removing in beforeDestroy
self.updateWidthHandler = function (width) {
self.updateWidth(width)
}
self.compactHandler = function (layout) {
self.compact(layout)
}
self.setDraggableHandler = function (isDraggable) {
if (self.isDraggable === null) {
self.draggable = isDraggable
}
}
self.setResizableHandler = function (isResizable) {
if (self.isResizable === null) {
self.resizable = isResizable
}
}
self.setRowHeightHandler = function (rowHeight) {
self.rowHeight = rowHeight
}
self.setMaxRowsHandler = function (maxRows) {
self.maxRows = maxRows
}
self.directionchangeHandler = () => {
this.rtl = getDocumentDir() === 'rtl'
this.compact()
}
self.setColNum = (colNum) => {
self.cols = parseInt(colNum)
}
this.eventBus.$on('updateWidth', self.updateWidthHandler)
this.eventBus.$on('compact', self.compactHandler)
this.eventBus.$on('setDraggable', self.setDraggableHandler)
this.eventBus.$on('setResizable', self.setResizableHandler)
this.eventBus.$on('setRowHeight', self.setRowHeightHandler)
this.eventBus.$on('setMaxRows', self.setMaxRowsHandler)
this.eventBus.$on('directionchange', self.directionchangeHandler)
this.eventBus.$on('setColNum', self.setColNum)
this.rtl = getDocumentDir() === 'rtl'
},
beforeDestroy: function () {
const self = this
// Remove listeners
this.eventBus.$off('updateWidth', self.updateWidthHandler)
this.eventBus.$off('compact', self.compactHandler)
this.eventBus.$off('setDraggable', self.setDraggableHandler)
this.eventBus.$off('setResizable', self.setResizableHandler)
this.eventBus.$off('setRowHeight', self.setRowHeightHandler)
this.eventBus.$off('setMaxRows', self.setMaxRowsHandler)
this.eventBus.$off('directionchange', self.directionchangeHandler)
this.eventBus.$off('setColNum', self.setColNum)
this.interactObj.unset() // destroy interact intance
},
mounted: function () {
this.cols = this.$parent.colNum
this.rowHeight = this.$parent.rowHeight
this.containerWidth = this.$parent.width !== null ? this.$parent.width : 100
this.margin = this.$parent.margin !== undefined ? this.$parent.margin : [10, 10]
this.maxRows = this.$parent.maxRows
if (this.isDraggable === null) {
this.draggable = this.$parent.isDraggable
} else {
this.draggable = this.isDraggable
}
if (this.isResizable === null) {
this.resizable = this.$parent.isResizable
} else {
this.resizable = this.isResizable
}
this.useCssTransforms = this.$parent.useCssTransforms
this.createStyle()
},
watch: {
isDraggable: function () {
this.draggable = this.isDraggable
},
static: function () {
this.tryMakeDraggable()
this.tryMakeResizable()
},
draggable: function () {
this.tryMakeDraggable()
},
isResizable: function () {
this.resizable = this.isResizable
},
resizable: function () {
this.tryMakeResizable()
},
rowHeight: function () {
this.createStyle()
this.emitContainerResized()
},
cols: function () {
this.tryMakeResizable()
this.createStyle()
this.emitContainerResized()
},
containerWidth: function () {
this.tryMakeResizable()
this.createStyle()
this.emitContainerResized()
},
x: function (newVal) {
this.innerX = newVal
this.createStyle()
},
y: function (newVal) {
console.log(newVal)
this.innerY = newVal
this.createStyle()
},
h: function (newVal) {
this.innerH = newVal
this.createStyle()
// this.emitContainerResized();
},
w: function (newVal) {
this.innerW = newVal
this.createStyle()
// this.emitContainerResized();
},
renderRtl: function () {
// console.log("### renderRtl");
this.tryMakeResizable()
this.createStyle()
},
minH: function () {
this.tryMakeResizable()
},
maxH: function () {
this.tryMakeResizable()
},
minW: function () {
this.tryMakeResizable()
},
maxW: function () {
this.tryMakeResizable()
}
},
computed: {
classObj () {
return {
'vue-resizable': this.resizableAndNotStatic,
static: this.static,
resizing: this.isResizing,
'vue-draggable-dragging': this.isDragging,
cssTransforms: this.useCssTransforms,
'render-rtl': this.renderRtl,
'disable-userselect': this.isDragging,
'no-touch': this.isAndroid && this.draggableOrResizableAndNotStatic
}
},
resizableAndNotStatic () {
return this.resizable && !this.static
},
draggableOrResizableAndNotStatic () {
return (this.draggable || this.resizable) && !this.static
},
isAndroid () {
return navigator.userAgent.toLowerCase().indexOf('android') !== -1
},
renderRtl () {
return (this.$parent.isMirrored) ? !this.rtl : this.rtl
},
resizableHandleClass () {
if (this.renderRtl) {
return 'vue-resizable-handle vue-rtl-resizable-handle'
} else {
return 'vue-resizable-handle'
}
}
},
methods: {
createStyle: function () {
if (this.x + this.w > this.cols) {
this.innerX = 0
this.innerW = (this.w > this.cols) ? this.cols : this.w
} else {
this.innerX = this.x
this.innerW = this.w
}
const pos = this.calcPosition(this.innerX, this.innerY, this.innerW, this.innerH)
if (this.isDragging) {
pos.top = this.dragging.top
// Add rtl support
if (this.renderRtl) {
pos.right = this.dragging.left
} else {
pos.left = this.dragging.left
}
}
if (this.isResizing) {
pos.width = this.resizing.width
pos.height = this.resizing.height
}
let style
// CSS Transforms support (default)
if (this.useCssTransforms) {
// Add rtl support
if (this.renderRtl) {
style = setTransformRtl(pos.top, pos.right, pos.width, pos.height)
} else {
style = setTransform(pos.top, pos.left, pos.width, pos.height)
}
} else { // top,left (slow)
// Add rtl support
if (this.renderRtl) {
style = setTopRight(pos.top, pos.right, pos.width, pos.height)
} else {
style = setTopLeft(pos.top, pos.left, pos.width, pos.height)
}
}
this.style = style
},
emitContainerResized () {
// this.style has width and height with trailing 'px'. The
// resized event is without them
const styleProps = {}
for (const prop of ['width', 'height']) {
const val = this.style[prop]
const matches = val.match(/^(\d+)px$/)
if (!matches) { return }
styleProps[prop] = matches[1]
}
this.$emit('container-resized', this.i, this.h, this.w, styleProps.height, styleProps.width)
},
handleResize: function (event) {
if (this.static) return
const position = getControlPosition(event)
// Get the current drag point from the event. This is used as the offset.
if (position == null) return // not possible but satisfies flow
const { x, y } = position
const newSize = { width: 0, height: 0 }
let pos
switch (event.type) {
case 'resizestart': {
this.previousW = this.innerW
this.previousH = this.innerH
pos = this.calcPosition(this.innerX, this.innerY, this.innerW, this.innerH)
newSize.width = pos.width
newSize.height = pos.height
this.resizing = newSize
this.isResizing = true
break
}
case 'resizemove': {
// console.log("### resize => " + event.type + ", lastW=" + this.lastW + ", lastH=" + this.lastH);
const coreEvent = createCoreData(this.lastW, this.lastH, x, y)
if (this.renderRtl) {
newSize.width = this.resizing.width - coreEvent.deltaX
} else {
newSize.width = this.resizing.width + coreEvent.deltaX
}
newSize.height = this.resizing.height + coreEvent.deltaY
/// console.log("### resize => " + event.type + ", deltaX=" + coreEvent.deltaX + ", deltaY=" + coreEvent.deltaY);
this.resizing = newSize
break
}
case 'resizeend': {
// console.log("### resize end => x=" +this.innerX + " y=" + this.innerY + " w=" + this.innerW + " h=" + this.innerH);
pos = this.calcPosition(this.innerX, this.innerY, this.innerW, this.innerH)
newSize.width = pos.width
newSize.height = pos.height
// console.log("### resize end => " + JSON.stringify(newSize));
this.resizing = null
this.isResizing = false
break
}
}
// Get new WH
pos = this.calcWH(newSize.height, newSize.width)
if (pos.w < this.minW) {
pos.w = this.minW
}
if (pos.w > this.maxW) {
pos.w = this.maxW
}
if (pos.h < this.minH) {
pos.h = this.minH
}
if (pos.h > this.maxH) {
pos.h = this.maxH
}
// if (pos.h < 1) {
// pos.h = 1;
// }
// if (pos.w < 1) {
// pos.w = 1;
// }
this.lastW = x
this.lastH = y
if (this.innerW !== pos.w || this.innerH !== pos.h) {
this.$emit('resize', this.i, pos.h, pos.w, newSize.height, newSize.width)
}
if (event.type === 'resizeend' && (this.previousW !== this.innerW || this.previousH !== this.innerH)) {
this.$emit('resized', this.i, pos.h, pos.w, newSize.height, newSize.width)
}
this.eventBus.$emit('resizeEvent', event.type, this.i, this.innerX, this.innerY, pos.h, pos.w)
},
handleDrag (event) {
if (this.static) return
if (this.isResizing) return
const position = getControlPosition(event)
// Get the current drag point from the event. This is used as the offset.
if (position === null) return // not possible but satisfies flow
const { x, y } = position
// let shouldUpdate = false;
const newPosition = { top: 0, left: 0 }
switch (event.type) {
case 'dragstart': {
this.previousX = this.innerX
this.previousY = this.innerY
const parentRect = event.target.offsetParent.getBoundingClientRect()
const clientRect = event.target.getBoundingClientRect()
if (this.renderRtl) {
newPosition.left = (clientRect.right - parentRect.right) * -1
} else {
newPosition.left = clientRect.left - parentRect.left
}
newPosition.top = clientRect.top - parentRect.top
this.dragging = newPosition
this.isDragging = true
break
}
case 'dragend': {
if (!this.isDragging) return
const parentRect = event.target.offsetParent.getBoundingClientRect()
const clientRect = event.target.getBoundingClientRect()
// Add rtl support
if (this.renderRtl) {
newPosition.left = (clientRect.right - parentRect.right) * -1
} else {
newPosition.left = clientRect.left - parentRect.left
}
newPosition.top = clientRect.top - parentRect.top
// console.log("### drag end => " + JSON.stringify(newPosition));
// console.log("### DROP: " + JSON.stringify(newPosition));
this.dragging = null
this.isDragging = false
// shouldUpdate = true;
break
}
case 'dragmove': {
const coreEvent = createCoreData(this.lastX, this.lastY, x, y)
// Add rtl support
if (this.renderRtl) {
newPosition.left = this.dragging.left - coreEvent.deltaX
} else {
newPosition.left = this.dragging.left + coreEvent.deltaX
}
newPosition.top = this.dragging.top + coreEvent.deltaY
// console.log("### drag => " + event.type + ", x=" + x + ", y=" + y);
// console.log("### drag => " + event.type + ", deltaX=" + coreEvent.deltaX + ", deltaY=" + coreEvent.deltaY);
// console.log("### drag end => " + JSON.stringify(newPosition));
this.dragging = newPosition
break
}
}
// Get new XY
let pos
if (this.renderRtl) {
pos = this.calcXY(newPosition.top, newPosition.left)
} else {
pos = this.calcXY(newPosition.top, newPosition.left)
}
this.lastX = x
this.lastY = y
if (this.innerX !== pos.x || this.innerY !== pos.y) {
this.$emit('move', this.i, pos.x, pos.y)
}
if (event.type === 'dragend' && (this.previousX !== this.innerX || this.previousY !== this.innerY)) {
this.$emit('moved', this.i, pos.x, pos.y)
}
this.eventBus.$emit('dragEvent', event.type, this.i, pos.x, pos.y, this.innerH, this.innerW)
},
calcPosition: function (x, y, w, h) {
const colWidth = this.calcColWidth()
// add rtl support
let out
if (this.renderRtl) {
out = {
right: Math.round(colWidth * x + (x + 1) * this.margin[0]),
top: Math.round(this.rowHeight * y + (y + 1) * this.margin[1]),
// 0 * Infinity === NaN, which causes problems with resize constriants;
// Fix this if it occurs.
// Note we do it here rather than later because Math.round(Infinity) causes deopt
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * this.margin[0]),
height: h === Infinity ? h : Math.round(this.rowHeight * h + Math.max(0, h - 1) * this.margin[1])
}
} else {
out = {
left: Math.round(colWidth * x + (x + 1) * this.margin[0]),
top: Math.round(this.rowHeight * y + (y + 1) * this.margin[1]),
// 0 * Infinity === NaN, which causes problems with resize constriants;
// Fix this if it occurs.
// Note we do it here rather than later because Math.round(Infinity) causes deopt
width: w === Infinity ? w : Math.round(colWidth * w + Math.max(0, w - 1) * this.margin[0]),
height: h === Infinity ? h : Math.round(this.rowHeight * h + Math.max(0, h - 1) * this.margin[1])
}
}
return out
},
/**
* Translate x and y coordinates from pixels to grid units.
* @param {Number} top Top position (relative to parent) in pixels.
* @param {Number} left Left position (relative to parent) in pixels.
* @return {Object} x and y in grid units.
*/
// TODO check if this function needs change in order to support rtl.
calcXY (top, left) {
const colWidth = this.calcColWidth()
// left = colWidth * x + margin * (x + 1)
// l = cx + m(x+1)
// l = cx + mx + m
// l - m = cx + mx
// l - m = x(c + m)
// (l - m) / (c + m) = x
// x = (left - margin) / (coldWidth + margin)
let x = Math.round((left - this.margin[0]) / (colWidth + this.margin[0]))
let y = Math.round((top - this.margin[1]) / (this.rowHeight + this.margin[1]))
// Capping
x = Math.max(Math.min(x, this.cols - this.innerW), 0)
y = Math.max(Math.min(y, this.maxRows - this.innerH), 0)
return { x, y }
},
// Helper for generating column width
calcColWidth () {
const colWidth = (this.containerWidth - (this.margin[0] * (this.cols + 1))) / this.cols
// console.log("### COLS=" + this.cols + " COL WIDTH=" + colWidth + " MARGIN " + this.margin[0]);
return colWidth
},
/**
* Given a height and width in pixel values, calculate grid units.
* @param {Number} height Height in pixels.
* @param {Number} width Width in pixels.
* @return {Object} w, h as grid units.
*/
calcWH (height, width) {
const colWidth = this.calcColWidth()
// width = colWidth * w - (margin * (w - 1))
// ...
// w = (width + margin) / (colWidth + margin)
let w = Math.round((width + this.margin[0]) / (colWidth + this.margin[0]))
let h = Math.round((height + this.margin[1]) / (this.rowHeight + this.margin[1]))
console.log(w, h, '1231213123')
// Capping
w = Math.max(Math.min(w, this.cols - this.innerX), 0)
h = Math.max(Math.min(h, this.maxRows - this.innerY), 0)
console.log(w, h, '1231213123')
return { w, h }
},
updateWidth: function (width, colNum) {
this.containerWidth = width
if (colNum !== undefined && colNum !== null) {
this.cols = colNum
}
},
compact: function () {
this.createStyle()
},
tryMakeDraggable: function () {
const self = this
if (this.interactObj === null || this.interactObj === undefined) {
this.interactObj = interact(this.$refs.item)
}
if (this.draggable && !this.static) {
const opts = {
ignoreFrom: this.dragIgnoreFrom,
allowFrom: this.dragAllowFrom
}
this.interactObj.draggable(opts)
/* this.interactObj.draggable({allowFrom: '.vue-draggable-handle'}); */
if (!this.dragEventSet) {
this.dragEventSet = true
this.interactObj.on('dragstart dragmove dragend', function (event) {
self.handleDrag(event)
})
}
} else {
this.interactObj.draggable({
enabled: false
})
}
},
tryMakeResizable: function () {
const self = this
if (this.interactObj === null || this.interactObj === undefined) {
this.interactObj = interact(this.$refs.item)
}
if (this.resizable && !this.static) {
const maximum = this.calcPosition(0, 0, this.maxW, this.maxH)
const minimum = this.calcPosition(0, 0, this.minW, this.minH)
// console.log("### MAX " + JSON.stringify(maximum));
// console.log("### MIN " + JSON.stringify(minimum));
const opts = {
preserveAspectRatio: true,
// allowFrom: "." + this.resizableHandleClass,
edges: {
left: false,
right: '.' + this.resizableHandleClass,
bottom: '.' + this.resizableHandleClass,
top: false
},
ignoreFrom: this.resizeIgnoreFrom,
restrictSize: {
min: {
height: minimum.height,
width: minimum.width
},
max: {
height: maximum.height,
width: maximum.width
}
}
}
this.interactObj.resizable(opts)
if (!this.resizeEventSet) {
this.resizeEventSet = true
this.interactObj
.on('resizestart resizemove resizeend', function (event) {
self.handleResize(event)
})
}
} else {
this.interactObj.resizable({
enabled: false
})
}
},
autoSize: function () {
// ok here we want to calculate if a resize is needed
this.previousW = this.innerW
this.previousH = this.innerH
const newSize = this.$slots.default[0].elm.getBoundingClientRect()
const pos = this.calcWH(newSize.height, newSize.width)
if (pos.w < this.minW) {
pos.w = this.minW
}
if (pos.w > this.maxW) {
pos.w = this.maxW
}
if (pos.h < this.minH) {
pos.h = this.minH
}
if (pos.h > this.maxH) {
pos.h = this.maxH
}
// if (pos.h < 1) {
// pos.h = 1;
// }
// if (pos.w < 1) {
// pos.w = 1;
// }
// this.lastW = x; // basically, this is copied from resizehandler, but shouldn't be needed
// this.lastH = y;
if (this.innerW !== pos.w || this.innerH !== pos.h) {
this.$emit('resize', this.i, pos.h, pos.w, newSize.height, newSize.width)
}
if (this.previousW !== pos.w || this.previousH !== pos.h) {
this.$emit('resized', this.i, pos.h, pos.w, newSize.height, newSize.width)
this.eventBus.$emit('resizeEvent', 'resizeend', this.i, this.innerX, this.innerY, pos.h, pos.w)
}
}
}
}
</script>

View File

@@ -1,439 +0,0 @@
<template>
<div ref="item" class="vue-grid-layout" :style="mergedStyle">
<slot></slot>
<grid-item class="vue-grid-placeholder"
v-show="isDragging"
:x="placeholder.x"
:y="placeholder.y"
:w="placeholder.w"
:h="placeholder.h"
:i="placeholder.i"></grid-item>
</div>
</template>
<style>
.vue-grid-layout {
position: relative;
transition: height 200ms ease;
}
</style>
<script>
import Vue from 'vue'
import { bottom, compact, getLayoutItem, moveElement, validateLayout, cloneLayout, getAllCollisions } from './gridItemUtils'
import { getBreakpointFromWidth, getColsFromBreakpoint, findOrGenerateResponsiveLayout } from './responsiveUtils'
// var eventBus = require('./eventBus');
import GridItem from './GridItem.vue'
import { addWindowEventListener, removeWindowEventListener } from './gridItemDOM'
const elementResizeDetectorMaker = require('element-resize-detector')
export default {
name: 'GridLayout',
provide () {
return {
eventBus: null
}
},
components: {
GridItem
},
props: {
// If true, the container height swells and contracts to fit contents
autoSize: {
type: Boolean,
default: true
},
colNum: {
type: Number,
default: 12
},
rowHeight: {
type: Number,
default: 150
},
maxRows: {
type: Number,
default: Infinity
},
margin: {
type: Array,
default: function () {
return [10, 10]
}
},
isDraggable: {
type: Boolean,
default: true
},
isResizable: {
type: Boolean,
default: true
},
isMirrored: {
type: Boolean,
default: false
},
useCssTransforms: {
type: Boolean,
default: true
},
verticalCompact: {
type: Boolean,
default: true
},
layout: {
type: Array,
required: true
},
responsive: {
type: Boolean,
default: false
},
breakpoints: {
type: Object,
default: function () { return { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 } }
},
cols: {
type: Object,
default: function () { return { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 } }
},
preventCollision: {
type: Boolean,
default: false
}
},
data: function () {
return {
width: null,
mergedStyle: {},
lastLayoutLength: 0,
isDragging: false,
placeholder: {
x: 0,
y: 0,
w: 0,
h: 0,
i: -1
},
layouts: {}, // array to store all layouts from different breakpoints
lastBreakpoint: null, // store last active breakpoint
originalLayout: null // store original Layout
}
},
created () {
const self = this
// Accessible refernces of functions for removing in beforeDestroy
self.resizeEventHandler = function (eventType, i, x, y, h, w) {
self.resizeEvent(eventType, i, x, y, h, w)
}
self.dragEventHandler = function (eventType, i, x, y, h, w) {
console.log(eventType, i, x, y, h, w,'dragFlag')
self.dragEvent(eventType, i, x, y, h, w)
}
self._provided.eventBus = new Vue()
self.eventBus = self._provided.eventBus
self.eventBus.$on('resizeEvent', self.resizeEventHandler)
self.eventBus.$on('dragEvent', self.dragEventHandler)
self.$emit('layout-created', self.layout)
},
beforeDestroy: function () {
// Remove listeners
this.eventBus.$off('resizeEvent', this.resizeEventHandler)
this.eventBus.$off('dragEvent', this.dragEventHandler)
this.eventBus.$destroy()
removeWindowEventListener('resize', this.onWindowResize)
this.erd.uninstall(this.$refs.item)
},
beforeMount: function () {
this.$emit('layout-before-mount', this.layout)
},
mounted: function () {
this.$emit('layout-mounted', this.layout)
this.$nextTick(function () {
validateLayout(this.layout)
this.originalLayout = this.layout
const self = this
this.$nextTick(function () {
self.onWindowResize()
self.initResponsiveFeatures()
// self.width = self.$el.offsetWidth;
addWindowEventListener('resize', self.onWindowResize)
compact(self.layout, self.verticalCompact)
self.updateHeight()
self.$nextTick(function () {
this.erd = elementResizeDetectorMaker({
strategy: 'scroll', // <- For ultra performance.
// See https://github.com/wnr/element-resize-detector/issues/110 about callOnAdd.
callOnAdd: false
})
this.erd.listenTo(self.$refs.item, function () {
self.onWindowResize()
})
})
})
})
},
watch: {
width: function (newval, oldval) {
const self = this
this.$nextTick(function () {
// this.$broadcast("updateWidth", this.width);
this.eventBus.$emit('updateWidth', this.width)
if (oldval === null) {
/*
If oldval == null is when the width has never been
set before. That only occurs when mouting is
finished, and onWindowResize has been called and
this.width has been changed the first time after it
got set to null in the constructor. It is now time
to issue layout-ready events as the GridItems have
their sizes configured properly.
The reason for emitting the layout-ready events on
the next tick is to allow for the newly-emitted
updateWidth event (above) to have reached the
children GridItem-s and had their effect, so we're
sure that they have the final size before we emit
layout-ready (for this GridLayout) and
item-layout-ready (for the GridItem-s).
This way any client event handlers can reliably
invistigate stable sizes of GridItem-s.
*/
this.$nextTick(() => {
this.$emit('layout-ready', self.layout)
})
}
this.updateHeight()
})
},
layout: function () {
this.layoutUpdate()
},
colNum: function (val) {
this.eventBus.$emit('setColNum', val)
},
rowHeight: function () {
this.eventBus.$emit('setRowHeight', this.rowHeight)
},
isDraggable: function () {
this.eventBus.$emit('setDraggable', this.isDraggable)
},
isResizable: function () {
this.eventBus.$emit('setResizable', this.isResizable)
},
responsive () {
if (!this.responsive) {
this.$emit('update:layout', this.originalLayout)
this.eventBus.$emit('setColNum', this.colNum)
}
this.onWindowResize()
},
maxRows: function () {
this.eventBus.$emit('setMaxRows', this.maxRows)
}
},
methods: {
layoutUpdate () {
if (this.layout !== undefined && this.originalLayout !== null) {
if (this.layout.length !== this.originalLayout.length) {
// console.log("### LAYOUT UPDATE!", this.layout.length, this.originalLayout.length);
const diff = this.findDifference(this.layout, this.originalLayout)
if (diff.length > 0) {
// console.log(diff);
if (this.layout.length > this.originalLayout.length) {
this.originalLayout = this.originalLayout.concat(diff)
} else {
this.originalLayout = this.originalLayout.filter(obj => {
return !diff.some(obj2 => {
return obj.i === obj2.i
})
})
}
}
this.lastLayoutLength = this.layout.length
this.initResponsiveFeatures()
}
compact(this.layout, this.verticalCompact)
this.eventBus.$emit('updateWidth', this.width)
this.updateHeight()
}
},
updateHeight: function () {
this.mergedStyle = {
height: this.containerHeight()
}
},
onWindowResize: function () {
if (this.$refs !== null && this.$refs.item !== null && this.$refs.item !== undefined) {
this.width = this.$refs.item.offsetWidth
}
this.eventBus.$emit('resizeEvent')
},
containerHeight: function () {
if (!this.autoSize) return
return bottom(this.layout) * (this.rowHeight + this.margin[1]) + this.margin[1] + 'px'
},
dragEvent: function (eventName, id, x, y, h, w) {
// console.log(eventName + " id=" + id + ", x=" + x + ", y=" + y);
let l = getLayoutItem(this.layout, id)
// GetLayoutItem sometimes returns null object
if (l === undefined || l === null) {
l = { x: 0, y: 0 }
}
if (eventName === 'dragmove' || eventName === 'dragstart') {
this.placeholder.i = id
this.placeholder.x = l.x
this.placeholder.y = l.y
console.log(l.y)
this.placeholder.w = w
this.placeholder.h = h
this.$nextTick(function () {
this.isDragging = true
})
// this.$broadcast("updateWidth", this.width);
this.eventBus.$emit('updateWidth', this.width)
} else {
this.$nextTick(function () {
this.isDragging = false
})
}
// Move the element to the dragged location.
this.layout = moveElement(this.layout, l, x, y, true, this.preventCollision)
compact(this.layout, this.verticalCompact)
// needed because vue can't detect changes on array element properties
this.eventBus.$emit('compact')
this.updateHeight()
if (eventName === 'dragend') this.$emit('layout-updated', this.layout)
},
resizeEvent: function (eventName, id, x, y, h, w) {
let l = getLayoutItem(this.layout, id)
// GetLayoutItem sometimes return null object
if (l === undefined || l === null) {
l = { h: 0, w: 0 }
}
let hasCollisions
if (this.preventCollision) {
const collisions = getAllCollisions(this.layout, { ...l, w, h }).filter(
layoutItem => layoutItem.i !== l.i
)
hasCollisions = collisions.length > 0
// If we're colliding, we need adjust the placeholder.
if (hasCollisions) {
// adjust w && h to maximum allowed space
let leastX = Infinity
let leastY = Infinity
collisions.forEach(layoutItem => {
if (layoutItem.x > l.x) leastX = Math.min(leastX, layoutItem.x)
if (layoutItem.y > l.y) leastY = Math.min(leastY, layoutItem.y)
})
if (Number.isFinite(leastX)) l.w = leastX - l.x
if (Number.isFinite(leastY)) l.h = leastY - l.y
}
}
if (!hasCollisions) {
// Set new width and height.
l.w = w
l.h = h
}
if (eventName === 'resizestart' || eventName === 'resizemove') {
this.placeholder.i = id
this.placeholder.x = x
this.placeholder.y = y
this.placeholder.w = l.w
this.placeholder.h = l.h
this.$nextTick(function () {
this.isDragging = true
})
// this.$broadcast("updateWidth", this.width);
this.eventBus.$emit('updateWidth', this.width)
} else {
this.$nextTick(function () {
this.isDragging = false
})
}
if (this.responsive) this.responsiveGridLayout()
compact(this.layout, this.verticalCompact)
this.eventBus.$emit('compact')
this.updateHeight()
if (eventName === 'resizeend') this.$emit('layout-updated', this.layout)
},
// finds or generates new layouts for set breakpoints
responsiveGridLayout () {
const newBreakpoint = getBreakpointFromWidth(this.breakpoints, this.width)
const newCols = getColsFromBreakpoint(newBreakpoint, this.cols)
// save actual layout in layouts
if (this.lastBreakpoint != null && !this.layouts[this.lastBreakpoint]) { this.layouts[this.lastBreakpoint] = cloneLayout(this.layout) }
// Find or generate a new layout.
const layout = findOrGenerateResponsiveLayout(
this.originalLayout,
this.layouts,
this.breakpoints,
newBreakpoint,
this.lastBreakpoint,
newCols,
this.verticalCompact
)
// Store the new layout.
this.layouts[newBreakpoint] = layout
// new prop sync
this.$emit('update:layout', layout)
this.lastBreakpoint = newBreakpoint
this.eventBus.$emit('setColNum', getColsFromBreakpoint(newBreakpoint, this.cols))
},
// clear all responsive layouts
initResponsiveFeatures () {
// clear layouts
this.layouts = {}
},
// find difference in layouts
findDifference (layout, originalLayout) {
// Find values that are in result1 but not in result2
const uniqueResultOne = layout.filter(function (obj) {
return !originalLayout.some(function (obj2) {
return obj.i === obj2.i
})
})
// Find values that are in result2 but not in result1
const uniqueResultTwo = originalLayout.filter(function (obj) {
return !layout.some(function (obj2) {
return obj.i === obj2.i
})
})
// Combine the two arrays of unique entries#
return uniqueResultOne.concat(uniqueResultTwo)
}
}
}
</script>

View File

@@ -83,6 +83,14 @@
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
:chart-option="chartOption" :chart-option="chartOption"
></chart-diagram> ></chart-diagram>
<chartAutoCarousel
:ref="'chart' + chartInfo.id"
v-if="isAutoCarousel(chartInfo.type)"
:chart-data="chartData"
:chart-info="chartInfo"
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
></chartAutoCarousel>
<chart-group <chart-group
:ref="'chart' + chartInfo.id" :ref="'chart' + chartInfo.id"
v-if="isGroup(chartInfo.type)" v-if="isGroup(chartInfo.type)"
@@ -92,14 +100,6 @@
:is-fullscreen="isFullscreen" :is-fullscreen="isFullscreen"
:chart-option="chartOption" :chart-option="chartOption"
></chart-group> ></chart-group>
<chartAutoCarousel
:ref="'chart' + chartInfo.id"
v-if="isAutoCarousel(chartInfo.type)"
:chart-data="chartData"
:chart-info="chartInfo"
:chart-option="chartOption"
:is-fullscreen="isFullscreen"
></chartAutoCarousel>
</template> </template>
</div> </div>
</template> </template>

View File

@@ -1,10 +1,101 @@
<template> <template>
<div v-loading="topologyLoading" class="overview">
<transition name = "el-zoom-in-center">
<div v-if="allProject&&allProject.length>0" style="width: 100%;height: 100%;position: relative">
<el-carousel :interval="5000" :trigger="'click'" arrow="hover">
<el-carousel-item v-for="(item,index) in allProject" :key="index">
<div class="maskLayer" @click="toProject(item)"></div>
<span class="project-name">{{item.name}}</span>
<topology
:fromOverView="true"
:obj="item"
:ref="'topology' + index"
:topologyIndexF="index"
/>
</el-carousel-item>
</el-carousel>
</div>
</transition>
<div v-if="allProject.length===0" class="chart-no-data">No Data</div>
</div>
</template> </template>
<script> <script>
import axios from 'axios'
import topology from '@/components/common/project/topologyL5'
import chartMixin from '@/components/chart/chartMixin'
import bus from '@/libs/bus'
export default { export default {
name: 'chartAutoCarousel' name: 'chartAutoCarousel',
data () {
return {
topologyLoading: false,
allProject: []
}
},
mixins: [chartMixin],
components: {
topology
},
methods: {
queryAllProjectData () {
this.$get('monitor/project', { pageSize: -1 }).then(res => {
this.topologyLoading = true
const axiosAll = []
const temp = []
if (res.data.list.length === 0) {
this.topologyLoading = false
}
res.data.list.forEach((item) => {
axiosAll.push(axios.get(`monitor/project/topo?projectId=${item.id}`))
})
axios.all(axiosAll).then(res2 => {
res2 = res2.map((item, index) => {
return { ...item.data.data, ...res.data.list[index] }
})
res2 = res2.filter((item) => item.topo && item.topo.pens && item.topo.pens.length)
if (res2.length == 0) {
this.topologyLoading = false
}
res2.forEach(item => {
temp.push(item)
})
this.allProject = temp
this.topologyLoading = false
})
})
},
toProject (projectInfo) { // 跳转对应project页面
this.$store.commit('currentProjectChange', projectInfo)
this.jumpTo('project')
},
jumpTo (data, id) {
if (data == 'asset') {
bus.$emit('clear-asset-filter') // 清除leftMenu左侧菜单过滤条件
// if(this.$store.getters.getIdcArr.length===0){return}//如果不存在idc 则不跳转
}
if (data === 'project' || data === 'module' || data === 'endpoint') {
data = 'monitor/' + data
}
if (data === 'alertList') {
data = 'alertMessage'
}
this.$router.push({
path: '/' + data,
query: {
t: +new Date()
}
})
},
resize () {
this.allProject.forEach((item, index) => {
this.$refs['topology' + index][0] && this.$refs['topology' + index][0].winResize()
})
}
},
mounted () {
this.queryAllProjectData()
}
} }
</script> </script>

View File

@@ -23,6 +23,7 @@ const chartTreemapOption = {
visibleMin: 40, visibleMin: 40,
childrenVisibleMin: 40, childrenVisibleMin: 40,
nodeClick: false, nodeClick: false,
roam: false,
label: { label: {
show: true, show: true,
position: 'inside', position: 'inside',

View File

@@ -80,8 +80,6 @@
<script> <script>
import VueGridLayout from 'vue-grid-layout' import VueGridLayout from 'vue-grid-layout'
import gridItem from './GridItem'
// import GridLayout from './GridLayout'
import { fromRoute } from '@/components/common/js/constants' import { fromRoute } from '@/components/common/js/constants'
import { getGroupHeight } from './chart/tools' import { getGroupHeight } from './chart/tools'
import panelChart from '@/components/chart/panelChart' import panelChart from '@/components/chart/panelChart'
@@ -103,7 +101,7 @@ export default {
}, },
components: { components: {
GridLayout: VueGridLayout.GridLayout, GridLayout: VueGridLayout.GridLayout,
GridItem: gridItem, GridItem: VueGridLayout.GridItem,
panelChart panelChart
}, },
computed: { computed: {
@@ -203,7 +201,7 @@ export default {
// console.log(this.$refs.layout) // console.log(this.$refs.layout)
const groupFind = this.copyDataList.find(item => item.id == group.id) const groupFind = this.copyDataList.find(item => item.id == group.id)
console.log(groupFind) console.log(groupFind)
if (group) { if (group && groupFind) {
groupFind.height = groupFind.h = height + this.headerHPadding groupFind.height = groupFind.h = height + this.headerHPadding
groupFind.children = copyList groupFind.children = copyList
this.copyDataList = [...this.copyDataList] this.copyDataList = [...this.copyDataList]

View File

@@ -1,29 +0,0 @@
const currentDir = 'auto'
function hasDocument () {
return (typeof document !== 'undefined')
}
function hasWindow () {
return (typeof window !== 'undefined')
}
export function getDocumentDir () {
if (!hasDocument()) {
return currentDir
}
const direction = (typeof document.dir !== 'undefined')
? document.dir
: document.getElementsByTagName('html')[0].getAttribute('dir')
return direction
}
export function addWindowEventListener (event, callback) {
if (!hasWindow) {
callback()
return
}
window.addEventListener(event, callback)
}
export function removeWindowEventListener (event, callback) {
if (!hasWindow) {
return
}
window.removeEventListener(event, callback)
}

View File

@@ -1,266 +0,0 @@
export function setTopLeft (top, left, width, height) {
return {
top: top + 'px',
left: left + 'px',
width: width + 'px',
height: height + 'px',
position: 'absolute'
}
}
export function setTopRight (top, right, width, height) {
return {
top: top + 'px',
right: right + 'px',
width: width + 'px',
height: height + 'px',
position: 'absolute'
}
}
export function setTransformRtl (top, right, width, height) {
// Replace unitless items with px
const translate = 'translate3d(' + right * -1 + 'px,' + top + 'px, 0)'
return {
transform: translate,
WebkitTransform: translate,
MozTransform: translate,
msTransform: translate,
OTransform: translate,
width: width + 'px',
height: height + 'px',
position: 'absolute'
}
}
export function setTransform (top, left, width, height) {
// Replace unitless items with px
const translate = 'translate3d(' + left + 'px,' + top + 'px, 0)'
return {
transform: translate,
WebkitTransform: translate,
MozTransform: translate,
msTransform: translate,
OTransform: translate,
width: width + 'px',
height: height + 'px',
position: 'absolute'
}
}
export function bottom (layout) {
let max = 0; let bottomY
for (let i = 0, len = layout.length; i < len; i++) {
bottomY = layout[i].y + layout[i].h
if (bottomY > max) max = bottomY
}
return max
}
export function compact (layout, verticalCompact) {
// Statics go in the compareWith array right away so items flow around them.
const compareWith = getStatics(layout)
// We go through the items by row and column.
const sorted = sortLayoutItemsByRowCol(layout)
// Holding for new items.
const out = Array(layout.length)
for (let i = 0, len = sorted.length; i < len; i++) {
let l = sorted[i]
// Don't move static elements
if (!l.static) {
l = compactItem(compareWith, l, verticalCompact)
// Add to comparison array. We only collide with items before this one.
// Statics are already in this array.
compareWith.push(l)
}
// Add to output array to make sure they still come out in the right order.
out[layout.indexOf(l)] = l
// Clear moved flag, if it exists.
l.moved = false
}
return out
}
export function getLayoutItem (layout, id) {
for (let i = 0, len = layout.length; i < len; i++) {
if (layout[i].i === id) return layout[i]
}
}
export function moveElement (layout, l, x, y, isUserAction, preventCollision) {
if (l.static) return layout
// Short-circuit if nothing to do.
// if (l.y === y && l.x === x) return layout;
const oldX = l.x
const oldY = l.y
const movingUp = y && l.y > y
// This is quite a bit faster than extending the object
if (typeof x === 'number') l.x = x
if (typeof y === 'number') l.y = y
l.moved = true
// If this collides with anything, move it.
// When doing this comparison, we have to sort the items we compare with
// to ensure, in the case of multiple collisions, that we're getting the
// nearest collision.
let sorted = sortLayoutItemsByRowCol(layout)
if (movingUp) sorted = sorted.reverse()
const collisions = getAllCollisions(sorted, l)
if (preventCollision && collisions.length) {
l.x = oldX
l.y = oldY
l.moved = false
return layout
}
// Move each item that collides away from this element.
for (let i = 0, len = collisions.length; i < len; i++) {
const collision = collisions[i]
// console.log('resolving collision between', l.i, 'at', l.y, 'and', collision.i, 'at', collision.y);
// Short circuit so we can't infinite loop
if (collision.moved) continue
// This makes it feel a bit more precise by waiting to swap for just a bit when moving up.
if (l.y > collision.y && l.y - collision.y > collision.h / 4) continue
// Don't move static items - we have to move *this* element away
if (collision.static) {
layout = moveElementAwayFromCollision(layout, collision, l, isUserAction)
} else {
layout = moveElementAwayFromCollision(layout, l, collision, isUserAction)
}
}
return layout
}
export function validateLayout (layout, contextName) {
contextName = contextName || 'Layout'
const subProps = ['x', 'y', 'w', 'h']
if (!Array.isArray(layout)) throw new Error(contextName + ' must be an array!')
for (let i = 0, len = layout.length; i < len; i++) {
const item = layout[i]
for (let j = 0; j < subProps.length; j++) {
if (typeof item[subProps[j]] !== 'number') {
throw new Error('VueGridLayout: ' + contextName + '[' + i + '].' + subProps[j] + ' must be a number!')
}
}
if (item.i && typeof item.i !== 'string') {
// number is also ok, so comment the error
// TODO confirm if commenting the line below doesn't cause unexpected problems
// throw new Error('VueGridLayout: ' + contextName + '[' + i + '].i must be a string!');
}
if (item.static !== undefined && typeof item.static !== 'boolean') {
throw new Error('VueGridLayout: ' + contextName + '[' + i + '].static must be a boolean!')
}
}
}
export function cloneLayout (layout) {
const newLayout = Array(layout.length)
for (let i = 0, len = layout.length; i < len; i++) {
newLayout[i] = cloneLayoutItem(layout[i])
}
return newLayout
}
export function getAllCollisions (layout, layoutItem) {
return layout.filter((l) => collides(l, layoutItem))
}
export function cloneLayoutItem (layoutItem) {
/* return {
w: layoutItem.w, h: layoutItem.h, x: layoutItem.x, y: layoutItem.y, i: layoutItem.i,
minW: layoutItem.minW, maxW: layoutItem.maxW, minH: layoutItem.minH, maxH: layoutItem.maxH,
moved: Boolean(layoutItem.moved), static: Boolean(layoutItem.static),
// These can be null
isDraggable: layoutItem.isDraggable, isResizable: layoutItem.isResizable
}; */
return JSON.parse(JSON.stringify(layoutItem))
}
export function 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
}
export function compactItem (compareWith, l, verticalCompact) {
if (verticalCompact) {
// Move the element up as far as it can go without colliding.
while (l.y > 0 && !getFirstCollision(compareWith, l)) {
l.y--
}
}
// Move it down, and keep moving it down if it's colliding.
let collides
while ((collides = getFirstCollision(compareWith, l))) {
l.y = collides.y + collides.h
}
return l
}
export function getFirstCollision (layout, layoutItem) {
for (let i = 0, len = layout.length; i < len; i++) {
if (collides(layout[i], layoutItem)) return layout[i]
}
}
export function getStatics (layout) {
// return [];
return layout.filter((l) => l.static)
}
export function moveElementAwayFromCollision (layout, collidesWith, itemToMove, isUserAction) {
const preventCollision = false // we're already colliding
// If there is enough space above the collision to put this element, move it there.
// We only do this on the main collision as this can get funky in cascades and cause
// unwanted swapping behavior.
if (isUserAction) {
// Make a mock item so we don't modify the item here, only modify in moveElement.
const fakeItem = {
x: itemToMove.x,
y: itemToMove.y,
w: itemToMove.w,
h: itemToMove.h,
i: '-1'
}
fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0)
if (!getFirstCollision(layout, fakeItem)) {
return moveElement(layout, itemToMove, undefined, fakeItem.y, preventCollision)
}
}
// Previously this was optimized to move below the collision directly, but this can cause problems
// with cascading moves, as an item may actually leapflog a collision and cause a reversal in order.
return moveElement(layout, itemToMove, undefined, itemToMove.y + 1, preventCollision)
}
export function sortLayoutItemsByRowCol (layout) {
return [].concat(layout).sort(function (a, b) {
if (a.y > b.y || (a.y === b.y && a.x > b.x)) {
return 1
}
return -1
})
}
export function correctBounds (layout, bounds) {
const collidesWith = getStatics(layout)
for (let i = 0, len = layout.length; i < len; i++) {
const l = layout[i]
// Overflows right
if (l.x + l.w > bounds.cols) l.x = bounds.cols - l.w
// Overflows left
if (l.x < 0) {
l.x = 0
l.w = bounds.cols
}
if (!l.static) collidesWith.push(l)
else {
// If this is static and collides with other statics, we must move it down.
// We have to do something nicer than just letting them overlap.
while (getFirstCollision(collidesWith, l)) {
l.y++
}
}
}
return layout
}

View File

@@ -153,12 +153,19 @@ export default {
}) })
} }
if (this.chartInfo.type === 'diagram') { if (this.chartInfo.type === 'diagram') {
this.chartData = [this.chartInfo.param.topo] if (!this.chartInfo.param.topo || !this.chartInfo.param.topo.pens.length){
this.chartData = []
} else {
this.chartData = [this.chartInfo.param.topo]
}
} }
if (this.chartInfo.type === 'group') { if (this.chartInfo.type === 'group') {
this.groupInit() this.groupInit()
this.chartData = [...this.chartInfo.children] this.chartData = [...this.chartInfo.children]
} }
if (this.chartInfo.type === 'carousel') {
this.chartData = ['carousel']
}
break break
} }
} }

View File

@@ -1,89 +0,0 @@
import { compact, cloneLayout, correctBounds } from './gridItemUtils'
export function getBreakpointFromWidth (breakpoints, width) {
const sorted = sortBreakpoints(breakpoints)
let matching = sorted[0]
for (let i = 1, len = sorted.length; i < len; i++) {
const breakpointName = sorted[i]
if (width > breakpoints[breakpointName]) matching = breakpointName
}
return matching
}
/**
* Given a breakpoint, get the # of cols set for it.
* @param {String} breakpoint Breakpoint name.
* @param {Object} cols Map of breakpoints to cols.
* @return {Number} Number of cols.
*/
export function getColsFromBreakpoint (breakpoint, cols) {
if (!cols[breakpoint]) {
throw new Error('ResponsiveGridLayout: `cols` entry for breakpoint ' + breakpoint + ' is missing!')
}
return cols[breakpoint]
}
/**
* Given existing layouts and a new breakpoint, find or generate a new layout.
*
* This finds the layout above the new one and generates from it, if it exists.
*
* @param {Array} orgLayout Original layout.
* @param {Object} layouts Existing layouts.
* @param {Array} breakpoints All breakpoints.
* @param {String} breakpoint New breakpoint.
* @param {String} breakpoint Last breakpoint (for fallback).
* @param {Number} cols Column count at new breakpoint.
* @param {Boolean} verticalCompact Whether or not to compact the layout
* vertically.
* @return {Array} New layout.
*/
export function findOrGenerateResponsiveLayout (orgLayout, layouts, breakpoints, breakpoint, lastBreakpoint, cols, verticalCompact) {
// If it already exists, just return it.
if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint])
// Find or generate the next layout
let layout = orgLayout
const breakpointsSorted = sortBreakpoints(breakpoints)
const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint))
for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
const b = breakpointsAbove[i]
if (layouts[b]) {
layout = layouts[b]
break
}
}
layout = cloneLayout(layout || []) // clone layout so we don't modify existing items
return compact(correctBounds(layout, { cols: cols }), verticalCompact)
}
export function generateResponsiveLayout (layout, breakpoints, breakpoint, lastBreakpoint, cols, verticalCompact) {
// If it already exists, just return it.
/* if (layouts[breakpoint]) return cloneLayout(layouts[breakpoint]);
// Find or generate the next layout
let layout = layouts[lastBreakpoint]; */
/* const breakpointsSorted = sortBreakpoints(breakpoints);
const breakpointsAbove = breakpointsSorted.slice(breakpointsSorted.indexOf(breakpoint));
for (let i = 0, len = breakpointsAbove.length; i < len; i++) {
const b = breakpointsAbove[i];
if (layouts[b]) {
layout = layouts[b];
break;
}
} */
layout = cloneLayout(layout || []) // clone layout so we don't modify existing items
return compact(correctBounds(layout, { cols: cols }), verticalCompact)
}
/**
* Given breakpoints, return an array of breakpoints sorted by width. This is usually
* e.g. ['xxs', 'xs', 'sm', ...]
*
* @param {Object} breakpoints Key/value pair of breakpoint names to widths.
* @return {Array} Sorted breakpoints.
*/
export function sortBreakpoints (breakpoints) {
const keys = Object.keys(breakpoints)
return keys.sort(function (a, b) {
return breakpoints[a] - breakpoints[b]
})
}

View File

@@ -518,7 +518,6 @@ export default {
}, },
props: { props: {
topologyIndexF: { topologyIndexF: {
type: Number,
default: 0 default: 0
}, },
obj: {}, obj: {},
@@ -2129,6 +2128,7 @@ export default {
flag = true flag = true
} }
}) })
getTopology(this.topologyIndex).resize()
getTopology(this.topologyIndex).centerView() getTopology(this.topologyIndex).centerView()
this.getNodesArr() this.getNodesArr()
}, 500) }, 500)