บทนำ
ป้ายชื่อในกราฟแท่งมักประสบปัญหาการอ่านเมื่อกราฟถูกปรับขนาด, แสดงบนความละเอียดหน้าจอที่แตกต่างกัน, หรือซูมเข้า/ออกโดยใช้การควบคุมการซูมของ amCharts โดยค่าเริ่มต้น, ป้ายชื่อใน amCharts 4 จะมีความกว้างคงที่, ซึ่งอาจทำให้เกิด การทับซ้อน, การตัดทอน, หรือข้อความที่อ่านไม่ออก บนหน้าจอขนาดเล็ก.
เพื่อทำให้ป้ายชื่อ ตอบสนอง จริงๆ, เราจำเป็นต้อง:
- คำนวณ ความกว้างสูงสุด ของป้ายชื่อแบบไดนามิกตามขนาดกราฟและความกว้างของคอลัมน์.
- ตัดทอนป้ายชื่อที่ยาว หากจำเป็นเพื่อป้องกันการล้น.
- ใช้ event hooks เพื่อให้แน่ใจว่าป้ายชื่อปรับตัวได้อย่างเหมาะสมเมื่อ:
- กราฟปรับขนาด.
- เกิดการซูม/เลื่อน.
- ข้อมูลอัปเดตแบบไดนามิก.
ในบทความนี้, เราจะสำรวจวิธีการ ปรับความกว้างของป้ายชื่อแบบไดนามิก และ ตัดทอนป้ายชื่อเมื่อจำเป็น โดยใช้เหตุการณ์ของ amCharts 4.
โค้ดการใช้งานที่มีปัญหา:
am4core.ready(function () {
// สร้างอินสแตนซ์กราฟ
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // การเฟดอินเริ่มต้น
chart.logo.disabled = true;
chart.responsive.enabled = true; // เปิดใช้งานพฤติกรรมที่ตอบสนอง
// ข้อมูลกราฟ
chart.data = [
{ company: "Apple Inc.", visits: 23725 },
{ company: "Microsoft Corporation", visits: 1882 },
{ company: "Alphabet Inc. (Google)", visits: 1809 },
{ company: "Amazon.com, Inc.", visits: 1322 },
{ company: "Tesla, Inc.", visits: 1122 },
{ company: "Meta Platforms, Inc. (Facebook)", visits: 1114 },
{ company: "Berkshire Hathaway Inc.", visits: 711 },
{ company: "PepsiCo, Inc.", visits: 443 },
{ company: "Johnson & Johnson Services, Inc.", visits: 350 },
{ company: "McDonald's Corporation", visits: 298 },
{ company: "NVIDIA Corporation", visits: 150 },
{ company: "Netflix, Inc.", visits: 100 }
];
// สร้างแกนหมวดหมู่ (แกน X)
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "company";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 40;
categoryAxis.fontSize = 11;
categoryAxis.renderer.labels.template.wrap = true;
categoryAxis.renderer.labels.template.maxWidth = 80;
categoryAxis.renderer.labels.template.padding(10, 0, 0, 0); // ตั้งค่าทุกด้านเป็น 0
// สร้างแกนค่า (แกน Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// สร้างชุดคอลัมน์
let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryX = "company";
series.dataFields.valueY = "visits";
series.columns.template.tooltipText = "{valueY.value}";
series.columns.template.tooltipY = 0;
series.columns.template.strokeOpacity = 0;
// ใช้สีที่แตกต่างกันสำหรับแต่ละคอลัมน์
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// เพิ่มแถบเลื่อน
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// เพิ่มการแบ่งแกนสำหรับค่าที่ใหญ่
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// ปรับขนาดการแบ่งแกน
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // ขนาดการแบ่งที่เพิ่มขึ้นเพื่อการมองเห็นที่ดีขึ้น
// ปรับเอฟเฟกต์ hover เพื่อการโต้ตอบที่ดีขึ้น
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // ขนาดการแบ่งที่ใหญ่ขึ้นเมื่อเลื่อนเมาส์
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // สิ้นสุด am4core.ready()
การตั้งค่าความกว้างสูงสุดที่ตอบสนองสำหรับป้ายชื่อ
ใน amCharts 4, ป้ายชื่อสำหรับ xAxis ใน กราฟแท่ง จะมีความกว้างสูงสุดคงที่ อย่างไรก็ตาม, เนื่องจากความกว้างนี้ไม่ปรับเปลี่ยนแบบไดนามิก, เราจึงต้องคำนวณมันตาม ความกว้างของคอลัมน์และขนาดกราฟ.
เพื่อให้บรรลุสิ่งนี้, เราจะใช้ rangechangeended และ sizechanged เหตุการณ์, ตรวจสอบความกว้างของคอลัมน์, และตั้งค่าความกว้างสูงสุดตามนั้น.
การใช้งาน
// ฟังก์ชันเพื่ออัปเดตความกว้างสูงสุดของป้ายชื่อตามคอลัมน์ที่กว้างที่สุด
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// วนลูปผ่านแต่ละคอลัมน์และหาความกว้างสูงสุด
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// ใช้ความกว้างสูงสุดกับป้ายชื่อ
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Updated Max Label Width: " + maxColumnWidth);
// บังคับให้ป้ายชื่อถูกประมวลผลใหม่
categoryAxis.invalidateLabels();
}
// กระตุ้นการอัปเดตความกว้างของป้ายชื่อเมื่อซูม/เลื่อน
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// กระตุ้นการอัปเดตความกว้างของป้ายชื่อเมื่อขนาดหน้าจอเปลี่ยน
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
คำอธิบาย
ฟังก์ชัน updateLabelMaxWidth ปรับความกว้างของป้ายชื่อแกน x แบบไดนามิกตามคอลัมน์ที่กว้างที่สุดในกราฟ มันวนลูปผ่านทุกคอลัมน์, หาความกว้าง สูงสุด, และนำไปใช้กับป้ายชื่อเพื่อป้องกัน การทับซ้อน.
Event Hooks:
- rangechangeended → อัปเดตความกว้างของป้ายชื่อเมื่อซูม/เลื่อน.
- sizechanged → ปรับป้ายชื่อเมื่อกราฟถูกปรับขนาด.
สิ่งนี้ทำให้แน่ใจว่าป้ายชื่อ ปรับขนาดแบบไดนามิก ตามพื้นที่ที่มีอยู่.
การตัดทอนป้ายชื่อที่ยาวเพื่อการอ่านที่ดีขึ้น
แม้จะมี ความกว้างสูงสุดแบบไดนามิก, ป้ายชื่อบางอันอาจยังคง ยาวเกินไป และอาจทำให้เกิดความยุ่งเหยิง เพื่อจัดการกับสิ่งนี้, เราจึง ตัดทอนป้ายชื่อ เมื่อมันเกินความยาวที่กำหนด.
การใช้งาน
categoryAxis.renderer.labels.template.adapter.add("textOutput", function(text, target) {
let maxLabelLength = 10; // ตั้งค่าจำนวนตัวอักษรสูงสุดก่อนการตัดทอน
if (text.length > maxLabelLength) {
return text.substring(0, maxLabelLength) + "..."; // ตัดทอนและเพิ่มจุดไข่ปลา
}
return text; // คืนค่าข้อความเดิมหากอยู่ภายในขีดจำกัด
});
คำอธิบาย
- ฟังก์ชันนี้ ตรวจสอบความยาว ของแต่ละป้ายชื่อ.
- หากป้ายชื่อ ยาวเกินไป, มันจะตัดทอนข้อความไปยังคำแรกและ เพิ่ม ".." ที่ท้าย.
- ป้ายชื่อที่อยู่ภายใน ขีดจำกัดจำนวนตัวอักษรสูงสุด จะไม่เปลี่ยนแปลง.
สิ่งนี้ทำให้แน่ใจว่าป้ายชื่อที่ยาวจะไม่ทับซ้อนในขณะที่ยังคงให้ข้อมูลเพียงพอและยังคงตอบสนองเมื่อปรับขนาดหรือซูมเข้า/ออก.
โค้ดการใช้งานทั้งหมดหลังจากการใช้วิธีแก้ปัญหา
am4core.ready(function () {
// สร้างอินสแตนซ์กราฟ
let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.hiddenState.properties.opacity = 0; // การเฟดอินเริ่มต้น
chart.logo.disabled = true;
chart.responsive.enabled = true; // เปิดใช้งานพฤติกรรมที่ตอบสนอง
// ข้อมูลกราฟ
chart.data = [
{ company: "Apple Inc.", visits: 23725 },
{ company: "Microsoft Corporation", visits: 1882 },
{ company: "Alphabet Inc. (Google)", visits: 1809 },
{ company: "Amazon.com, Inc.", visits: 1322 },
{ company: "Tesla, Inc.", visits: 1122 },
{ company: "Meta Platforms, Inc. (Facebook)", visits: 1114 },
{ company: "Berkshire Hathaway Inc.", visits: 711 },
{ company: "PepsiCo, Inc.", visits: 443 },
{ company: "Johnson & Johnson Services, Inc.", visits: 350 },
{ company: "McDonald's Corporation", visits: 298 },
{ company: "NVIDIA Corporation", visits: 150 },
{ company: "Netflix, Inc.", visits: 100 }
];
// สร้างแกนหมวดหมู่ (แกน X)
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "company";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 40;
categoryAxis.fontSize = 11;
categoryAxis.renderer.labels.template.wrap = true;
categoryAxis.renderer.labels.template.maxWidth = 80;
categoryAxis.renderer.labels.template.padding(10, 0, 0, 0); // ตั้งค่าทุกด้านเป็น 0
// สร้างแกนค่า (แกน Y)
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.min = 0;
valueAxis.max = 24000;
valueAxis.strictMinMax = true;
valueAxis.renderer.minGridDistance = 30;
// ฟังก์ชันเพื่ออัปเดตความกว้างสูงสุดของป้ายชื่อตามคอลัมน์ที่กว้างที่สุด
const updateLabelMaxWidth = () => {
let maxColumnWidth = 0;
// วนลูปผ่านแต่ละคอลัมน์และหาความกว้างสูงสุด
series.columns.each(function (column) {
if (column && column.pixelWidth > maxColumnWidth) {
maxColumnWidth = column.pixelWidth;
}
});
// ใช้ความกว้างสูงสุดกับป้ายชื่อ
categoryAxis.renderer.labels.template.maxWidth = maxColumnWidth;
console.log("Updated Max Label Width: " + maxColumnWidth);
// บังคับให้ป้ายชื่อถูกประมวลผลใหม่
categoryAxis.invalidateLabels();
}
// กระตุ้นการอัปเดตความกว้างของป้ายชื่อเมื่อซูม/เลื่อน
categoryAxis.events.on("rangechangeended", function () {
updateLabelMaxWidth();
});
// กระตุ้นการอัปเดตความกว้างของป้ายชื่อเมื่อขนาดหน้าจอเปลี่ยน
chart.events.on("sizechanged", function () {
updateLabelMaxWidth();
});
// ตัดทอนป้ายชื่อที่ปลายคำแรกเมื่อจำเป็น
categoryAxis.renderer.labels.template.adapter.add("textOutput", function (text, target) {
let labelMaxWidth = target.maxWidth;
if (labelMaxWidth < 60 && text) { // ตรวจสอบว่าความกว้างของป้ายชื่อมีน้อยกว่า 60 พิกเซล
let words = text.split(" "); // แยกข้อความเป็นคำ
return words.length > 1 ? words[0] + ".." : text; // เก็บเฉพาะคำแรกพร้อมกับ ".."
}
return text;
});
// สร้างชุดคอลัมน์
let series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.categoryX = "company";
series.dataFields.valueY = "visits";
series.columns.template.tooltipText = "{valueY.value}";
series.columns.template.tooltipY = 0;
series.columns.template.strokeOpacity = 0;
// ใช้สีที่แตกต่างกันสำหรับแต่ละคอลัมน์
series.columns.template.adapter.add("fill", function (fill, target) {
return chart.colors.getIndex(target.dataItem.index);
});
// เพิ่มแถบเลื่อน
chart.scrollbarX = new am4core.Scrollbar();
chart.scrollbarX.marginTop = 30;
chart.scrollbarX.parent = chart.bottomAxesContainer;
// เพิ่มการแบ่งแกนสำหรับค่าที่ใหญ่
let axisBreak = valueAxis.axisBreaks.create();
axisBreak.startValue = 2100;
axisBreak.endValue = 22900;
// ปรับขนาดการแบ่งแกน
let d = (axisBreak.endValue - axisBreak.startValue) / (valueAxis.max - valueAxis.min);
axisBreak.breakSize = 0.05 * (1 - d) / d; // ขนาดการแบ่งที่เพิ่มขึ้นเพื่อการมองเห็นที่ดีขึ้น
// ปรับเอฟเฟกต์ hover เพื่อการโต้ตอบที่ดีขึ้น
let hoverState = axisBreak.states.create("hover");
hoverState.properties.breakSize = 1; // ขนาดการแบ่งที่ใหญ่ขึ้นเมื่อเลื่อนเมาส์
hoverState.properties.opacity = 0.1;
hoverState.transitionDuration = 1500;
axisBreak.defaultState.transitionDuration = 1000;
}); // สิ้นสุด am4core.ready()
ด้วยการปรับแต่งเหล่านี้, กราฟของเราตอนนี้ ปรับตัวได้อย่างสมบูรณ์—ป้ายชื่อยังคงอ่านได้, ไม่มีการทับซ้อนที่น่าเกลียด, และทุกอย่างปรับขนาดได้อย่างราบรื่น โดยการปรับความกว้างแบบไดนามิก, การตัดทอนชื่อที่ยาว, และการเชื่อมต่อกับเหตุการณ์, เราได้ทำให้แน่ใจว่ากราฟดูดีบนหน้าจอใดๆ ตอนนี้, ลองไปทำดูนะ!