
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<!-- <div>
<select name="x-axis" v-model="selectedSubGroup" @change="changeSelectSubGroup">
<option key="" value="" >sub 선택</option>
<option v-for="(column, index) in subGroupArr" :key="index" :value="column.index">{{ column.columnNm }}</option>
</select>
</div> -->
<div
class="chartdiv"
id="chartdiv"
ref="chartdiv"
style="width: 100%; height: 100%"
></div>
</template>
<script>
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import * as am5percent from "@amcharts/amcharts5/percent";
import * as am5wc from "@amcharts/amcharts5/wc";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import Frozen from "@amcharts/amcharts5/themes/Frozen";
import Dark from "@amcharts/amcharts5/themes/Dark"; // 배경이 어두워야 이쁨
import Dataviz from "@amcharts/amcharts5/themes/Dataviz";
import Kelly from "@amcharts/amcharts5/themes/Kelly";
import Material from "@amcharts/amcharts5/themes/Material";
import Micro from "@amcharts/amcharts5/themes/Micro";
import Moonrise from "@amcharts/amcharts5/themes/Moonrise";
import Spirited from "@amcharts/amcharts5/themes/Spirited";
import chartDataTransform from "./chartDataTransform";
export default {
props: {
createDataObj: {
type: Object,
default: {},
},
},
data() {
return {
// 가공된 데이터를 담을 배열
chartJsondData: [],
// select box에서 선택 된 그룹
selectedSubGroup: "",
// group 선택에 따른 변수
isSelectGroup: false,
subGroupArr: [],
groupsResult: [],
//
datalist: [],
chartName: this.createDataObj.chart_knd,
selectedFieldArr: [],
isMultiData: this.createDataObj.isMultiData,
selectedCal: this.createDataObj.chart_cal,
selectedTheme: "",
// selectedGroupNm: ,
};
},
components: {},
methods: {
// 그룹 선택으로 인한 데이터 필터링 함수
changeSelectSubGroup: function (event) {
this.selectedSubGroup = event.target.value;
// 필터 적용 함수 호출
const filterDataList = chartDataTransform.setFilteringData(
this.datalist,
this.subGroupArr,
this.selectedSubGroup
);
this.transformData(filterDataList);
},
changeSubGroupData: function (val) {
if (Array.isArray(val)) {
this.subGroupArr = [];
this.subGroupArr = val
.map((data) => data.group)
.filter((value, index, self) => self.indexOf(value) === index)
.map((column, index) => {
return {
index: index,
columnNm: column,
};
});
// subGroupArr sort 처리
this.subGroupArr.sort((a, b) =>
a.columnNm < b.columnNm ? -1 : a.columnNm > b.columnNm ? 1 : 0
);
}
},
//y 객체 배열 생성
createYData: function () {
this.selectedFieldArr = this.createDataObj.valueAxis.map((field) => {
return {
valNm: field.columnNm,
valIndex: field.columnIdx,
};
});
},
// 데이터 생성 함수
// dataList를 받아와 차트에 표현할 데이터로 가공
transformData: function (val) {
if (val == null) {
this.chartJsondData = [];
this.runCreateChart();
return;
}
this.createYData();
if (this.selectedCal === "default") {
this.chartJsondData = val;
this.runCreateChart();
return;
}
// 전체 데이터를 그룹화하여 가공 (All Data)
this.groupsResult = chartDataTransform.dataGrouping(
val,
this.selectedFieldArr
);
if (!this.isSelectGroup) {
// groupSubArr에 group의 key를 중복을 제거하고 담음
this.changeSubGroupData(this.datalist);
}
// 데이터 가공 함수
this.chartJsondData = chartDataTransform.calculateSetting(
this.groupsResult,
this.selectedCal
);
this.runCreateChart();
},
/**
* 차트 테마 선택 기능
*/
choeseTheme: function (choeseTheme) {
if (choeseTheme === "Frozen") {
return Frozen;
} else if (choeseTheme === "Dark") {
return Dark;
} else if (choeseTheme === "Dataviz") {
return Dataviz;
} else if (choeseTheme === "Kelly") {
return Kelly;
} else if (choeseTheme === "Material") {
return Material;
} else if (choeseTheme === "Micro") {
return Micro;
} else if (choeseTheme === "Moonrise") {
return Moonrise;
} else if (choeseTheme === "Spirited") {
return Spirited;
}
},
initializeChartArea: function () {
let chartWarp = this.$refs["chartdiv"]; // 차트 상위 div ref 매칭
if(chartWarp){
chartWarp.innerHTML = ""; // 차트 상위 div 내용 초기화 (기존 차트 삭제)
let div = document.createElement("div"); // 차트를 담을 빈 div 생성 (차트 하위 div)
div.style.width = "100%"; // 차트를 담을 div의 넓이
div.style.height = "100%"; // 차트를 담을 div의 높이
chartWarp.appendChild(div); // 차트 상위 div 안에 차트 하위 div를 추가
let chartArea = am5.Root.new(chartWarp.firstChild);
let themes = this.choeseTheme(this.selectedTheme);
if (this.selectedTheme != "") {
chartArea.setThemes([am5themes_Animated.new(root), themes.new(root)]);
} else {
chartArea.setThemes([am5themes_Animated.new(root)]);
}
return chartArea;}
},
/* Create chart */
// column chart
createColumnChart: function () {
// 필요 데이터 및 변수 선언
let vm = this;
let data = vm.chartJsondData;
let root = vm.initializeChartArea(); // 차트 초기화
let chartConfig = vm.getChartConfig(vm.chartName);
let chart = vm.initializeChart(root, chartConfig);
let series = null;
let cursor = chart.set(
"cursor",
am5xy.XYCursor.new(root, {
behavior: chartConfig.behavior,
})
);
// 축 라인 숨김
// cursor.lineY.set("forceHidden", true);
// cursor.lineX.set("forceHidden", true);
let categoryRenderer = am5xy[chartConfig.categoryAxisRenderer].new(root, {
minGridDistance: 30,
minorGridEnabled: true,
inversed: chartConfig.categoryInversed,
});
// 카테고리 렌더러 옵션 설정
categoryRenderer.labels.template.setAll({
rotation: -90,
centerY: am5.p50,
centerX: am5.p100,
paddingRight: 15,
});
categoryRenderer.grid.template.setAll({
stroke: am5.color(0xf15f5f),
location: 1,
});
// 카테고리 축 설정
let categoryAxis = chart[chartConfig.categoryAxes].push(
am5xy.CategoryAxis.new(root, {
maxDeviation: 0.3,
categoryField: "categoryData",
renderer: categoryRenderer,
tooltip: am5.Tooltip.new(root, {}),
})
);
// value 랜더러 설정
let valueRenderer = am5xy[chartConfig.valueAxisRenderer].new(root, {
strokeOpacity: 0.1,
});
// value 축 설정
let valueAxis = chart[chartConfig.valueAxes].push(
am5xy.ValueAxis.new(root, {
maxDeviation: 0.3,
renderer: valueRenderer,
})
);
categoryAxis.data.setAll(data);
// 시리즈 설정
let seriesConfig = vm.getSeriesConfig(
vm.chartName,
categoryAxis,
valueAxis
);
let valuedata =
vm.selectedFieldArr.length > 0 ? vm.selectedFieldArr[0].valNm : "";
series = vm.initializeSeries(chart, seriesConfig, valuedata);
series.columns.template.setAll({
cornerRadiusTL: 5,
cornerRadiusTR: 5,
strokeOpacity: 0,
});
series.columns.template.adapters.add("fill", function (fill, target) {
return chart.get("colors").getIndex(series.columns.indexOf(target));
});
series.columns.template.adapters.add("stroke", function (stroke, target) {
return chart.get("colors").getIndex(series.columns.indexOf(target));
});
series.data.setAll(data);
series.appear(1000);
root._logo.dispose();
},
// line chart
createLineChart: function () {
let vm = this;
let data = vm.chartJsondData;
let root = vm.initializeChartArea(); // 차트 초기화
let chartConfig = vm.getChartConfig(vm.chartName);
let chart = vm.initializeChart(root, chartConfig);
let series = null;
let categoryRenderer = am5xy[chartConfig.categoryAxisRenderer].new(root, {
minorGridEnabled: true,
minGridDistance: 60,
});
categoryRenderer.grid.template.setAll({
location: 1,
});
let categoryAxis = chart[chartConfig.categoryAxes].push(
am5xy.CategoryAxis.new(root, {
categoryField: "categoryData",
renderer: categoryRenderer,
tooltip: am5.Tooltip.new(root, {}),
})
);
categoryAxis.data.setAll(data);
let valueRenderer = am5xy[chartConfig.valueAxisRenderer].new(root, {
strokeOpacity: 0.1,
});
let valueAxis = chart[chartConfig.valueAxes].push(
am5xy.ValueAxis.new(root, {
min: 0,
renderer: valueRenderer,
})
);
let cursor = chart.set(
"cursor",
am5xy.XYCursor.new(root, {
behavior: "none",
})
);
cursor.lineY.set("visible", false);
let seriesConfig = vm.getSeriesConfig(
vm.chartName,
categoryAxis,
valueAxis
);
//데이터 없애는 부분 생각 필요
let valuedata =
vm.selectedFieldArr.length > 0 ? vm.selectedFieldArr[0].valNm : "value";
for (let i = 0; i < vm.selectedFieldArr.length; i++) {
series = vm.makeSeries(
root,
chart,
vm.selectedFieldArr[i].valNm,
seriesConfig
);
// 노드 표시
if (vm.chartName == "node_line_chart") {
series.bullets.push(function (root) {
return am5xy.AxisBullet.new(root, {
location: 0.5,
sprite: am5.Circle.new(root, {
radius: 5,
fill: am5.color(0xff0000),
}),
});
});
}
// 그래프 배경 색상
if (vm.chartName == "liin_chart_back") {
series.fills.template.setAll({
fillOpacity: 0.2,
visible: true,
});
}
series.data.setAll(data);
}
series.appear(1000, 100);
root._logo.dispose();
},
// pie_chart chart
createPieChart: function () {
let data = this.chartJsondData;
let root = this.initializeChartArea(); // 차트 초기화
let chart = null;
let series = null;
// Create chart
let startAngle = null;
let endAngle = null;
let innerRadius = null;
if (this.chartName == "semicircle_chart") {
startAngle = 180;
endAngle = 360;
}
if (this.chartName == "dounet_chart") {
innerRadius = am5.percent(50);
}
chart = root.container.children.push(
am5percent.PieChart.new(root, {
startAngle: startAngle,
endAngle: 360,
innerRadius: innerRadius,
})
);
let valuedata =
this.selectedFieldArr.length > 0
? this.selectedFieldArr[0].valNm
: "value";
series = chart.series.push(
am5percent.PieSeries.new(root, {
valueField: valuedata,
categoryField: "categoryData",
startAngle: this.chartName == "semicircle_chart" ? 180 : null,
endAngle: 360,
})
);
series.states.create("hidden", {
endAngle: -90,
});
series.data.setAll(data);
series.appear(1000, 100);
root._logo.dispose();
},
// Clustered data chart
createClusteredChart: function () {
let vm = this;
let root = this.initializeChartArea(); // 차트 초기화'
let dataVal = this.chartJsondData;
let chartConfig = this.getChartConfig(vm.chartName);
let chart = this.initializeChart(root, chartConfig);
// Add legend
let legend = chart.children.push(
am5.Legend.new(root, {
centerX: am5.p50,
x: am5.p50,
})
);
let categoryRenderer = am5xy[chartConfig.categoryAxisRenderer].new(root, {
cellStartLocation: 0.1,
cellEndLocation: 0.9,
minorGridEnabled: true,
});
let categoryAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "categoryData",
renderer: categoryRenderer,
tooltip: am5.Tooltip.new(root, {}),
})
);
categoryRenderer.grid.template.setAll({
location: 1,
});
categoryAxis.data.setAll(dataVal);
// value 랜더러 설정
let valueRenderer = am5xy[chartConfig.valueAxisRenderer].new(root, {
strokeOpacity: 0.1,
});
let valueAxis = chart[chartConfig.valueAxes].push(
am5xy.ValueAxis.new(root, {
renderer: valueRenderer,
})
);
let seriesConfig = vm.getSeriesConfig(
vm.chartName,
categoryAxis,
valueAxis
);
let series = null;
for (let i = 0; i < vm.selectedFieldArr.length; i++) {
series = vm.makeSeries(
root,
chart,
vm.selectedFieldArr[i].valNm,
seriesConfig
);
series.data.setAll(dataVal);
}
chart.appear(1000, 300);
root._logo.dispose(); //amChart 로고 삭제
},
createWordChart: function () {
let vm = this;
let root = vm.initializeChartArea(); // 차트 초기화
let valuedata = vm.selectedFieldArr.length > 0 ? vm.selectedFieldArr[0].valNm : "";
let series = root.container.children.push(
am5wc.WordCloud.new(root, {
categoryField: "categoryData",
valueField: valuedata,
maxFontSize: am5.percent(15),
})
);
// Configure labels
series.labels.template.setAll({
fontFamily: "Courier New",
});
series.data.setAll(this.chartJsondData);
root._logo.dispose();
},
// 음수 차트 수정 필요(아직 합치지않음)
createNagativeChart: function () {
let vm = this;
let root = vm.initializeChartArea(); // 차트 초기화
root._logo.dispose();
if (vm.selectedFieldArr.length < 2) {
return;
}
chartDataTransform.convertValuesToNegative(
vm.chartJsondData,
vm.selectedFieldArr[0].valNm
);
let chart = root.container.children.push(
am5xy.XYChart.new(root, {
panX: false,
panY: false,
wheelX: "panX",
wheelY: "zoomX",
layout: root.verticalLayout,
arrangeTooltips: false,
paddingLeft: 0,
paddingRight: 10,
})
);
// Use only absolute numbers
chart.getNumberFormatter().set("numberFormat", "#.#s");
let legend = chart.children.push(
am5.Legend.new(root, {
centerX: am5.p50,
x: am5.p50,
})
);
let yAxis = chart.yAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "categoryData",
renderer: am5xy.AxisRendererY.new(root, {
inversed: true,
cellStartLocation: 0.1,
cellEndLocation: 0.9,
minorGridEnabled: true,
minGridDistance: 20,
}),
})
);
yAxis.data.setAll(this.chartJsondData);
let xAxis = chart.xAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererX.new(root, {
minGridDistance: 60,
strokeOpacity: 0.1,
}),
})
);
function createSeries(
field,
labelCenterX,
pointerOrientation,
rangeValue
) {
let series = chart.series.push(
am5xy.ColumnSeries.new(root, {
xAxis: xAxis,
yAxis: yAxis,
valueXField: field,
categoryYField: "categoryData",
sequencedInterpolation: true,
clustered: false,
tooltip: am5.Tooltip.new(root, {
pointerOrientation: pointerOrientation,
labelText: "{categoryY}: {valueX}",
}),
})
);
series.columns.template.setAll({
height: am5.p100,
strokeOpacity: 0,
fillOpacity: 0.8,
});
series.bullets.push(function () {
return am5.Bullet.new(root, {
locationX: 1,
locationY: 0.5,
sprite: am5.Label.new(root, {
centerY: am5.p50,
text: "{valueX}",
populateText: true,
centerX: labelCenterX,
}),
});
});
series.data.setAll(vm.chartJsondData);
series.appear();
let rangeDataItem = xAxis.makeDataItem({
value: rangeValue,
});
xAxis.createAxisRange(rangeDataItem);
rangeDataItem.get("grid").setAll({
strokeOpacity: 1,
stroke: series.get("stroke"),
});
let label = rangeDataItem.get("label");
label.setAll({
text: field.toUpperCase(),
fontSize: "1.1em",
fill: series.get("stroke"),
paddingTop: 10,
isMeasured: false,
centerX: labelCenterX,
});
label.adapters.add("dy", function () {
return -chart.plotContainer.height();
});
return series;
}
createSeries(vm.selectedFieldArr[0].valNm, am5.p100, "right", -3);
createSeries(vm.selectedFieldArr[1].valNm, 0, "left", 4);
let cursor = chart.set(
"cursor",
am5xy.XYCursor.new(root, {
behavior: "zoomY",
})
);
cursor.lineY.set("forceHidden", true);
cursor.lineX.set("forceHidden", true);
chart.appear(1000, 100);
root._logo.dispose(); //amChart 로고 삭제
},
// 막대 선 차트 (수정 필요)
createColAndLineChart: function () {
let vm = this;
let data = vm.chartJsondData;
let root = vm.initializeChartArea(); // 차트 초기화
root._logo.dispose(); //amChart 로고 삭제
if (data.length == 0) {
return;
}
let income = Object.keys(data[0])[1];
let expenses = Object.keys(data[0])[2];
let chart = root.container.children.push(
am5xy.XYChart.new(root, {
panX: false,
panY: false,
wheelX: "panX",
wheelY: "zoomX",
paddingLeft: 0,
layout: root.verticalLayout,
})
);
let xRenderer = am5xy.AxisRendererX.new(root, {
minorGridEnabled: true,
minGridDistance: 60,
});
let xAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "categoryData",
renderer: xRenderer,
tooltip: am5.Tooltip.new(root, {}),
})
);
xRenderer.grid.template.setAll({
location: 1,
});
xAxis.data.setAll(data);
let yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
min: 0,
extraMax: 0.1,
renderer: am5xy.AxisRendererY.new(root, {
strokeOpacity: 0.1,
}),
})
);
let series1 = chart.series.push(
am5xy.ColumnSeries.new(root, {
name: income,
xAxis: xAxis,
yAxis: yAxis,
valueYField: income,
categoryXField: "categoryData",
tooltip: am5.Tooltip.new(root, {
pointerOrientation: "horizontal",
labelText: "{name} in {categoryX}: {valueY} {info}",
}),
})
);
series1.columns.template.setAll({
tooltipY: am5.percent(10),
templateField: "columnSettings",
});
series1.data.setAll(data);
let series2 = chart.series.push(
am5xy.LineSeries.new(root, {
name: expenses,
xAxis: xAxis,
yAxis: yAxis,
valueYField: expenses,
categoryXField: "categoryData",
tooltip: am5.Tooltip.new(root, {
pointerOrientation: "horizontal",
labelText: "{name} in {categoryX}: {valueY} {info}",
}),
})
);
series2.strokes.template.setAll({
strokeWidth: 3,
templateField: "strokeSettings",
});
series2.data.setAll(data);
series2.bullets.push(function () {
return am5.Bullet.new(root, {
sprite: am5.Circle.new(root, {
strokeWidth: 3,
stroke: series2.get("stroke"),
radius: 5,
fill: root.interfaceColors.get("background"),
}),
});
});
chart.set("cursor", am5xy.XYCursor.new(root, {}));
series1.appear(1000);
chart.appear(1000, 300);
root._logo.dispose(); //amChart 로고 삭제
},
// Create chart
getChartConfig: function (chartName) {
// 차트에 따라 설정이 달라져야함
let axis = true;
if (
chartName == "column_chart_h" ||
chartName == "clustered_chart_h" ||
chartName == "STACK_ROW"
) {
axis = false;
}
return {
// 차트 축 설정
categoryAxisRenderer: axis ? "AxisRendererX" : "AxisRendererY",
valueAxisRenderer: axis ? "AxisRendererY" : "AxisRendererX",
categoryAxes: axis ? "xAxes" : "yAxes",
valueAxes: axis ? "yAxes" : "xAxes",
categoryInversed: axis ? false : true,
// 차트 이동 및 확대/축소 설정
panX: true,
panY: true,
wheelX: "panX",
wheelY: axis ? "panY" : "zoomX",
behavior: axis ? "none" : "zoomY",
};
},
initializeChart: function (root, config) {
console.log(root.container.children);
return root.container.children.push(
am5xy.XYChart.new(root, {
panX: config.panX,
panY: config.panY,
wheelX: config.wheelX,
wheelY: config.wheelY,
})
);
},
// Create series
getSeriesConfig: function (chartName, categoryAxis, valueAxis) {
// 차트에 따라 설정이 달라져야함
let axis = true;
let chartNm = "ColumnSeries";
if (
chartName == "column_chart_h" ||
chartName == "clustered_chart_h" ||
chartName == "STACK_ROW"
) {
axis = false;
}
if (
chartName == "line_chart" ||
chartName == "node_line_chart" ||
chartName == "liin_chart_back"
) {
chartNm = "LineSeries";
}
let isStack = false;
if (
this.chartName === "stacked_column_chart" ||
this.chartName === "STACK_ROW"
) {
isStack = true;
}
return {
chartNm: chartNm,
isStack: isStack,
xAxis: axis ? categoryAxis : valueAxis,
yAxis: axis ? valueAxis : categoryAxis,
categoryField: axis ? "categoryXField" : "categoryYField",
valueField: axis ? "valueYField" : "valueXField",
categoryXY: axis ? "categoryX" : "categoryY",
valueXY: axis ? "valueY" : "valueX",
tooltipText: axis ? "{valueY}" : "{valueX}",
};
},
initializeSeries: function (chart, seriesConfig, valuedata) {
// 차트에 새로운 시리즈를 생성하여 추가
let series = chart.series.push(
am5xy[seriesConfig.chartNm].new(chart.root, {
name: valuedata, // 이 부분은 valuedata를 이름으로 사용하고 있으나, 이는 데이터의 의도에 따라 다를 수 있습니다.
stacked: seriesConfig.isStack,
xAxis: seriesConfig.xAxis,
yAxis: seriesConfig.yAxis,
[seriesConfig.valueField]: valuedata,
[seriesConfig.categoryField]: "categoryData",
tooltip: am5.Tooltip.new(chart.root, {
labelText: seriesConfig.tooltipText,
}),
})
);
return series; // 생성된 시리즈 객체를 반환
},
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
makeSeries: function (root, chart, name, seriesConfig) {
let series = chart.series.push(
am5xy[seriesConfig.chartNm].new(root, {
name: name,
stacked: seriesConfig.isStack,
xAxis: seriesConfig.xAxis,
yAxis: seriesConfig.yAxis,
[seriesConfig.valueField]: name,
[seriesConfig.categoryField]: "categoryData",
tooltip: am5.Tooltip.new(chart.root, {
labelText: seriesConfig.tooltipText,
}),
})
);
return series;
},
// 차트 생성 실행 함수
runCreateChart: function () {
if (
this.chartName === "column_chart_v" ||
this.chartName === "column_chart_h"
) {
this.createColumnChart();
} else if (
this.chartName === "line_chart" ||
this.chartName === "node_line_chart" ||
this.chartName === "liin_chart_back"
) {
this.createLineChart();
} else if (
this.chartName === "pie_chart" ||
this.chartName === "dounet_chart" ||
this.chartName === "semicircle_chart"
) {
this.createPieChart();
} else if (
this.chartName === "clustered_chart_v" ||
this.chartName === "clustered_chart_h" ||
this.chartName === "stacked_column_chart" ||
this.chartName === "STACK_ROW"
) {
this.createClusteredChart();
} else if (this.chartName === "word_chart") {
this.createWordChart();
} else if (this.chartName === "stacked_bar_chart") {
this.createNagativeChart();
} else if (this.chartName === "mix_chart") {
this.createColAndLineChart();
}
},
},
watch: {
createDataObj: {
handler: function (newVal, oldVal) {
this.datalist = newVal.data_list;
this.chartName = newVal.chart_knd;
this.isMultiData = newVal.multidata_use_yn;
this.selectedCal = newVal.chart_cal;
this.transformData(this.datalist);
},
deep: true,
},
},
mounted() {
this.datalist = this.createDataObj.data_list;
this.chartName = this.createDataObj.chart_knd;
this.isMultiData = this.createDataObj.multidata_use_yn;
this.selectedCal = this.createDataObj.chart_cal;
this.transformData(this.datalist);
},
};
</script>
<style scoped>
#chartdiv {
width: 100%;
height: 500px;
}
button {
margin: 10px;
background-color: antiquewhite;
border-radius: 10px;
}
</style>