-
Notifications
You must be signed in to change notification settings - Fork 0
Feature/snapshot #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
547f2b5
89e05ce
fb52fe7
4436f3c
760a93b
cff741a
937340c
ac86931
ef09066
099acf3
a223546
1f09a8e
00623e2
1f7c8e3
4b618db
e1b031e
dc33644
5116a84
8fbf716
e7da65d
74e9bf0
9a8559e
166724b
9dc9423
13eef9f
f124a03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# Plotly Snapshots | ||
|
||
## Purpose | ||
The purpose of this markdown document is to document exploration of how to best attach the `Plotly.Snapshot.toImage` function to the plot/`div` itself most fully discussed in [issue 83](https://github.com/plotly/plotly.js/issues/83). Another very nice ability would be to offer resize options for the snapshot. | ||
|
||
|
||
|
||
## Questions | ||
Where do we attach toImage on the graph div? | ||
Is it _toImage? | ||
Do we just require /snapshot and bind to `this`? | ||
|
||
Will any of the chart types require special snapshot abilities or features? | ||
|
||
What is the expected use case of our new ability? | ||
|
||
How do we piggyback on the snapshot button in the toolbar? | ||
|
||
How do we ask for new size? | ||
|
||
Are there reference points from other libraries that we could mimic or learn from? | ||
|
||
|
||
## Thoughts | ||
|
||
- `Plotly.Snapshot.clone` could be used to resize by adding this to `options` when/if we use `Plotly.plot` with our cloned `div`. We could also dynamically show a resulting view in a modal or something similar and adjust with `Plotly.relayout`. | ||
|
||
- `Plotly.Snapshot.clone` by default sets `staticPlot:true` in `config`. | ||
|
||
- A very basic way to attach this assuming there is a modebar would be to do something like this. See [codepen](http://codepen.io/timelyportfolio/pen/ZWvyYM). | ||
``` | ||
gd._toImage = function(){ | ||
this._fullLayout._modeBar.buttons.filter( | ||
function(btn){return btn[0].name==="toImage" | ||
})[0][0].click(this) | ||
} | ||
``` | ||
|
||
- `Plotly.Snapshot.clone` already has thumbnail ability by specifying [options tileClass:"thumbnail"](https://github.com/plotly/plotly.js/blob/master/src/snapshot/cloneplot.js#L76) for the specific thumbnail use case. | ||
|
||
|
||
|
||
- Quick code to experiment from R | ||
``` | ||
library(plotly) | ||
|
||
ggplotly(ggplot(cars,aes(speed,dist))+geom_point()) | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,62 +9,61 @@ | |
|
||
'use strict'; | ||
|
||
var EventEmitter = require('events').EventEmitter; | ||
|
||
function svgToImg(opts) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the solution would be to make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, I'll get that working. Maybe in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's the goal. We un-exposed
Exactly. So that |
||
|
||
var ev = opts.emitter ? opts.emitter : new EventEmitter(); | ||
|
||
var Image = window.Image; | ||
var Blob = window.Blob; | ||
|
||
var svg = opts.svg; | ||
var format = opts.format || 'png'; | ||
var canvas = opts.canvas; | ||
|
||
var ctx = canvas.getContext('2d'); | ||
var img = new Image(); | ||
var DOMURL = window.URL || window.webkitURL; | ||
var svgBlob = new Blob([svg], {type: 'image/svg+xml;charset=utf-8'}); | ||
var url = DOMURL.createObjectURL(svgBlob); | ||
|
||
canvas.height = opts.height || 150; | ||
canvas.width = opts.width || 300; | ||
|
||
img.onload = function() { | ||
var imgData; | ||
|
||
DOMURL.revokeObjectURL(url); | ||
ctx.drawImage(img, 0, 0); | ||
|
||
switch(format) { | ||
case 'jpeg': | ||
imgData = canvas.toDataURL('image/jpeg'); | ||
break; | ||
case 'png': | ||
imgData = canvas.toDataURL('image/png'); | ||
break; | ||
case 'webp': | ||
imgData = canvas.toDataURL('image/webp'); | ||
break; | ||
case 'svg': | ||
imgData = svg; | ||
break; | ||
default: | ||
return ev.emit('error', 'Image format is not jpeg, png or svg'); | ||
} | ||
|
||
ev.emit('success', imgData); | ||
}; | ||
|
||
img.onerror = function(err) { | ||
DOMURL.revokeObjectURL(url); | ||
return ev.emit('error', err); | ||
}; | ||
|
||
img.src = url; | ||
|
||
return ev; | ||
var promise = new Promise(function(resolve, reject) { | ||
|
||
var Image = window.Image; | ||
var Blob = window.Blob; | ||
|
||
var svg = opts.svg; | ||
var format = opts.format || 'png'; | ||
var canvas = opts.canvas; | ||
|
||
var ctx = canvas.getContext('2d'); | ||
var img = new Image(); | ||
var DOMURL = window.URL || window.webkitURL; | ||
var svgBlob = new Blob([svg], {type: 'image/svg+xml;charset=utf-8'}); | ||
var url = DOMURL.createObjectURL(svgBlob); | ||
|
||
canvas.height = opts.height || 150; | ||
canvas.width = opts.width || 300; | ||
|
||
img.onload = function() { | ||
var imgData; | ||
|
||
DOMURL.revokeObjectURL(url); | ||
ctx.drawImage(img, 0, 0); | ||
|
||
switch(format) { | ||
case 'jpeg': | ||
imgData = canvas.toDataURL('image/jpeg'); | ||
break; | ||
case 'png': | ||
imgData = canvas.toDataURL('image/png'); | ||
break; | ||
case 'webp': | ||
imgData = canvas.toDataURL('image/webp'); | ||
break; | ||
case 'svg': | ||
imgData = svg; | ||
break; | ||
default: | ||
reject(new Error('Image format is not jpeg, png or svg')); | ||
} | ||
|
||
resolve(imgData); | ||
}; | ||
|
||
img.onerror = function(err) { | ||
DOMURL.revokeObjectURL(url); | ||
reject(err); | ||
}; | ||
|
||
img.src = url; | ||
}); | ||
|
||
return promise; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, making There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @timelyportfolio I should have mentioned ⏫ to you before, my mistake. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no problem, I should have asked. |
||
|
||
module.exports = svgToImg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's put
toSnapshot
in a new file calledsrc/plot_api/to_image.js
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually,
tosnapshot
remains from my first misguided attempt. I can eliminate, since I'm not sure it has much value any more with our improved promise-basedtoimage
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Scratch ⏫ ,
toSnapshot
is essentially what the modebar uses. Putting that in a separate file insrc/snapshot/
makes sense.Maybe you could rename
tosnapshot.js
->download.js
instead?