https://jsfiddle.net/Abhi_Solanki/9yktct3z/3/ here fiddle link..what i am trying to do is to show the same output as the highcharts show when it is exported in PDF format or SVG format, infact in this code i have used the same function that is used to generate SVG file of Highcharts the output of that seems proper to me but the problem arises when i pass that variable into canvg.js file calling canvg at function that time the output of the image gets blurry where i want the output to remain same as it is without pixels getting blurred as it is same in the highcharts pdf. as i have to display that image of chart in a pdf file so please help. code is as below.
var svgres = chart.getSVG();
var svgArr = [],
top = 0,
height = 0,
width = 0,
col=0;
svgCustDim = 400;
var svgWidth = 600,
svg = svgres.replace('<svg', '<g transform="translate(' + col * svgWidth + ',' + top + ')" ');
svg = svg.replace('</svg>', '</g>');
svg = '<svg height="' + svgCustDim + '" width="' + svgCustDim*(3)+ '" version="1.1" xmlns="http://www.w3.org/2000/svg">' + svg + '</svg>';
canvg('canvas', svg);
var canvas = document.getElementById('canvas');
return canvas.toDataURL("image/jpeg");
The version of canvg used in the demo page on github is buggy. If i take the script from here https://github.com/canvg/canvg/blob/master/canvg.js and paste it in the fiddle it works fine.
You can read more about it here https://github.com/canvg/canvg/issues/486.
Also your canvas is a lot bigger than the image, you can take the chart width and height so that the canvas is the same dimension as the chart.
svgCustDim = chart.chartHeight;
var svgWidth = chart.chartWidth,
svg = svgres.replace('<svg', '<g');
svg = svg.replace('</svg>', '</g>');
svg = '<svg height="' + svgCustDim + '" width="' + svgWidth+ '" version="1.1" xmlns="http://www.w3.org/2000/svg">' + svg + '</svg>';
Here is a fiddle with the canvg.js taken from the url above and the changes so that your canvas is the same dimension as your chart https://jsfiddle.net/9yktct3z/6/
Note that it appear that the minified version (canvg.min.js) is
if you want a bigger resolution image remove the height and width from you chart container
<div id="container" style="margin: 0 auto"></div>
and set them in the chart option, i used 2000*2000 but you play around with the values
chart: {
height: 2000,
width: 2000,
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
here is the full fiddle https://jsfiddle.net/9yktct3z/10/
Related
I want to put some images as SVG on each point in Gantt chart, I've tried something like below:
function (chartt) { // on complete
chartt.renderer.image('imageURL.png',100,100,30,30)
.add();
}
But after running this code, the image will be shown on the corner of the page. I want to draw images on each point in the chart and set their position related to its point.
Live Demo: https://jsfiddle.net/meysamm22/x41wdu5z/
You need to use the right x and y attributes, calculate them based on plotX and plotY point's properties:
function(chartt) { // on complete
var points = chartt.series[0].points,
width = 30,
height = 30;
points.forEach(function(point) {
chartt.renderer.image(
'https://www.highcharts.com/images/employees2014/Torstein.jpg',
point.plotX + chartt.plotLeft + point.shapeArgs.width / 2 - width / 2,
point.plotY + chartt.plotTop - height / 2,
width,
height
)
.attr({
zIndex: 5
})
.add();
});
});
Live demo: https://jsfiddle.net/BlackLabel/r4ph3ykz/
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#image
I'm finding a potential bug in KonvaJS. Or I'm not sure about the capabilities...
1) Create a layer and add it to stage
2) Create a group and add it to layer
3) Create an Image node and add it to group (Note my images are loaded using Konva.Image.fromURL which waits for the image to load then adds it to the group.)
Result: Image does not appear.
But if you add the image to the group then add the group to the layer, the image appears. This is going to cause problems if I want to attach an image to a group dynamical if it just disappears.
I'm trying to create the concept of a tray or plate. Where the user can place items onto the plate. If the user drags the plate it creates a group with all the intersecting nodes and moves them all together. At drag end it releases all the objects back to the user.
EDIT: The problem I was experiencing had to do with group coordinates as I mentioned in my comment bellow.
"I think I misunderstood, for the longest time how positioning works with groups. Read the comments: jsfiddle.net/jusatx6s"
LL: Make sure you're checking the position of the nodes your are rendering and that they do appear on screen.
I have created a plunkr and followed steps which you have mentioned. Everything is working fine. Here's my code.
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
// 1. created layer added it to stage.
var layer = new Konva.Layer();
stage.add(layer);
// 2. created group added it to layer
var group = new Konva.Group({
x: 120,
y: 40,
rotation: 20
});
layer.add(group);
var src = 'https://konvajs.github.io/assets/yoda.jpg';
// 3. Create an Image node and add it to group
Konva.Image.fromURL(src, function(yoda) {
console.log(yoda);
yoda.setAttrs({
x: 50,
y: 50,
width: 106,
height: 118
});
// 4. Add it to group.
group.add(yoda);
layer.batchDraw(); // It's required to draw changes.
});
Here's the plnkr to play around. Please let me know if I have missed anything.
Edited in light of OP's edit re confusion over co-ordinates.
Principles:
layers use the same co-ordinate system as the stage. So setting a shape position to {X: 10, y: 20} is at 10,20 in relation to the top left of the stage.
Adding a shape to a group is different, but you will not notice this if you do not set the group x & y position. For shapes that are added to the group, the shape positions are ADDED to the parent group positions.
Here is an example using a layer and a group. The gold rect is on the layer only. The group is illustrated by the green rect and has been set to position (60, 50). The red rect is a copy of the gold rect except the color. It has the same x & y position as red, BUT it is added to the group. And so its position (5, 5) is added to the group position (60, 50) to give its absolute position on the stage as (65, 55).
// add a stage
var s = new Konva.Stage({
container: 'container',
width: 400,
height: 400
});
// add a layer
var l = new Konva.Layer();
s.add(l);
// Add a gold rect to the LAYER
var gold = new Konva.Rect({stroke: 'gold', width: 40, height: 50, x: 5, y: 5});
l.add(gold);
// add a group
var g = new Konva.Group({x:60, y:50});
l.add(g);
// Add a green rect to the LAYER then add to the group
var green = new Konva.Rect({stroke: 'lime', width:100, height: 100, x: 0, y: 0});
g.add(green);
// Add a red rect, same apparent co-ords as red, but this time to the group
var red = new Konva.Rect({stroke: 'red', width: 40, height: 50, x: 5, y: 5});
g.add(red);
var abspos = red.getAbsolutePosition();
var pos = red.position();
console.log('Abs position of red is (' + abspos.x + ', ' + abspos.y + ') but its co-ords are ' + '(' + pos.x + ', ' + pos.y + ')');
l.draw(); // redraw the layer it all sits on.
#container {
border: 1px solid #ccc;
}
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.2/konva.min.js"></script>
<body>
<div id="container"></div>
</body>
I'm trying to position custom labels on the outside of a polar chart but can't figure out any way to do it. Please image below for what I'm trying to achieve.
Doesn't have to use the actual series labels but haven't found anything else that can be positioned relative to the actual chart (top level labels can be positioned anywhere but only using absolute left and top).
Have also tried changing the pointPlacement and tickmarkPlacement to "between" which sort of works but it rotates the actual chart so I get a diamond shape instead of a square, the effect I'm after would be more like rotating the labels and leaving the ticks in place.
IN such case custom labels can be positioned relative to grid line group.
Method for drawing the labels:
function drawLabels () {
let labels = this.customLabels,
bbox = this.xAxis[0].gridGroup.getBBox(),
positions = [
[bbox.x + bbox.width / 2, bbox.y],
[bbox.x + bbox.width, bbox.y + bbox.height / 2],
[bbox.x + bbox.width / 2, bbox.y + bbox.height],
[bbox.x, bbox.y + bbox.height / 2]
];
if (!labels) {
labels = this.customLabels = ['lab1', 'lab2', 'lab3', 'lab4'].map(text => this.renderer.label(text, 0, -9999).add().attr({zIndex: 4}));
}
labels.forEach((label, i) => {
label.align({
align: 'center',
verticalAlign: 'middle',
width: label.width,
height: label.height
}, null, {
x: positions[i][0],
y: positions[i][1],
width: 0,
height: 0
});
});
}
Draw labels on load/redraw:
Highcharts.chart('container', {
chart: {
polar: true,
type: 'line',
events: {
load: drawLabels,
redraw: drawLabels
}
},
example: http://jsfiddle.net/d6y1bn31/
Still in the process of improving my competence about D3, I got stuck with a problem where I'm trying to plot a zoomable curve in a SVG element with margins (so that I need a clipPath rect to avoid that plot invades margins when zoomed) but the clipPath margins cut the display of d3.symbols off the plot.
This is the relevant code for the plot
var margin = {top: 20, right: 60, bottom: 30, left: 30},
w = 960 - margin.left - margin.right,
h = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", h);
// The curve I want to plot: y=x^2
var my_curve = d3.range(10).map(function(d) { var my_y = d * d; return { "x" : d, "y" : my_y }; });
var x_range_min = d3.min(my_curve, function(d) { return d.x; });
var x_range_max = d3.max(my_curve, function(d) { return d.x; });
var y_range_min = d3.min(my_curve, function(d) { return d.y; });
var y_range_max = d3.max(my_curve, function(d) { return d.y; });
var xScale = d3.scaleLinear().domain([x_range_min, x_range_max]).range([0, w]);
var yScale = d3.scaleLinear().domain([y_range_max, y_range_min]).range([0, h]);
var xAxis = d3.axisBottom().scale(xScale);
var yAxis = d3.axisLeft().scale(yScale);
// symbols
svg.selectAll(".my_pts").data(my_curve).enter().append("path")
.attr("class", "my_pts")
.attr("d", d3.symbol().type(d3.symbolTriangle).size(200))
.attr("transform", function(d) { return "translate(" + xScale(d.x) + "," + yScale(d.y) + ")"; })
// with this zoomed line does not enter margin area
.attr("clip-path", "url(#clip)");
...as you can see only part of the triangle symbol is depicted, I guess because the path is drawn at 0,0 and cut by the clipPath before the translation can be performed.
I have also posted this fiddle https://jsfiddle.net/fabio_p/988c1sjv/
where you can find a more complete version of the code, with the brush & zoom function, so that you can see why the clipPath is needed (if you have never encountered the issue with margins before)
My question is the following: is there a workaround to this problem? I was hoping to find a way to directly draw the symbol in the right place without the need of a later translation (possibly with a "custom symbol type"), but it seems it goes beyond my current skills, since I was unable to produce any actual solution.
Any suggestion would be welcome. Thanks in advance.
Create a group with the clip path:
var clipping = svg.append("g")
.attr("clip-path", "url(#clip)");
And append both the line and the symbols to the group:
clipping.append("path")
.data([my_curve])
//etc...
Here is your updated fiddle: https://jsfiddle.net/cvtvrL2q/
How can I calculate the height of a bar chart so that for different number of bars, highcharts always use the same height for a single bar. Without setting any height the size of the bars are to large for a minor number and to thin and missing labels for larger number of bars.
You can do it by dynamic change of height of your chart in dependence on your data length.
http://api.highcharts.com/highcharts#chart.height
chart: {
marginTop: 40,
marginBottom: 80,
height: data.length * 20 + 120 // 20px per data item plus top and bottom margins
}
jsFiddle made by Torstein Hønsi:
http://jsfiddle.net/highcharts/jMX8G/
Similar Topic:
https://highcharts.uservoice.com/forums/55896-highcharts-javascript-api/suggestions/3456724-size-height-of-bar-graph-based-on-contents-when-co
You can also see custom function I wrote. Inside it I am iterating over all of my series data and making a sum of all visible data. Then I am setting the height of my chart with width of my column (passed in function parameter), number of columns, marginBottom and plotTop of my chart.
at the end if this size is different than previous size of chart I am setting new size of chart with Chart.setSize():
http://api.highcharts.com/highcharts#Chart.setSize
example:
http://jsfiddle.net/izothep/d3ezek8t/1/
I have a similar set up that I use, I will post here for posterity:
http://jsfiddle.net/jlbriggs/kpu5d1qf/
Uses a set of variables to define the chart/bar sizing parameters, and works from there.
//count the data points
var barCount = chartData.length;
//specify chart properties that will be used to calculate the total height
var pointWidth = 20;
var marginTop = 60;
var marginRight = 10;
var marginBottom = 50;
var marginLeft = 100;
var groupPadding = 0;
var pointPadding = 0.3;
var chartHeight = marginTop
+ marginBottom
+ ((pointWidth * barCount) * (1 + groupPadding + pointPadding));
And in the chart options, for example:
chart: {
type : 'bar',
marginTop : marginTop,
marginRight : marginRight,
marginBottom : marginBottom,
marginLeft : marginLeft,
height : chartHeight
},
So you can edit all of the properties that might affect the height of the chart outside of the chart options, and all are accounted for when calculating the final height.