Can You Draw Canvas on Svg Element
How to capture HTML and SVG into an image | Toucan Toco
Table of Contents
                       This article will tell you how we managed to transform part of our app (mix of HTML & SVG elements) into an image. We recently did an internal hackathon, where we all stopped working on our daily job to tackle fun and              nice to have              features that we would otherwise not prioritize. It was a great day of creativity and we had a lot of fun. What we wanted              and succeeded ;)              to achieve was a feature allowing one of our user to capture an image of a chart, add some annotation, and send the annotated image by email. This feature can be useful if you want to share some noteworthy data with someone who is not necessarily authorized on the app, or if you'd like to draw a cat on              Toucan Toco's dataviz, whatever floats your boat. The general idea is this:              HTML&SVG » Canvas » Image.              I've seen a lot of resources on the subject, but all of them addressed only parts of that pipeline, not the whole, and none worked in a satisfying way out of the box:              When              it worked, the styles would be wrong, fonts would be wrong, some SVG elements wouldn't display etc… Since we went through a lot of trials an errors to get a good result, I thought I'd spare you the trouble. What you want is to put your HTML and SVG elements into a canvas. For this to look good, you will need to inline all computed styles. Because if you only copy HTML, styles coming from stylesheets will not be copied with it. To quickly hack it we shamelessly copied the                               gotcha number 1:                We had to make a modification to the crowbar code: The SVG we are parsing is handled with                d3.js, and elements like                                 Note:                In the SVG crowbar, the code was designed for SVG only, we used it on a div containing SVG and it worked fine. Now that we have properly copied our styles, so let's draw that onto a canvas.                The rest is pretty simple: you copy the               You can see we manually added a               You can probably try and detect the font face from your stylesheet, then find the font-family used and add the rules accordingly (Some SO resources here and here – I have not tried this). In my case I have only one font, and I know which, so I just added it.                 Note 1:                I get an error in the console (chrome) that does not seem to affect the end result:                                 Note 2:                A nice bonus is the fact that we use                d3.js zoom                to handle scrolling, and thanks to this method, the chart will be captured at the right scroll level, since it's all transforms :) I'm not gonna detail here how to make a Paint like feature using canvas, there's plenty of resources out there. Personnally, I used this tutorial. This is very very simple. In my case, I wanted the user to be able to send an email to someone with the image attached. This is sadly not possible with a                               Note:                The image will have a transparent background. You might need to set the background color on your element before exporting if this is an issue. The chart is in SVG, done using d3.js, the grey block to the right is HTML. I hope you appreciate the quality of my doodle. The original chart               the canvas+doodle version               We've succeeded in getting a doodled capture of a part of our app! Hope this was useful to you. I would love some feedbacks, so please do comment ! ;) Sophie Despeisse, dev @ Toucan Toco              
            Inline your styles
            setInlineStyles              from SVG Crowbar This method will parse the DOM,              getComputedStyle              on each element, and inline these styles.              
            rect                for instance already have a width and height set. As a result, we had to exclude some styles on SVG elements :                width,                height,                min-width                and                min-height. I'm not sure why, and whether it's specific to d3.js.                If you do know, leave a comment!                            
                            
                              // Set Inline Styles method                  function                  setInlineStyles                  (                  svg                  )                  {                  function                  explicitlySetStyle                  (                  element                  )                  {                  var                  cSSStyleDeclarationComputed                  =                  getComputedStyle                  (                  element                  );                  var                  i                  ,                  len                  ,                  key                  ,                  value                  ;                  var                  svgExcludedValues                  =                  [                  '                  height                  '                  ,                  '                  width                  '                  ,                  '                  min-height                  '                  ,                  '                  min-width                  '                  ];                  var                  computedStyleStr                  =                  ""                  ;                  for                  (                  i                  =                  0                  ,                  len                  =                  cSSStyleDeclarationComputed                  .                  length                  ;                  i                  <                  len                  ;                  i                  ++                  )                  {                  key                  =                  cSSStyleDeclarationComputed                  [                  i                  ];                  if                  (                  !                  ((                  element                  instanceof                  SVGElement                  )                  &&                  svgExcludedValues                  .                  indexOf                  (                  key                  )                  >=                  0                  ))                  {                  value                  =                  cSSStyleDeclarationComputed                  .                  getPropertyValue                  (                  key                  );                  computedStyleStr                  +=                  key                  +                  "                  :                  "                  +                  value                  +                  "                  ;                  "                  ;                  }                  }                  element                  .                  setAttribute                  (                  '                  style                  '                  ,                  computedStyleStr                  );                  }                  function                  traverse                  (                  obj                  ){                  var                  tree                  =                  [];                  tree                  .                  push                  (                  obj                  );                  visit                  (                  obj                  );                  function                  visit                  (                  node                  )                  {                  if                  (                  node                  &&                  node                  .                  hasChildNodes                  ())                  {                  var                  child                  =                  node                  .                  firstChild                  ;                  while                  (                  child                  )                  {                  if                  (                  child                  .                  nodeType                  ===                  1                  &&                  child                  .                  nodeName                  !=                  '                  SCRIPT                  '                  ){                  tree                  .                  push                  (                  child                  );                  visit                  (                  child                  );                  }                  child                  =                  child                  .                  nextSibling                  ;                  }                  }                  }                  return                  tree                  ;                  }                  // hardcode computed css styles inside SVG                  var                  allElements                  =                  traverse                  (                  svg                  );                  var                  i                  =                  allElements                  .                  length                  ;                  while                  (                  i                  --                  ){                  explicitlySetStyle                  (                  allElements                  [                  i                  ]);                  }                  }                  // Use the setInlineStyles method                  var                  elementToExport                  =                  document                  .                  querySelector                  (                  '                  #stuff-container                  '                  );                  setInlineStyles                  (                  elementToExport                  );                              Draw me like one of your French apps
            
            innerHTML              and draw it on a HTML canvas. I used rasterizehtml.                
                              var                  rasterize                  =                  require                  (                  '                  rasterizehtml                  '                  );                  // More on the font face below                  var                  fontFaceRule                  =                  "                  <style>                  \n                  @font-face {                  \n                                      font-family:                                    \"                  Montserrat                  \"                  ;                  \n                                      src: url('../fonts/Montserrat-Regular.ttf') format('truetype');                  \n                  }                  \n                  </style>                  "                  ;                  // Get the html with inlined styles                  var                  htmlContent                  =                  fontFaceRule                  +                  elementToExport                  .                  innerHTML                  ;                  // Create a canvas element                  var                  canvas                  =                  document                  .                  createElement                  (                  '                  canvas                  '                  );                  canvas                  .                  setAttribute                  (                  '                  id                  '                  ,                  '                  canvas                  '                  );                  // Set the width and height of the canvas to match the element's                  canvas                  .                  width                  =                  elementToExport                  .                  getBoundingClientRect                  ().                  width                  ;                  canvas                  .                  height                  =                  elementToExport                  .                  getBoundingClientRect                  ().                  height                  ;                  // Append the canvas to your page, this does not have to be done on the body                  document                  .                  body                  .                  appendChild                  (                  canvas                  );                  // Draw the HTML                  rasterize                  .                  drawHTML                  (                  htmlContent                  ,                  canvas                  );                              @font-face              rule. This is due to              another gotcha: if your font is not a standard font, you will need to add this rule.              
                          
            Blocked script execution in 'about:blank' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.                            
            Doodle
            Get the resulting image
                            
                              // Get the Base64 image                  var                  imageURL                  =                  canvas                  .                  toDataURL                  (                  "                  image/png                  "                  );                  // Assuming you have a #png-container div somewhere                  document                  .                  querySelector                  (                  '                  #png-container                  '                  ).                  innerHTML                  =                  '                  <img src="                  '                  +                  imageURL                  +                  '                  "/>                  '                  ;                  // Or you might want to download the image                  // I did not use this method, so you might want to refine it a bit                  window                  .                  location                  .                  href                  =                  imageURL                  .                  replace                  (                  "                  image/png                  "                  ,                  "                  image/octet-stream                  "                  );                              mailto, so the dataurl was sent to our back-end for the rest of the feature.              
            The result
            
            
            
Can You Draw Canvas on Svg Element
Source: https://www.toucantoco.com/en/tech-blog/capture-your-html