antvis / antvis/F2

多chart平移问题

Open
#1,073 5 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
8k
Forks
637
PR merge metrics
No merged PRs in 30d

Description

复现代码:

```





F2 图表组件库 - AntV




/*Fixing iframe window.innerHeight 0 issue in Safari*/ document.body
.clientHeight;




.chart-wrapper {
background-color: #101419;
}

.chart-container {
position: relative;
}

.chart-title {
width: 100%;
height: 20px;
line-height: 20px;
padding-left: 10px;
color: #676c79;
font-size: 12px;
font-weight: bold;
border-bottom: 1px solid #191e26;
}

canvas#chart {
height: 212px;
border-bottom: 1px solid #191e26;
margin-top: 16px;
}

canvas#volumn {
height: 50px;
border-bottom: 1px solid #191e26;
}

.tooltip-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 20px;
display: flex;
flex-wrap: wrap;
align-content: space-between;
visibility: hidden;
padding: 0 10px;
border-bottom: 1px solid #191e26;
background-color: #101419;
}

.tooltip-wrapper .tooltip-item {
width: 15%;
height: 16px;
line-height: 16px;
vertical-align: middle;
}

.tooltip-wrapper .tooltip-item.last {
width: 40%;
}

.tooltip-wrapper .tooltip-item span {
display: inline;
color: #899198;
font-size: 12px;
}

.tooltip-wrapper .tooltip-item span.item-value {
font-weight: bold;
}

#barTooltip .tooltip-item {
width: 100%;
}

.ma-wrapper {
position: absolute;
top: 20px;
visibility: hidden;
width: 100%;
height: 16px;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
padding: 0 10px 0 8px;
border-bottom: 1px solid #191e26;
background-color: #101419;
}

.ma-wrapper .tooltip-item {
width: auto;
height: 16px;
line-height: 16px;
vertical-align: middle;
font-size: 10px;
transform: scale(0.83);
}

.ma-wrapper .tooltip-item.first {
width: 7%;
}

.ma-wrapper .tooltip-item.first span {
background: #676c79;
padding: 0 4px;
}

.ma-wrapper .tooltip-item span {
display: inline;
color: #899198;
}



日 K



















成交





MA


5:



10:



20:



30:






成交量



成交量:






数据纯属虚构


手机扫码,体验更佳



var COLOR_MAP = ['#FF4433', '#32A532']; // 涨跌
var barChart = void 0;
var kChart = void 0;
// let min = null;
// let max = null;

function updateMATip(data, index) {
var currItem = data[index];
$('#ma .item-value').each(function (index, ele) {
var type = $(ele).data('type');
var value = currItem[type];
$(ele).text(value);
});
$('#ma').css('visibility', 'visible');
}

function getMinAndMax(data = [], currentValues = []) {
if (!data.length || !currentValues.length) {
return [null, null];
}

const firstIndex = data.findIndex(
(i) =>
i.reportDate === currentValues[0] ||
F2.Util.toTimeStamp(i.reportDate) === currentValues[0]
);
const lastIndex = data.findIndex(
(i) =>
i.reportDate === currentValues[currentValues.length - 1] ||
F2.Util.toTimeStamp(i.reportDate) ===
currentValues[currentValues.length - 1]
);

const currentData = data.slice(firstIndex, lastIndex + 1);
const result = currentData.reduce(
(result, current) => {
const minGroup = [
current.low,
current.MA5,
current.MA10,
current.MA20,
current.MA30,
];
const maxGroup = [
current.high,
current.MA5,
current.MA10,
current.MA20,
current.MA30,
];

if (!result[0] || !result[1]) {
const theMin = Math.min(...minGroup);
const theMax = Math.max(...maxGroup);
return [theMin, theMax];
}

const theMin = Math.min(...minGroup, result[0]);
const theMax = Math.max(...maxGroup, result[1]);
return [theMin, theMax];
},
[null, null]
);

return result;
}

function toDate(value) {
const d = new Date(value);
const years = d.getFullYear();
const months = `0${d.getMonth() + 1}`;
const days = `0${d.getDate()}`;
return `${years}-${months.substr(-2)}-${days.substr(-2)}`;
}

$.getJSON(
'https://gw.alipayobjects.com/os/antvdemo/assets/data/f2/1d-k.json',
function (data) {
// 构造数据结构
var reportDates = [];
data.forEach(function (obj) {
reportDates.push(obj.reportDate);
obj.range = [obj.start, obj.end, obj.high, obj.low];
obj.trend = obj.start <= obj.end ? 0 : 1; // 0 表示涨,1 表示跌
});
var firstShowDates = reportDates.slice(75); // 首屏展示的日期
// 绘制 K 线图
kChart = drawKChart(data, firstShowDates, reportDates);
// 绘制成交量柱状图
barChart = drawBarChart(data, firstShowDates);
}
);

// 绘制成交量柱状图
function drawBarChart(data, firstShowDates) {
const chart = new F2.Chart({
id: 'volumn',
padding: [0, 0, 6],
pixelRatio: window.devicePixelRatio,
});
chart.source(data, {
reportDate: {
type: 'timeCat',
values: firstShowDates,
},
});
chart.axis(false);
chart.tooltip({
alwaysShow: true,
showCrosshairs: true,
crosshairsStyle: {
stroke: '#D1D3D4',
lineWidth: 1,
},
showTooltipMarker: false,
custom: true,
onChange: function onChange(obj) {
var currentPoint = {
x: obj.x,
y: obj.y,
};
kChart.showTooltip(currentPoint);
var data = obj.items[0].origin;
$('#barTooltip .item-value').each(function (index, ele) {
var type = $(ele).data('type');
var value = data[type];
$(ele).css({
color: '#FFFFFF',
});
$(ele).text(value);
});
$('#barTooltip').css('visibility', 'visible');
},
onHide: function onHide() {
$('#barTooltip').css('visibility', 'hidden');
},
});
chart
.interval()
.position('reportDate*volumn')
.color('trend', function (val) {
return COLOR_MAP[val];
});
// chart.interaction('pinch', {
// maxScale: 25,
// onProcess: function onProcess() {
// if (this.pressed) return;
// var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
// kChart.scale('reportDate', {
// type: 'timeCat',
// values: currentValues,
// ticks: [
// '2018-06-08',
// '2018-07-02',
// '2018-08-01',
// '2018-09-03',
// '2018-10-08',
// '2018-11-01',
// ],
// });
// kChart.repaint();
// },
// onEnd: function onEnd() {
// kChart.hideTooltip();
// chart.hideTooltip();
// },
// });
chart.interaction('pan', {
onProcess: function onProcess() {
if (this.pressed) return;
var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values

const [min, max] = getMinAndMax(data, currentValues);
// const newValues = currentValues.map((i) => toDate(i));
kChart.scale('reportDate', {
type: 'timeCat',
values: currentValues,
// ticks: [
// '2018-06-08',
// '2018-07-02',
// '2018-08-01',
// '2018-09-03',
// '2018-10-08',
// '2018-11-01',
// ],
});
kChart.scale('range', {
max,
min,
});
kChart.scale('MA5', {
max,
min,
});
kChart.scale('MA10', {
max,
min,
});
kChart.scale('MA20', {
max,
min,
});
kChart.scale('MA30', {
max,
min,
});
kChart.repaint();
},
onEnd: function onEnd() {
kChart.hideTooltip();
chart.hideTooltip();
kChart.repaint();
},
});
// // 添加进度条
// chart.scrollBar({
// mode: 'x',
// xStyle: {
// backgroundColor: 'rgba(202, 215, 239, .2)',
// fillerColor: '#818991',
// size: 4,
// lineCap: 'square',
// offsetX: 0,
// offsetY: 1,
// },
// });
chart.render();
return chart;
}

function drawKChart(data, firstShowDates, allDates) {
const [firstMin, firstMax] = getMinAndMax(data, firstShowDates);
const chart = new F2.Chart({
id: 'chart',
padding: [0, 0, 18],
pixelRatio: window.devicePixelRatio,
syncY: true,
});
chart.source(data, {
reportDate: {
type: 'timeCat',
ticks: [
'2018-06-08',
'2018-07-02',
'2018-08-01',
'2018-09-03',
'2018-10-08',
'2018-11-01',
],
values: firstShowDates,
sortable: false,
},
range: {
nice: false,
max: firstMax,
min: firstMin,
},
MA5: {
nice: false,
max: firstMax,
min: firstMin,
},
MA10: {
nice: false,
max: firstMax,
min: firstMin,
},
MA20: {
nice: false,
max: firstMax,
min: firstMin,
},
MA30: {
nice: false,
max: firstMax,
min: firstMin,
},
});
chart.axis('reportDate', {
labelOffset: 1,
label: function label(text, index, total) {
var textAlign = 'center';
if (index === 0) {
textAlign = 'start';
} else if (index === total - 1) {
textAlign = 'end';
}
return {
text: text.slice(0, 7),
fill: '#818991',
textAlign: textAlign,
};
},

line: {
stroke: '#181D26',
},
grid: {
lineWidth: 1,
stroke: '#181D26',
},
});
chart.axis('range', {
line: {
stroke: '#181D26',
},
grid: {
stroke: '#181D26',
},
labelOffset: -2,
label: function label(text, index, total) {
var cfg = {
textAlign: 'start',
text: parseFloat(text).toFixed(2),
fill: '#818991',
};
if (index === 0) {
cfg.textBaseline = 'bottom';
} else if (index === total - 1) {
cfg.textBaseline = 'top';
}
return cfg;
},
});
chart.axis('MA5', false);
chart.axis('MA10', false);
chart.axis('MA20', false);
chart.axis('MA30', false);
chart.tooltip({
showTooltipMarker: false,
alwaysShow: true,
showCrosshairs: true,
crosshairsType: 'xy',
showXTip: true,
showYTip: true,
crosshairsStyle: {
stroke: '#D1D3D4',
lineWidth: 1,
},
xTip: {
fill: '#80888F',
fontSize: 10,
},
yTip: function yTip(val) {
return {
fill: '#80888F',
fontSize: 10,
text: val.toFixed(3),
};
},

xTipBackground: {
fill: '#232C39',
fillOpacity: 0.75,
radius: 2,
},
yTipBackground: {
fill: '#232C39',
fillOpacity: 0.75,
radius: 2,
},
custom: true,
onChange: function onChange(obj) {
var currentPoint = {
x: obj.x,
y: obj.y,
};
barChart.showTooltip(currentPoint);
var currData = obj.items[0].origin;
$('#kTooltip .item-value').each(function (index, ele) {
var type = $(ele).data('type');
var value = currData[type];
var color = void 0;
if (type === 'volumn') {
color = '#FFF';
} else {
color = currData.trend === 0 ? COLOR_MAP[0] : COLOR_MAP[1];
}
$(ele).css({
color: color,
});
$(ele).text(value);
});
$('#kTooltip').css('visibility', 'visible');

updateMATip(data, allDates.indexOf(currData.reportDate));
},
onHide: function onHide() {
$('#kTooltip').css('visibility', 'hidden');
$('#ma').css('visibility', 'hidden');
},
});
chart
.schema()
.position('reportDate*range')
.color('trend', function (val) {
return COLOR_MAP[val];
})
.shape('candle');
chart
.line()
.position('reportDate*MA5')
.color('#C6268B')
.size(1)
.animate(false);
chart
.line()
.position('reportDate*MA10')
.color('#D7A429')
.size(1)
.animate(false);
chart
.line()
.position('reportDate*MA20')
.color('#227BAF')
.size(1)
.animate(false);
chart
.line()
.position('reportDate*MA30')
.color('#6960C4')
.size(1)
.animate(false);

// chart.interaction('pinch', {
// maxScale: 25,
// onProcess: function onProcess() {
// if (this.pressed) return;

// var currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
// barChart.scale('reportDate', {
// type: 'timeCat',
// values: currentValues,
// });
// barChart.repaint();
// },
// onEnd: function onEnd() {
// barChart.hideTooltip();
// chart.hideTooltip();
// },
// });
chart.interaction('pan', {
onStart: function onStart() {},
onProcess: function onProcess() {
if (this.pressed) return; // TODO, 这个标识位好恶心

const currentValues = chart.getXScale().values; // 获取平移后的当前展示 values
// const newValues = currentValues.map((i) => toDate(i));
barChart.scale('reportDate', {
type: 'timeCat',
values: currentValues,
});
barChart.repaint();

const [min, max] = getMinAndMax(data, currentValues);

const yScales = chart.getYScales();
yScales.forEach((item) => {
this.updateLinearScale(item.field, min, max);
});
},
onEnd: function onEnd() {
barChart.hideTooltip();
chart.hideTooltip();
barChart.repaint();
},
});
chart.render();
return chart;
}

```

复现步骤:
滑动"蜡烛图", 再滑动"条形图", 这时候"蜡烛图"显示就不完整了. 反之也是一样, 只有一直滑同一个chart才正常

Contributor guide

Open the contributing guide

Research direction

Start with the supplied HTML reproduction using F2 3.7.8, then inspect drawBarChart's pan interaction, getMinAndMax, and the calls that update kChart. Compare both chart instances while panning; done means the linked charts remain synchronized without the reported multi-chart pan problem.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
data-visualization
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.