우리의 아이디어는 불규칙한 너비의 폭포수 차트를 그리는 것이 었습니다. 직사각형을 해당 데이터 포인트 (데모 목적으로 피들에 표시)로 렌더링하여이 차트 스타일을 달성했습니다.
또한 툴팁을 추가하고이 툴팁을 마우스 다음에 만들고 싶습니다. 하이 차트 맞춤 렌더러 차트 및 툴팁
차트에 매우 가까이 확대
, 당신은 그 즉 rect2 및 rect3뿐만 아니라 rect3 표시되고 rect4는 rectangulars 가장자리 사이의 작은 차이를 보여우리는 세 가지 문제에 직면하고있다. 이것은 모든 직사각형이 같은 for-loop 절차 (바이올린의 68-84 행)에 의해 생성 되었기 때문에 이상하게 보입니다. 어떤 아이디어? (차트 너비를 변경하면 간격이 사라지거나 다른 직사각형간에 발생할 수 있습니다 ...)
첫 번째 및 마지막 사각형의 경우 개별 테두리를 만들고 싶습니다. 따라서 첫 번째와 마지막 사각형 (흰돌의 97,155 행)에 흰색 테두리를 설정하고 나중에 렌더러 경로 (점선, 실선)를 추가합니다 (221-298 줄). rect0의 경우에서 볼 수 있듯이 직사각형과 동일한 플롯 좌표를 사용했지만 세로선은 흰색 테두리를 정확히 덮지 않습니다. 우리는 렌더러 그룹 (rectangulars, dataLabels)에 사용자 지정 도구 설명을 렌더링 및 마우스 오버와로 마우스 이벤트에 의해 이러한 표시
(차트 폭을 변경하는 경우, 문제의 크기는 더 나은 또는 악화). 첫 번째 문제는 dataLabel을 가리키면 툴팁이 사라 졌다는 것입니다. 해결 방법을 만들었지 만 (190-195 줄) rect와 레이블 모두에 툴팁을 표시하는보다 세련된 방법이 있는지 궁금해하고 있습니다. 또한 툴팁이 마우스 움직임 (이벤트 mousemove)을 따르기를 원하지만이 이벤트가 우리의 예제에서 작동하도록 할 수는 없습니다.
$(function() { var chart = new Highcharts.Chart({ chart: { renderTo: 'container', type: 'scatter' }, title: { text: 'Custom waterfall with unequal width' }, xAxis: { min: 0, max: 50, reversed: true }, yAxis: { title: { text: 'Share' }, min: 0, max: 100 }, tooltip: { enabled: false }, legend: { enabled: false }, credits: { enabled: false }, series: [{ name: 'basicData', visible: true, //for demonstration purpose data: [ [50, 40], [45, 48], [39, 52], [33, 68], [22, 75], [15, 89], [5, 100] ] }] }, //add function for custom renderer function (chart) { var points = this.series[0].data, addMarginX = this.plotLeft, addMarginY = this.plotTop, xZero = this.series[0].points[0].plotX, yZero = this.chartHeight - addMarginY - this.yAxis[0].bottom, xAll = [], yAll = [], widthAll = [], heightAll = []; //renderer group for all rectangulars rectGroup = chart.renderer.g() .attr({ zIndex: 5 }) .add(); //draw for each point a rectangular for (var i = 0; i < points.length; i++) { var x = points[i].plotX + addMarginX, y = points[i].plotY + addMarginY, width, height; if (i === 0) { //for the first rect height is defined by pixel difference of yAxis and yValue height = yZero - points[i].plotY } else { // else height is pixel difference of yValue and preceeding yValue height = points[i - 1].plotY - points[i].plotY }; if (i === points.length - 1) { // for the last rectangular pixel difference of xValue and xAxis at point=0 width = this.xAxis[0].translate(0) - points[i].plotX } else { // else pixel difference of xValue and subsequent xValue width = points[i + 1].plotX - points[i].plotX }; xAll.push(x); yAll.push(y); widthAll.push(width); heightAll.push(height); //general styling of rects, exception for first and last rect var attrOptions; if (i === 0) { attrOptions = { id: i, 'stroke-width': 0.75, stroke: 'rgb(255, 255, 255)', //white border which is later covered by dotted lines fill: { linearGradient: { x1: 1, y1: 0, x2: 0, y2: 0 }, stops: [ [0, Highcharts.getOptions().colors[0]], [1, 'rgba(255,255,255,0.5)'] ] } }; } else if (i === points.length - 1) { attrOptions = { id: i, 'stroke-width': 0.75, stroke: 'rgb(255, 255, 255)', //white border which is later covered by dotted lines fill: { linearGradient: { x1: 0, y1: 0, x2: 1, y2: 0 }, stops: [ [0, Highcharts.getOptions().colors[0]], [1, 'rgba(255,255,255,0.5)'] ] } }; } else { attrOptions = { id: i, 'stroke-width': 0.75, stroke: 'black', fill: Highcharts.getOptions().colors[0] }; } // draw rect, y-position is set to yAxis for animation var tempRect = chart.renderer.rect(x, this.chartHeight - this.yAxis[0].bottom, width, 0, 0) .attr(attrOptions) .add(rectGroup); //animate rect tempRect.animate({ y: y, height: height }, { duration: 1000 }); }; // for loop ends over all rect //renderer centered dataLabels to rectangulars for (var i = 0; i < points.length; i++) { var labelColor = 'rgb(255,255,255)'; if (i === 0 || i === points.length - 1) { labelColor = '#666666' } var label = chart.renderer.label('rect' + i) .attr({ align: 'center', zIndex: 5, padding: 0 }) .css({ fontSize: '11px', color: labelColor }) .add(rectGroup); var labelBBox = label.getBBox(); label.attr({ x: xAll[i] + widthAll[i] * 0.5, y: yAll[i] + heightAll[i] * 0.5 - labelBBox.height * 0.5 }); }; // loop for dataLabels ends // add tooltip to rectangulars AND labels (rectGroup) var tooltipIndex; rectGroup.on('mouseover', function (e) { //get the active element (or is there a simpler way?) var el = (e.target.correspondingUseElement) ? e.target.correspondingUseElement : e.target; //determine with the 'id' to which dataPoint this element belongs //problem: if label is hovered, use tootltipIndex of rect var i = parseFloat(el.getAttribute('id')); if (!isNaN(i)) { tooltipIndex = i; } // render text for tooltip based on coordinates of rect text = chart.renderer.text('This could be <br>an informative text', xAll[tooltipIndex], yAll[tooltipIndex] - 30) .attr({ zIndex: 101 }) .add(); var box = text.getBBox(); //box surrounding the tool tip text border = chart.renderer.rect(box.x - 5, box.y - 5, box.width + 10, box.height + 10, 5) .attr({ fill: 'rgba(255, 255, 255, 0.95)', stroke: 'blue', 'stroke-width': 1, zIndex: 100 }) .add(); }) .on('mouseout', function() { text.destroy(); border.destroy(); }) //render first and last rect as open and partly dotted rect var M = 'M', L = 'L', pathStartSol = [], pathEndSol = [], pathStartDot = [], pathEndDot = [], y0 = this.chartHeight - this.yAxis[0].bottom, last = xAll.length - 1; pathStartDot = [ M, xAll[0], y0, L, xAll[0] + widthAll[0] * 0.6, y0, M, xAll[0], y0, L, xAll[0] + widthAll[0] * 0.6, y0, M, xAll[last] + widthAll[last] * 0.4, y0, L, xAll[last] + widthAll[last], y0, M, xAll[last] + widthAll[last] * 0.4, y0, L, xAll[last] + widthAll[last], y0]; pathStartSol = [ M, xAll[0] + widthAll[0] * 0.6, y0, L, xAll[1], y0, L, xAll[1], y0, L, xAll[0] + widthAll[0] * 0.6, y0, M, xAll[last] + widthAll[last] * 0.4, y0, L, xAll[last], y0, L, xAll[last], y0, L, xAll[last] + widthAll[last] * 0.4, y0]; pathEndDot = [ M, xAll[0], yAll[0], L, xAll[0] + widthAll[0] * 0.6, yAll[0], M, xAll[0], y0, L, xAll[0] + widthAll[0] * 0.6, y0, M, xAll[last] + widthAll[last] * 0.4, yAll[last], L, xAll[last] + widthAll[last], yAll[last], M, xAll[last] + widthAll[last] * 0.4, yAll[last - 1], L, xAll[last] + widthAll[last], yAll[last - 1]]; pathEndSol = [ M, xAll[0] + widthAll[0] * 0.6, yAll[0], L, xAll[1], yAll[0], // does not match exactly the underlying white border of rect L, xAll[1], y0, // does not match exactly the underlying white border of rect L, xAll[0] + widthAll[0] * 0.6, y0, M, xAll[last] + widthAll[last] * 0.4, yAll[last], L, xAll[last], yAll[last], L, xAll[last], yAll[last - 1], L, xAll[last] + widthAll[last] * 0.4, yAll[last - 1]]; var pathSol = chart.renderer.path(pathStartSol) .attr({ 'stroke-width': 1, stroke: 'black', zIndex: 100 }).add(); var pathDot = chart.renderer.path(pathStartDot) .attr({ 'stroke-width': 1, stroke: 'black', zIndex: 100, dashstyle: 'Dot' }).add(); pathSol.animate({ d: pathEndSol }, { duration: 1000 }); pathDot.animate({ d: pathEndDot }, { duration: 1000 }); }); });
너비가 다른가 필요합니까? 아주 처음부터 당신은 Highcharts에 대해 잘못된 데이터를 분류하지 않았고 정렬을 적용 할 때 차트가 파괴되었습니다. Highcharts에서 지원하는 간단한 폭포를 사용할 수 없습니까?참조 : http://www.highcharts.com/demo/waterfall –
다른 너비는이 종류의 차트에 필수적입니다. 따라서 기둥 형 차트를 기반으로 한 HS 폭포는 사용하거나 변경할 수 없습니다. 그래서 우리는 직사각형을 렌더링하여 폭이 다른 어떤 종류의 폭포를 만들려고 노력했습니다 ... – user2285607
그래서이 경우 데이터 정렬과 직사각형 고정으로 시작하는 것이 좋습니다. 그 후 jsFiddle을 작성하면 도움을 드리겠습니다. –