Skip to content

Commit

Permalink
fix(api): Correct on exporting custom points
Browse files Browse the repository at this point in the history
- Do not replace '#' char, which makes not converting proper dataURL.
- Improved not evaluating node's dimension size.
- Replace the use of canvas.toBlob for .toDataURL, to expand the
coverage

Fix #541
Close #741
  • Loading branch information
netil committed Jan 21, 2019
1 parent 4eba766 commit f65bcfb
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 24 deletions.
68 changes: 56 additions & 12 deletions spec/api/api.export-spec.js
Expand Up @@ -7,20 +7,21 @@ import util from "../assets/util";

describe("API export", () => {
let chart;
let args = {
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 5000, 2000, 1000, 4000, 1500, 2500]
],
types: {
data1: "bar",
data2: "area"
}
}
};

beforeEach(() => {
chart = util.generate({
data: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 5000, 2000, 1000, 4000, 1500, 2500]
],
types: {
data1: "bar",
data2: "area"
}
}
});
chart = util.generate(args);
});

it("should invoke a callback when ready", done => {
Expand All @@ -46,4 +47,47 @@ describe("API export", () => {

chart.export("image/png", exportCallback);
});

it("set options", () => {
args = {
size: {
width: 100,
height: 150
},
data: {
columns: [
["data1", 3]
]
},
point: {
pattern: [
"<g><circle cx='10' cy='10' r='10'></circle><rect x='5' y='5' width='10' height='10' style='fill:#fff'></rect></g>"
]
},
axis: {
x: {
show: false
},
y: {
show: false,
min: 2.5,
max: 3
}
},
legend: {
show: false
}
}
})

it("shoul exported custom points properly?", done => {
const expectedDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAACWCAYAAAAouC1GAAAFk0lEQVR4Xu2ZS2hcZRiGv+9MK8UatWK9lFxcuXJhrF2487ZKJgoFC7pxI4pQEC+dRChaKkhmEkQISjfuiwUhnYmgLsSNK2MQ3biyM+MFxWgwpKbQnE+SoCYRORl9yDkH3lmG73/+/3+eOZkMcdOrUAa8UKfRYUxBCvYmUBAFKZiBgh1HT4iCgAbOfLxvYHV52NNk2NK43Sr2fUSy0P1mZcEunFgDd9ozVCmfkMGJ1qFYi/Pu/pC7rViEm3ufWSybeYTFdRH+0crvyYlfZkZ+2zObwEalCzJUa5409ykzO5B5/7ArqdkL3Ub17czZggyUKshArTWTuD1pZn09+FuOSN7pNEae72FNbqOlCTI03nojwp5138WTsUNnmK1axEynMVbLzfQuNy5FkIGJi8c89Q/c/dD6vSqJ274k++hX07C1NDZVRCxZUnmwPTmysEs3uYxl3yqXY23fdGi8tWRmN2z96dlH78o82SuzX22bCYvFTn3s5syFOQ4UPkj/S3NPVJL03OZfUX+/Lk2OZmq7Y2LuH0HC/GS3Xj2fuTingcIHGaq1ps3txZ1+/kuQzd9cMVXkz5LCBxmsNefd/R4siNl8p169N6cHIHPbwgcZqjV/NPdbqCAW8VO7MXZrppmcBgofZLDWWnS3m6ggYbbYqVcL+8FegiDNT939PiqIhX/Sbozen9MDkLlt4YMMjDdfS8xPU0HC7GynXn0100xOA4UP0l+bPV7xyjkzO/y//+yN+DnS5Knu9OhsTr4zty18kPUbDNZaX7rbtm+Cjx3tz7zchflvd8580a5X785cmONAKYLc9vL7h69J00tudu3Gd4kehG254Gq4HelMVn/tYfmej5YiyMZTcqr5nLm97u4bUXp5Rdhlj6i1p8be6mVdHrOlCbIuZ+DU3ONJEuufJ9fvWlbEUqTxTGf6kXd3vSbHwVIF2YgycfFYkvqHYb7f3Q7+m7uwuGzmVzyNh9tTY5/n6LinrUsX5M/bDY7PvWmRHjezI+6+EhGpuycRdtDdvkvD3us2qqX4p9TWYqUN8tclnv5sf/+NPwwn7neGp193D/Qt2JkHrvb0tizQcPmDFEgmcRQFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCDAUBZRIoBSEsggwFAWUSKAUhLIIMBQFlEigFISyCjD8ArsX8lwrNQzkAAAAASUVORK5CYII=";

setTimeout(() => {
chart.export("image/png", data => {
expect(data).to.be.equal(expectedDataURL);
done();
});
}, 500);
});
});
22 changes: 10 additions & 12 deletions src/api/api.export.js
Expand Up @@ -24,8 +24,7 @@ const b64EncodeUnicode = str => btoa(
* @return {String}
* @private
*/
const nodeToSvgDataUrl = node => {
const {width, height} = node.getBoundingClientRect();
const nodeToSvgDataUrl = (node, size) => {
const clone = node.cloneNode(true);
const styleSheets = toArray(document.styleSheets);
const cssRules = getCssRules(styleSheets);
Expand All @@ -37,12 +36,11 @@ const nodeToSvgDataUrl = node => {

// foreignObject not supported in IE11 and below
// https://msdn.microsoft.com/en-us/library/hh834675(v=vs.85).aspx
const dataStr = `<svg xmlns="${d3Namespaces.svg}" width="${width}" height="${height}">
const dataStr = `<svg xmlns="${d3Namespaces.svg}" width="${size.width}" height="${size.height}">
<foreignObject width="100%" height="100%">
<style>${cssText.join("\n")}</style>
${nodeXml}
${nodeXml.replace(/(url\()[^#]+/g, "$1")}
</foreignObject></svg>`
.replace(/#/g, "%23")
.replace("/\n/g", "%0A");

return `data:image/svg+xml;base64,${b64EncodeUnicode(dataStr)}`;
Expand Down Expand Up @@ -75,8 +73,10 @@ extend(Chart.prototype, {
* document.body.appendChild(link);
* });
*/
export(mimeType = "image/png", callback) {
const svgDataUrl = nodeToSvgDataUrl(this.element);
export(mimeType, callback) {
const $$ = this.internal;
const size = {width: $$.currentWidth, height: $$.currentHeight};
const svgDataUrl = nodeToSvgDataUrl(this.element, size);

if (isFunction(callback)) {
const img = new Image();
Expand All @@ -86,13 +86,11 @@ extend(Chart.prototype, {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

canvas.width = img.width;
canvas.height = img.height;
canvas.width = size.width;
canvas.height = size.height;
ctx.drawImage(img, 0, 0);

canvas.toBlob(blob => {
callback(window.URL.createObjectURL(blob));
}, mimeType);
callback(canvas.toDataURL(mimeType));
};

img.src = svgDataUrl;
Expand Down

0 comments on commit f65bcfb

Please sign in to comment.