
글이 길어서 그런가 한번에 글을 작성했더니
로드되는데 문제가 있어 글을 2개로 나눠 작성한다.
블로그에 다시 정리하기 위해 테스트를 진행했고 수정한 코드는 아래와 같다.
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Highcharts Ctrl+C Clipboard Demo</title>
<script src="https://unpkg.com/highcharts/highcharts.js"></script>
<script src="https://unpkg.com/highcharts/modules/exporting.js"></script>
<script src="https://code.jquery.com/jquery-3.0.0.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
}
.chartContainer {
border: 2px solid transparent;
border-radius: 8px;
padding: 10px;
}
.chartContainer.selected {
border-color: #bdbdbd;
}
.controls {
text-align: center;
margin-top: 15px;
}
</style>
</head>
<body>
<h2>Highcharts 12.x Ctrl+C 이미지 복사</h2>
<p>차트를 클릭한 뒤 Ctrl+C를 누르면 PNG 이미지가 클립보드에 복사됩니다.</p>
<div id="container" class="chartContainer"></div>
<div class="controls">
<select id="ChType">
<option value="column">column</option>
<option value="pie">pie</option>
<option value="line">line</option>
</select>
</div>
<script>
const albumName = [
'2Cool4School', 'O!RUL8,2', 'School Love Affair', 'Dark&Wild',
'화양연화 pt.1', '화양연화 pt.2', 'Young Forever',
'WINGS', 'WINGS 외전', 'Love Yourself'
];
const albumNum = [
101637, 118170, 191444, 199090,
353063, 432740, 440367,
827947, 749954, 1376915
];
let chart;
let selected = false;
function createChart(type) {
const seriesData = type === 'pie'
? albumName.map((name, i) => ({
name: name,
y: albumNum[i]
}))
: albumNum;
chart = Highcharts.chart('container', {
chart: {
type: type
},
title: {
text: 'BTS Album Sale Rate'
},
subtitle: {
text: 'Ctrl+C → PNG Clipboard Copy'
},
credits: {
text: 'MTFIS'
},
xAxis: {
categories: albumName
},
yAxis: {
title: {
text: '앨범 판매량'
}
},
exporting: {
enabled: true,
local: true,
fallbackToExportServer: false
},
series: [{
name: 'Sale Rate',
data: seriesData
}]
});
}
async function copyChartToClipboard() {
try {
const svg = chart.getSVG();
const svgBlob = new Blob(
[svg],
{ type: 'image/svg+xml;charset=utf-8' }
);
const url = URL.createObjectURL(svgBlob);
const img = new Image();
img.onload = async function () {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
canvas.toBlob(async function (blob) {
await navigator.clipboard.write([
new ClipboardItem({
'image/png': blob
})
]);
alert('차트가 클립보드에 복사되었습니다.');
}, 'image/png');
URL.revokeObjectURL(url);
};
img.src = url;
} catch (err) {
console.error(err);
alert('복사 실패: 브라우저가 이미지 클립보드를 지원하는지 확인하세요.');
}
}
document.getElementById('container').addEventListener('click', function () {
selected = true;
this.classList.add('selected');
});
document.addEventListener('keydown', function (e) {
if (selected && e.ctrlKey && e.key.toLowerCase() === 'c') {
e.preventDefault();
copyChartToClipboard();
}
});
document.getElementById('ChType').addEventListener('change', function () {
createChart(this.value);
document.getElementById('container')
.classList.remove('selected');
selected = false;
});
createChart('column');
</script>
</body>
동작은 다음과 같다.
차트 생성 → 차트 클릭 → Ctrl + C → 차트 SVG 추출 → Canvas에 그림 → PNG 변환 → 클립보드 저장 → Ctrl+V
지금 보면 간단한 기능이지만 개발 초창기 시절의 삽질 기록을 남긴다는 의미로 정리해본다.
개인적으로 개발 블로그에서 가장 싫어하는 것 중 하나가 예제 코드는 있는데 복사는 막아놓은 글이기 때문에
내 블로그에 올라오는 모든 예제 코드는 복사가 가능하도록 작성하고 있다.
그래도 혹시 HTML 예제 파일 자체가 필요하다는 댓글이 있다면 수정 후 파일도 함께 첨부하도록 하겠다.
'IT SW 개발' 카테고리의 다른 글
| [Highcharts] 하이차트 Ctrl+C, Ctrl+V로 문서에 복사 붙여넣기_(1) (0) | 2026.06.17 |
|---|---|
| [Windows+Docker+Spring Boot+VScode] Window에서 Docker를 이용한 Spring Boot 환경 세팅_(1) (0) | 2026.06.11 |