mirror of
https://gitee.com/antv/g6.git
synced 2024-12-15 18:11:08 +08:00
311 lines
7.9 KiB
JavaScript
311 lines
7.9 KiB
JavaScript
|
/**
|
|||
|
* @fileOverview minimap
|
|||
|
* @author huangtonger@aliyun.com
|
|||
|
*/
|
|||
|
const G6 = require('@antv/g6');
|
|||
|
const { Util, G } = G6;
|
|||
|
const Canvas = G.Canvas;
|
|||
|
|
|||
|
class Minimap {
|
|||
|
constructor(options) {
|
|||
|
Util.mix(this, {
|
|||
|
/**
|
|||
|
* 类型
|
|||
|
* @type {string}
|
|||
|
*/
|
|||
|
type: 'minimap',
|
|||
|
|
|||
|
/**
|
|||
|
* dom 容器
|
|||
|
* @type {dom}
|
|||
|
*/
|
|||
|
container: null,
|
|||
|
|
|||
|
/**
|
|||
|
* 是否是缩略图
|
|||
|
* @type {boolean}
|
|||
|
*/
|
|||
|
isMinimap: true,
|
|||
|
|
|||
|
/**
|
|||
|
* 背景样式
|
|||
|
* @type {CSS}
|
|||
|
*/
|
|||
|
backgroundCSS: {
|
|||
|
height: '100%',
|
|||
|
position: 'absolute',
|
|||
|
margin: 'auto',
|
|||
|
left: 0,
|
|||
|
right: 0,
|
|||
|
'z-index': 0
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 容器样式
|
|||
|
* @type {CSS}
|
|||
|
*/
|
|||
|
minimapContainerCSS: {
|
|||
|
background: '#fff',
|
|||
|
position: 'relative',
|
|||
|
overflow: 'hidden'
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 缩略图视口框
|
|||
|
* @type {CSS}
|
|||
|
*/
|
|||
|
viewportCSS: {
|
|||
|
height: '100%',
|
|||
|
position: 'absolute',
|
|||
|
margin: 'auto',
|
|||
|
left: 0,
|
|||
|
right: 0,
|
|||
|
'z-index': 1
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 控制图层
|
|||
|
* @type {CSS}
|
|||
|
*/
|
|||
|
controlLayerCSS: {
|
|||
|
width: '100%',
|
|||
|
height: '100%',
|
|||
|
cursor: 'move',
|
|||
|
position: 'absolute',
|
|||
|
'z-index': 2
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 缩略图可视区域视窗样式
|
|||
|
* @type {G.Rect.ATTRS}
|
|||
|
*/
|
|||
|
viewportWindowStyle: {
|
|||
|
stroke: '#91D5FF'
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 缩略图背景样式
|
|||
|
* @type {G.Rect.ATTRS}
|
|||
|
*/
|
|||
|
viewportBackStyle: {
|
|||
|
fill: '#EBEEF2',
|
|||
|
fillOpacity: 0.65
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 获取 G6 图
|
|||
|
* @type {funtion}
|
|||
|
*/
|
|||
|
getGraph() {
|
|||
|
|
|||
|
},
|
|||
|
...options
|
|||
|
});
|
|||
|
this._initContainer();
|
|||
|
this._initMiniMap();
|
|||
|
this._bindEvent();
|
|||
|
}
|
|||
|
_bindEvent() {
|
|||
|
const controlLayer = this.controlLayer;
|
|||
|
let miniMapViewPortActived = false;
|
|||
|
let startMatrix;
|
|||
|
let miniMapScale;
|
|||
|
let graphScale;
|
|||
|
let startPoint;
|
|||
|
let graph;
|
|||
|
controlLayer.on('mousedown', ev => {
|
|||
|
if (!this.miniMapMatrix) {
|
|||
|
return;
|
|||
|
}
|
|||
|
graph = this.getGraph();
|
|||
|
miniMapViewPortActived = true;
|
|||
|
startMatrix = Util.cloneDeep(graph.getMatrix());
|
|||
|
miniMapScale = this.miniMapMatrix[0];
|
|||
|
graphScale = startMatrix[0];
|
|||
|
startPoint = {
|
|||
|
clientX: ev.clientX,
|
|||
|
clientY: ev.clientY
|
|||
|
};
|
|||
|
});
|
|||
|
controlLayer.on('mouseup', () => {
|
|||
|
resetStatus();
|
|||
|
});
|
|||
|
controlLayer.on('mouseleave', () => {
|
|||
|
resetStatus();
|
|||
|
});
|
|||
|
controlLayer.on('mousemove', ev => {
|
|||
|
if (miniMapViewPortActived && graph) {
|
|||
|
const dx = startPoint.clientX - ev.clientX;
|
|||
|
const dy = startPoint.clientY - ev.clientY;
|
|||
|
const matrix = Util.cloneDeep(startMatrix);
|
|||
|
Util.mat3.translate(matrix, matrix, [ graphScale * dx / miniMapScale, graphScale * dy / miniMapScale ]);
|
|||
|
graph.updateMatrix(matrix);
|
|||
|
}
|
|||
|
});
|
|||
|
function resetStatus() {
|
|||
|
miniMapViewPortActived = false;
|
|||
|
miniMapScale = undefined;
|
|||
|
startPoint = undefined;
|
|||
|
startMatrix = undefined;
|
|||
|
graphScale = undefined;
|
|||
|
graph = undefined;
|
|||
|
}
|
|||
|
}
|
|||
|
_initMiniMap() {
|
|||
|
const background = this.background;
|
|||
|
const viewport = this.viewPort;
|
|||
|
const width = this.width;
|
|||
|
const height = this.height;
|
|||
|
const viewportWindowStyle = this.viewportWindowStyle;
|
|||
|
const viewportBackStyle = this.viewportBackStyle;
|
|||
|
const miniMapCanvas = new Canvas({
|
|||
|
containerDOM: background,
|
|||
|
width,
|
|||
|
height
|
|||
|
});
|
|||
|
const viewportCanvas = new Canvas({
|
|||
|
containerDOM: viewport,
|
|||
|
width,
|
|||
|
height
|
|||
|
});
|
|||
|
const viewportWindow = viewportCanvas.addShape('rect', {
|
|||
|
attrs: {
|
|||
|
x: 0,
|
|||
|
y: 0,
|
|||
|
width,
|
|||
|
height,
|
|||
|
...viewportWindowStyle
|
|||
|
}
|
|||
|
});
|
|||
|
const viewportBack = viewportCanvas.addShape('path', {
|
|||
|
attrs: {
|
|||
|
path: 'M0,0 L1,1',
|
|||
|
...viewportBackStyle
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
background.css({
|
|||
|
width: width + 'px',
|
|||
|
height: height + 'px'
|
|||
|
});
|
|||
|
viewport.css({
|
|||
|
position: 'absolute'
|
|||
|
});
|
|||
|
this.miniMapCanvas = miniMapCanvas;
|
|||
|
this.viewportCanvas = viewportCanvas;
|
|||
|
this.viewportWindow = viewportWindow;
|
|||
|
this.viewportBack = viewportBack;
|
|||
|
}
|
|||
|
_initContainer() {
|
|||
|
let container = this.container;
|
|||
|
let width = this.width;
|
|||
|
let height = this.height;
|
|||
|
if (container) {
|
|||
|
if (Util.isString(container)) {
|
|||
|
container = document.getElementById(container);
|
|||
|
}
|
|||
|
} else {
|
|||
|
throw new Error('please set the container for the minimap !');
|
|||
|
}
|
|||
|
if (!width) {
|
|||
|
width = Util.getWidth(container);
|
|||
|
}
|
|||
|
if (!height) {
|
|||
|
height = Util.getHeight(container);
|
|||
|
}
|
|||
|
const minimapContainerCSS = this.minimapContainerCSS;
|
|||
|
minimapContainerCSS.width = width + 'px';
|
|||
|
minimapContainerCSS.height = height + 'px';
|
|||
|
const backgroundCSS = this.backgroundCSS;
|
|||
|
const viewportCSS = this.viewportCSS;
|
|||
|
const controlLayerCSS = this.controlLayerCSS;
|
|||
|
const minimapContainer = Util.createDOM('<div class="g6-editor-minimap-container"></div>', minimapContainerCSS);
|
|||
|
const background = Util.createDOM('<div class="g6-editor-minimap-background"></div>', backgroundCSS);
|
|||
|
const viewPort = Util.createDOM('<div class="g6-editor-minimap-viewport">', viewportCSS);
|
|||
|
const controlLayer = Util.createDOM('<div class="g6-editor-minimap-control-layer">', controlLayerCSS);
|
|||
|
container.appendChild(minimapContainer);
|
|||
|
minimapContainer.appendChild(controlLayer);
|
|||
|
minimapContainer.appendChild(viewPort);
|
|||
|
minimapContainer.appendChild(background);
|
|||
|
this.minimapContainer = minimapContainer;
|
|||
|
this.background = background;
|
|||
|
this.viewPort = viewPort;
|
|||
|
this.controlLayer = controlLayer;
|
|||
|
}
|
|||
|
// 1. 为了防止画面闪烁 2. 为了缩略图中元素最小尺寸可控;所以这里采取了一种比较 hack 的方式绘制缩略图
|
|||
|
// 大体思路是将 graph canvas 的 context 篡改为 minimap canvas 的 context,然后用 graph 的 canvas 去画
|
|||
|
renderBackground(graph) {
|
|||
|
if (!graph) {
|
|||
|
graph = this.getGraph();
|
|||
|
}
|
|||
|
const miniMapCanvas = this.miniMapCanvas;
|
|||
|
const width = this.width;
|
|||
|
const height = this.height;
|
|||
|
Util.graph2Canvas({
|
|||
|
graph,
|
|||
|
width,
|
|||
|
height,
|
|||
|
canvas: miniMapCanvas
|
|||
|
});
|
|||
|
this.miniMapMatrix = miniMapCanvas.matrix;
|
|||
|
}
|
|||
|
renderViewPort(graph) {
|
|||
|
if (!graph) {
|
|||
|
graph = this.getGraph();
|
|||
|
}
|
|||
|
if (graph.getItems().length === 0) {
|
|||
|
return;
|
|||
|
}
|
|||
|
const viewportWindow = this.viewportWindow;
|
|||
|
const viewportCanvas = this.viewportCanvas;
|
|||
|
const viewportBack = this.viewportBack;
|
|||
|
const miniMapMatrix = this.miniMapMatrix;
|
|||
|
const graphWidth = graph.getWidth();
|
|||
|
const graphHeight = graph.getHeight();
|
|||
|
const width = this.width;
|
|||
|
const height = this.height;
|
|||
|
const graphMatrix = graph.getMatrix();
|
|||
|
if (!miniMapMatrix) {
|
|||
|
return;
|
|||
|
}
|
|||
|
const graphTL = Util.invertMatrix({
|
|||
|
x: 0,
|
|||
|
y: 0
|
|||
|
}, graphMatrix);
|
|||
|
const graphBR = Util.invertMatrix({
|
|||
|
x: graphWidth,
|
|||
|
y: graphHeight
|
|||
|
}, graphMatrix);
|
|||
|
const viewPortTL = Util.applyMatrix(graphTL, miniMapMatrix);
|
|||
|
const viewPortBR = Util.applyMatrix(graphBR, miniMapMatrix);
|
|||
|
const windowWidth = viewPortBR.x - viewPortTL.x;
|
|||
|
const windowHeight = viewPortBR.y - viewPortTL.y;
|
|||
|
viewportBack.attr({
|
|||
|
path: [
|
|||
|
[ 'M', 0, 0 ],
|
|||
|
[ 'L', width, 0 ],
|
|||
|
[ 'L', width, height ],
|
|||
|
[ 'L', 0, height ],
|
|||
|
[ 'L', 0, 0 ],
|
|||
|
[ 'M', viewPortTL.x, viewPortTL.y ],
|
|||
|
[ 'L', viewPortTL.x, viewPortBR.y ],
|
|||
|
[ 'L', viewPortBR.x, viewPortBR.y ],
|
|||
|
[ 'L', viewPortBR.x, viewPortTL.y ],
|
|||
|
[ 'L', viewPortTL.x, viewPortTL.y ]
|
|||
|
]
|
|||
|
});
|
|||
|
viewportWindow.attr({
|
|||
|
x: viewPortTL.x,
|
|||
|
y: viewPortTL.y,
|
|||
|
width: windowWidth,
|
|||
|
height: windowHeight
|
|||
|
});
|
|||
|
viewportCanvas.draw();
|
|||
|
}
|
|||
|
destroy() {
|
|||
|
this.minimapContainer.destroy();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
module.exports = Minimap;
|