我使用我在Github上找到的James Alvarez的Draggable Pie Chart插件创建了一个交互式饼图。我决定使用图像作为每个饼图的标签而不是文本。我有饼图显示和按预期运行,但我对标签图像的显示方式有疑问。
问题在于标签图像必须与饼图一起旋转/翻译,以便它们具有正确的位置,这会导致徽标显示为颠倒。
我希望一切都保持原样,但标志始终是正确的。这可能在canvas元素中吗?
这是我的代码: https://jsfiddle.net/uwx3vv7c/
HTML:
<div id="piechart-controls">
<canvas id="piechart" width="400" height="400">Your browser is too old!</canvas>
<div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn4.iconfinder.com/data/icons/seo-web-15/465/web-user-interface_49-128.png">
<span class="mixPercentage">33%</span>
</div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn3.iconfinder.com/data/icons/picons-social/57/46-facebook-128.png">
<span class="mixPercentage">33%</span>
</div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn3.iconfinder.com/data/icons/picons-social/57/43-twitter-128.png">
<span class="mixPercentage">34%</span>
</div>
</div>
</div>
JS:
(function($){
$(window).ready(setupPieChart);
function setupPieChart() {
let proportions = [
{ proportion: 45, format: { image: "https://cdn4.iconfinder.com/data/icons/seo-web-15/465/web-user-interface_49-128.png" }},
{ proportion: 30, format: { image: "https://cdn3.iconfinder.com/data/icons/picons-social/57/46-facebook-128.png" }},
{ proportion: 25, format: { image: "https://cdn3.iconfinder.com/data/icons/picons-social/57/43-twitter-128.png" }}
];
let setup = {
canvas: document.getElementById('piechart'),
radius: 0.9,
collapsing: false,
proportions: proportions,
drawSegment: drawSegmentOutlineOnly,
onchange: onPieChartChange,
minAngle: 1.575
};
let newPie = new DraggablePiechart(setup);
// initial drawing function for pie chart
function drawSegmentOutlineOnly(context, piechart, centerX, centerY, radius, startingAngle, arcSize, format, collapsed) {
if (collapsed) { return; }
// Draw segment
context.save();
let endingAngle = startingAngle + arcSize;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, radius, startingAngle, endingAngle, false);
context.closePath();
context.fillStyle = '#666';
context.fill();
context.stroke();
context.restore();
// Draw image
context.save();
context.translate(centerX, centerY);
context.rotate(startingAngle);
let iconHeight = Math.floor(context.canvas.height / 5);
let iconWidth = Math.floor(context.canvas.width / 5);
let dx = (radius / 2) - (iconWidth/2);
let dy = (radius / 2) - (iconHeight/2);
let flavorImage = new Image();
flavorImage.src = format.image;
context.drawImage(flavorImage, dx, dy, iconWidth, iconHeight);
context.restore();
}
// update the percentages when the pieces are adjusted
function onPieChartChange(piechart) {
let percentages = piechart.getAllSliceSizePercentages();
let percentLabels = $(".mixPercentage");
for (let i = 0; i < percentages.length; i++) {
percentLabels.eq(i).html(percentages[i].toFixed(0) + "%");
}
}
}
})(jQuery);
我尝试了几件事,包括:
不能旋转和翻译图像,但会导致图像无法正常显示
使用图像作为背景图案,而不是将它们实际绘制为画布上下文的一部分,但它可以平铺图像或将其拉伸到完整饼图的大小。
奖金问题 - 在饼图中垂直和水平居中的任何方式?
答案 0 :(得分:0)
要绘制旋转和缩放的图像,请使用以下功能
// ctx is the 2D context
// image is the image to draw
// x,y where on the canvas the image center will be
// the scale 1 is no change, < 1 is smaller, > 1 is larger
// angle in radians to rotate the image
function drawImage(ctx, image, x, y, scale, angle){
ctx.setTransform(scale, 0, 0, scale, x, y);
ctx.rotate(angle);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform
// not really needed if you call this
// function many times in a row.
// You can restore the default afterwards
}
如果您需要镜像图像,以下功能将有所帮助,只需将图像轴的比例设置为负片,例如drawImage(ctx,image,100,100,1,-1,0);
将图像上下颠倒。
// ctx is the 2D context
// image is the image to draw
// x,y where on the canvas the image center will be
// the scaleX, scaleY 1 is no change, < 1 is smaller, > 1 is larger
// angle in radians to rotate the image
function drawImageMirror(ctx, image, x, y, scaleX, scaleY, angle){
ctx.setTransform(scaleX, 0, 0, scaleY, x, y);
ctx.rotate(angle);
ctx.drawImage(image, -image.width / 2, -image.height / 2);
ctx.setTransform(1, 0, 0, 1, 0, 0); // restore default transform
// not really needed if you call this
// function many times in a row.
// You can restore the default afterwards
}
在饼图的中心绘制,用
绘制外部曲线context.arc(centerX, centerY, radius, startingAngle, endingAngle, false);
使用第一个功能
const scale = Math.min(canvas.width / 5, canvas.height / 5) / flavorImage.width;
const imgSize = flavorImage.width * scale;
const centerAngle = (startingAngle + endingAngle) / 2;
const angle = 0; // for image directions see comment below
drawImage(
context,
flavorImage,
Math.cos(centerAngle) * (radius - imgSize) + centerX,
Math.sin(centerAngle) * (radius - imgSize) + centerY,
scale,
angle,
);
// or if you want the top of image to face center use next line
// const angle = centerAngle - Math.PI / 2;
// or if you want the bottom of image to face center use next line
// const angle = centerAngle + Math.PI / 2;
答案 1 :(得分:0)
您的库为您提供了必须使用arc()
方法的起始角度。它还为您提供了arcLength和中心坐标。
您似乎已经能够绘制弧段,但要绘制图像,您需要进行一些调整。
首先,您将上下文的矩阵移动到饼图的中心, 然后您将找到旋转角度,以便您面向当前线段的中间,然后在Y轴上移动到图像的中心位置,最后,您将旋转线段旋转的倒数来制作图像正常面对。
// you've got starting angle for arc() method,
// which itself starts at 3'oclock, while the matrix is noon based
// so we subtract half PI from the starting angle and add half arcSize to get to the middle
let rotationAngle = -Math.PI / 2 + (startingAngle + (arcSize / 2));
// distance from center
let distance = (radius / 2);
// position our pointer to the center of the canvas
context.translate(centerX, centerY);
// rotate it so we face the middle of the arc
context.rotate(rotationAngle);
// move on the Y axis
context.translate(0, distance);
// now we are at the center X&Y of our arc segment
// inverse current rotation
context.rotate(-rotationAngle);
// draw the image
context.drawImage(format.image, -iconWidth / 2, -iconHeight / 2, iconWidth, iconHeight);
(function($) {
$(window).ready(setupPieChart);
function setupPieChart() {
// Instead of storing only the images' src, store directly the HTMLImg elements.
// Will avoid huge amount of useless loadings
let proportions = [{
proportion: 45,
format: {
image: Object.assign(new Image, {
src: "https://cdn4.iconfinder.com/data/icons/seo-web-15/465/web-user-interface_49-128.png"
})
}
},
{
proportion: 30,
format: {
image: Object.assign(new Image, {
src: "https://cdn3.iconfinder.com/data/icons/picons-social/57/46-facebook-128.png"
})
}
},
{
proportion: 25,
format: {
image: Object.assign(new Image, {
src: "https://cdn3.iconfinder.com/data/icons/picons-social/57/43-twitter-128.png"
})
}
}
];
let setup = {
canvas: document.getElementById('piechart'),
radius: 0.9,
collapsing: false,
proportions: proportions,
drawSegment: drawSegmentOutlineOnly,
onchange: onPieChartChange,
minAngle: 1.575
};
let newPie = new DraggablePiechart(setup);
// initial drawing function for pie chart
function drawSegmentOutlineOnly(context, piechart, centerX, centerY, radius, startingAngle, arcSize, format, collapsed) {
if (collapsed) {
return;
}
// because the library needs it for anchors...
context.save();
// reset context's matrix
context.setTransform(1, 0, 0, 1, 0, 0);
// Draw segment
let endingAngle = startingAngle + arcSize;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, radius, startingAngle, endingAngle, false);
context.closePath();
context.fillStyle = '#666';
context.fill();
context.stroke();
// Draw image
// you've got starting angle for arc() method, which itself starts at 3'oclock, while the matrix is noon based
// so we subtract half PI from the starting angle and add half arcSize to get to the middle
let rotationAngle = -Math.PI / 2 + (startingAngle + (arcSize / 2));
let iconHeight = Math.floor(context.canvas.height / 5);
let iconWidth = Math.floor(context.canvas.width / 5);
// distance from center
let distance = (radius / 2);
// position our pointer to the center of the canvas
context.translate(centerX, centerY);
// rotate it so we face the middle of the arc
context.rotate(rotationAngle);
// move on the Y axis
context.translate(0, distance);
// now we are at the center X&Y of our arc segment
// inverse current rotation
context.rotate(-rotationAngle);
// draw the image
context.drawImage(format.image, -iconWidth / 2, -iconHeight / 2, iconWidth, iconHeight);
// because the library needs it for anchors...
context.restore();
}
// update the percentages when the pieces are adjusted
function onPieChartChange(piechart) {
let percentages = piechart.getAllSliceSizePercentages();
let percentLabels = $(".mixPercentage");
for (let i = 0; i < percentages.length; i++) {
percentLabels.eq(i).html(percentages[i].toFixed(0) + "%");
}
}
}
})(jQuery);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/jamesalvarez/draggable-piechart/master/draggable-piechart.js?ver=4.9"></script>
<div id="piechart-controls">
<canvas id="piechart" width="400" height="400">Your browser is too old!</canvas>
<div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn4.iconfinder.com/data/icons/seo-web-15/465/web-user-interface_49-128.png">
<span class="mixPercentage">33%</span>
</div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn3.iconfinder.com/data/icons/picons-social/57/46-facebook-128.png">
<span class="mixPercentage">33%</span>
</div>
<div class="percentWrapper" style="display: inline-block;">
<img src="https://cdn3.iconfinder.com/data/icons/picons-social/57/43-twitter-128.png">
<span class="mixPercentage">34%</span>
</div>
</div>
</div>