Skip to content

Commit

Permalink
[#925] [3.0] Chart - Plot line
Browse files Browse the repository at this point in the history
#####################
1. plot line 옵션 처리 로직 추가
  • Loading branch information
jhee564 committed Oct 25, 2021
1 parent 2a288eb commit c8bb949
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 18 deletions.
17 changes: 17 additions & 0 deletions src/components/chart/helpers/helpers.constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,23 @@ export const AXIS_OPTION = {
},
};

export const PLOT_LINE_OPTION = {
color: '#FF0000',
lineWidth: 1,
};

export const PLOT_LINE_LABEL_OPTION = {
fontSize: 12,
fontColor: '#FF0000',
fillColor: '#FFFFFF',
lineColor: '#FF0000',
lineWidth: 0,
fontWeight: 400,
fontFamily: 'Roboto',
verticalAlign: 'middle',
textAlign: 'center',
};

export const TIME_INTERVALS = {
millisecond: {
common: true,
Expand Down
263 changes: 245 additions & 18 deletions src/components/chart/scale/scale.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import Canvas from '@/components/chart/helpers/helpers.canvas';
import { defaultsDeep } from 'lodash-es';
import { AXIS_OPTION, AXIS_UNITS } from '../helpers/helpers.constant';
import {
AXIS_OPTION,
AXIS_UNITS,
PLOT_LINE_OPTION,
PLOT_LINE_LABEL_OPTION,
} from '../helpers/helpers.constant';
import Util from '../helpers/helpers.util';

class Scale {
Expand Down Expand Up @@ -278,37 +284,258 @@ class Scale {
ctx.closePath();
}

// draw plot line
// Draw plot line
if (this.plotLines?.length) {
const xArea = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
const yArea = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
const padding = aliasPixel + 1;
const minX = aPos.x1 + padding;
const maxX = aPos.x2;
const minY = aPos.y1 + padding;
const maxY = aPos.y2;

this.plotLines.forEach((plotLine) => {
const { color, lineWidth, lineStyle, value } = plotLine;
ctx.beginPath();
ctx.save();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;

if (lineStyle === 'dash') {
ctx.setLineDash([10, 5]);
if (!plotLine.value) {
return;
}

const mergedPlotLineOpt = defaultsDeep({}, plotLine, PLOT_LINE_OPTION);
const { value, label: labelOpt } = mergedPlotLineOpt;

this.setPlotLineStyle(mergedPlotLineOpt);

if (this.type === 'x') {
const dp = aPos.x1 + value;
ctx.moveTo(dp, aPos.y2 + padding);
ctx.lineTo(dp, aPos.y1 + padding);
const dataX = Canvas.calculateX(value, axisMin, axisMax, xArea, minX);
this.drawXPlotLine(dataX, minX, maxX, minY, maxY, labelOpt);
} else {
const dp = aPos.y2 - value;
ctx.moveTo(aPos.x1 + padding, dp);
ctx.lineTo(aPos.x2 + padding, dp);
const dataY = Canvas.calculateY(value, axisMin, axisMax, yArea, maxY);
this.drawYPlotLine(dataY, minX, maxX, minY, maxY, labelOpt);
}

ctx.stroke();
ctx.restore();
ctx.closePath();
});
}
}

/**
* Set plot line style
* @param {object} plotLine plotLine Options
*
* @returns {undefined}
*/
setPlotLineStyle(plotLine) {
const ctx = this.ctx;
const { color, lineWidth } = plotLine;

ctx.beginPath();
ctx.save();
ctx.lineWidth = lineWidth;
ctx.strokeStyle = color;

if (plotLine.segments) {
ctx.setLineDash(plotLine.segments);
}
}

/**
* Draw X Plot line
* @param {object} dataX Data's X Position
* @param {number} minX Min X Position
* @param {number} maxX Max X Position
* @param {number} minY Min Y Position
* @param {number} maxY Max Y Position
* @param {object} labelOpt plotLine Options
*
* @returns {undefined}
*/
drawXPlotLine(dataX, minX, maxX, minY, maxY, labelOpt) {
const ctx = this.ctx;

if (!dataX || dataX < minX || dataX > maxX) {
ctx.closePath();
ctx.restore();
return;
}

ctx.moveTo(dataX, maxY);
ctx.lineTo(dataX, minY);

ctx.stroke();
ctx.restore();
ctx.closePath();

if (labelOpt) {
const mergedLabelOpt = defaultsDeep({}, labelOpt, PLOT_LINE_LABEL_OPTION);

ctx.save();
ctx.beginPath();
ctx.font = Util.getLabelStyle(mergedLabelOpt);

const {
fontSize,
labelBoxPadding,
labelHalfWidth,
} = this.getLabelParameters(mergedLabelOpt);

if (fontSize <= 0) {
return;
}

let textX;
switch (mergedLabelOpt.textAlign) {
case 'left':
textX = dataX - labelHalfWidth - labelBoxPadding;
break;

case 'right':
textX = dataX + labelHalfWidth + labelBoxPadding;
break;

case 'center':
default:
textX = dataX;
break;
}

const textY = minY - labelBoxPadding - fontSize;

this.drawPlotLineLabel(mergedLabelOpt, {
top: minY - (labelBoxPadding * 2) - fontSize,
bottom: minY - labelBoxPadding,
left: textX - labelHalfWidth - labelBoxPadding,
right: textX + labelHalfWidth + labelBoxPadding,
x: textX,
y: textY,
});
}
}

/**
* Draw Y Plot line
* @param {object} dataY Data's Y Position
* @param {number} minX Min X Position
* @param {number} maxX Max X Position
* @param {number} minY Min Y Position
* @param {number} maxY Max Y Position
* @param {object} labelOpt plotLine Options
*
* @returns {undefined}
*/
drawYPlotLine(dataY, minX, maxX, minY, maxY, labelOpt) {
const ctx = this.ctx;

if (!dataY || dataY > maxY || dataY < minY) {
ctx.closePath();
ctx.restore();
return;
}

ctx.moveTo(minX, dataY);
ctx.lineTo(maxX, dataY);

ctx.stroke();
ctx.restore();
ctx.closePath();

if (labelOpt) {
const mergedLabelOpt = defaultsDeep({}, labelOpt, PLOT_LINE_LABEL_OPTION);

ctx.save();
ctx.beginPath();
ctx.font = Util.getLabelStyle(mergedLabelOpt);

const {
fontSize,
labelWidth,
labelHalfHeight,
labelBoxPadding,
} = this.getLabelParameters(mergedLabelOpt);

if (fontSize <= 0) {
return;
}

let textY;
switch (mergedLabelOpt.verticalAlign) {
case 'top':
textY = dataY - labelHalfHeight - labelBoxPadding;
break;

case 'bottom':
textY = dataY + labelHalfHeight + labelBoxPadding;
break;

case 'middle':
default:
textY = dataY;
break;
}

const textX = maxX + labelWidth + labelBoxPadding;

this.drawPlotLineLabel(mergedLabelOpt, {
top: textY - labelHalfHeight - labelBoxPadding,
bottom: textY + labelHalfHeight + labelBoxPadding,
left: textX - labelWidth - (labelBoxPadding / 2),
right: textX + labelBoxPadding,
x: textX,
y: textY,
});
}
}

/**
* Calculate Values for drawing label
* @param {object} labelOpt plotLine Options
*
* @returns {object}
*/
getLabelParameters(labelOpt) {
const ctx = this.ctx;
const fontSize = labelOpt.fontSize > 20 ? 20 : labelOpt.fontSize;
const labelBoxPadding = fontSize / 4;
const labelWidth = ctx.measureText(labelOpt.text).width;
const labelHalfWidth = labelWidth / 2;
const labelHalfHeight = fontSize / 2;

return {
fontSize,
labelBoxPadding,
labelWidth,
labelHalfWidth,
labelHalfHeight,
};
}

/**
* Calculate Values for drawing label
* @param {object} labelOpt plot line Label Options
* @param {object} positions label positions
*
* @returns {undefined}
*/
drawPlotLineLabel(labelOpt, positions) {
const ctx = this.ctx;
const { top, bottom, left, right, x, y } = positions;

ctx.fillStyle = labelOpt.fillColor;
ctx.strokeStyle = labelOpt.lineColor;
ctx.lineWidth = labelOpt.lineWidth;
ctx.moveTo(left, bottom);
ctx.lineTo(left, top);
ctx.lineTo(right, top);
ctx.lineTo(right, bottom);
ctx.lineTo(left, bottom);
ctx.fill();

if (labelOpt.lineWidth > 0) {
ctx.stroke();
}

ctx.fillStyle = labelOpt.fontColor;
ctx.fillText(labelOpt.text, x, y);
ctx.closePath();
}
}

export default Scale;
31 changes: 31 additions & 0 deletions src/components/chart/scale/scale.step.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { defaultsDeep } from 'lodash-es';
import { PLOT_LINE_OPTION } from '@/components/chart/helpers/helpers.constant';
import Scale from './scale';
import Util from '../helpers/helpers.util';

Expand Down Expand Up @@ -157,6 +159,35 @@ class StepScale extends Scale {
});

ctx.closePath();

// draw plot line
if (this.plotLines?.length) {
const padding = aliasPixel + 1;
const minX = aPos.x1 + padding;
const maxX = aPos.x2;
const minY = aPos.y1 + padding;
const maxY = aPos.y2;

this.plotLines.forEach((plotLine) => {
if (!plotLine.value) {
return;
}

const mergedPlotLineOpt = defaultsDeep({}, plotLine, PLOT_LINE_OPTION);
const { value, label: labelOpt } = mergedPlotLineOpt;
const dataPos = Math.round(startPoint + (labelGap * value)) + (labelGap / 2);

this.setPlotLineStyle(mergedPlotLineOpt);

if (this.type === 'x') {
this.drawXPlotLine(dataPos, minX, maxX, minY, maxY, labelOpt);
} else {
this.drawYPlotLine(dataPos, minX, maxX, minY, maxY, labelOpt);
}

ctx.restore();
});
}
}

/**
Expand Down

0 comments on commit c8bb949

Please sign in to comment.