chart = {
const div = d3.create('div');
const svgChart = div.append('svg')
.attr('width', config.viewWidth)
.attr('height', config.viewHeight);
const stageChartWrapper = svgChart.append('g')
const stageChart = stageChartWrapper.append('g')
.attr("transform", `translate(${config.margin}, ${config.margin})`)
.selectAll('path')
.data(data)
.join('path')
.attr('d', lineGen)
const svgMinimap = div.append('svg')
.attr('width', config.viewWidth)
.attr('height', config.viewHeight)
.attr('viewBox', [0, 0, config._width, config._height].join(' '))
.attr('preserveAspectRatio', 'xMidYMid meet');
svgMinimap.append('rect')
.attr('width', config._width)
.attr('height', config._height)
.attr('fill', 'pink');
const stageMinimap = svgMinimap.append('g')
.attr("transform", `translate(${config.margin}, ${config.margin})`)
.selectAll('path') // 绘图也和左图一致
.data(data)
.join('path')
.attr('d', lineGen)
// 小地图的刷子
const stageBrush = svgMinimap.append('g');
// 左图的 zoom behavior
const zoom = d3.zoom()
.scaleExtent([config.minimapScale, 1]) // 缩小时刚好充满容器,放大时 1:1
.translateExtent([[0, 0], [config._width, config._height]]) // 拖动时不允许移出容器边界
// 小地图的 brush behavior
const brush = d3.brush()
.extent([[0, 0], [config._width, config._height]]) // 设定最大大小,其实已经受到左图 zoom extent 的限制了
function onBrush() {
// prevent zoom invoked event
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom")
return null;
// console.log('onBrush', d3.event);
if (Array.isArray(d3.event.selection)) {
const [[brushX, brushY], [brushX2, brushY2]] = d3.event.selection; // brush 左上角、右下角的坐标
const zoomScale = d3.zoomTransform(stageChartWrapper.node()).k; // 获取此时左图的缩放比例,为 1 表示不缩放
// console.log(svgChart)
// console.log(zoomScale)
const scaleX = minimapScaleX(zoomScale); // 一个线性变换函数,将实际坐标(也就是 brush 的坐标)换算成缩放后的坐标(也就是左图的坐标)
const scaleY = minimapScaleY(zoomScale);
// 容器设置 transform 属性,内容设置 translate 偏移
svgChart.call(
zoom.transform,
d3.zoomIdentity.translate(scaleX(-brushX), scaleY(-brushY)).scale(zoomScale)
);
stageChartWrapper.attr("transform", `translate(${scaleX(-brushX)}, ${scaleY(-brushY)}) scale(${zoomScale})`);
}
}
function onZoom() {
//prevent brush invoked event
if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") // 如果把这一行注释掉,在拖动 brush 的时候也会有 zoom 事件,即:event.type == zoom, event.sourceEvent.type == brush
return null;
// console.log('onZoom', d3.event);
const t = d3.event.transform;
stageChartWrapper.attr("transform", t); // 左图响应 zoom 事件
// brush 同步变更大小
const scaleX = minimapScaleX(t.k);
const scaleY = minimapScaleY(t.k);
brush.move(stageBrush, [
[scaleX.invert(-t.x), scaleY.invert(-t.y)],
[
scaleX.invert(-t.x + config.viewWidth),
scaleY.invert(-t.y + config.viewHeight)
]
]);
}
brush.on('brush', onBrush);
zoom.on('zoom', onZoom);
svgChart.call(zoom);
stageBrush.call(brush).call(brush.move, [ // 设置 brush 的初始大小
[0, 0],
[config.viewWidth, config.viewHeight]
]);
// svgMinimap.selectAll('.handle').remove();
// svgMinimap.selectAll('.overlay').remove();
return div.node();
}