added new map screenshot capture method
This commit is contained in:
parent
d73fa37f57
commit
44923eb660
9 changed files with 197 additions and 26 deletions
BIN
app/assets/images/screenshot_sprite.png
Normal file
BIN
app/assets/images/screenshot_sprite.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -20,7 +20,13 @@ Metamaps.JIT = {
|
|||
|
||||
$(".zoomIn").click(self.zoomIn);
|
||||
$(".zoomOut").click(self.zoomOut);
|
||||
$(".zoomExtents").click(self.zoomExtents);
|
||||
|
||||
var zoomExtents = function (event) {
|
||||
self.zoomExtents(event, Metamaps.Visualize.mGraph.canvas);
|
||||
};
|
||||
$(".zoomExtents").click(zoomExtents);
|
||||
|
||||
$(".takeScreenshot").click(Metamaps.Map.exportImage);
|
||||
|
||||
self.synapseStarImage = new Image();
|
||||
self.synapseStarImage.src = '/assets/synapsestar.png';
|
||||
|
@ -123,7 +129,11 @@ Metamaps.JIT = {
|
|||
var directionCat = synapse.get("category");
|
||||
|
||||
//label placement on edges
|
||||
Metamaps.JIT.renderEdgeArrows($jit.Graph.Plot.edgeHelper, adj, synapse);
|
||||
if (canvas.denySelected) {
|
||||
var color = Metamaps.Settings.colors.synapses.normal;
|
||||
canvas.getCtx().fillStyle = canvas.getCtx().strokeStyle = color;
|
||||
}
|
||||
Metamaps.JIT.renderEdgeArrows($jit.Graph.Plot.edgeHelper, adj, synapse, canvas);
|
||||
|
||||
//check for edge label in data
|
||||
var desc = synapse.get("desc");
|
||||
|
@ -140,7 +150,7 @@ Metamaps.JIT = {
|
|||
}
|
||||
};
|
||||
|
||||
if (desc != "" && showDesc) {
|
||||
if (!canvas.denySelected && desc != "" && showDesc) {
|
||||
// '&' to '&'
|
||||
desc = Metamaps.Util.decodeEntities(desc);
|
||||
|
||||
|
@ -188,7 +198,7 @@ Metamaps.JIT = {
|
|||
drawStar(ctx, x + width, y);
|
||||
}
|
||||
}
|
||||
else if (showDesc) {
|
||||
else if (!canvas.denySelected && showDesc) {
|
||||
if (adj.getData("synapses").length > 1) {
|
||||
var ctx = canvas.getCtx();
|
||||
var x = (pos.x + posChild.x) / 2;
|
||||
|
@ -400,7 +410,7 @@ Metamaps.JIT = {
|
|||
ctx = canvas.getCtx();
|
||||
|
||||
// if the topic is selected draw a circle around it
|
||||
if (node.selected) {
|
||||
if (!canvas.denySelected && node.selected) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(pos.x, pos.y, dim + 3, 0, 2 * Math.PI, false);
|
||||
ctx.strokeStyle = Metamaps.Settings.colors.topics.selected;
|
||||
|
@ -1595,12 +1605,10 @@ Metamaps.JIT = {
|
|||
ctx.lineTo(v2.x, v2.y);
|
||||
ctx.stroke();
|
||||
}, // renderMidArrow
|
||||
renderEdgeArrows: function (edgeHelper, adj, synapse) {
|
||||
renderEdgeArrows: function (edgeHelper, adj, synapse, canvas) {
|
||||
|
||||
var self = Metamaps.JIT;
|
||||
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas;
|
||||
|
||||
var directionCat = synapse.get('category');
|
||||
var direction = synapse.getDirection();
|
||||
|
||||
|
@ -1657,8 +1665,7 @@ Metamaps.JIT = {
|
|||
Metamaps.Visualize.mGraph.canvas.scale(0.8,0.8);
|
||||
$(document).trigger(Metamaps.JIT.events.zoom, [event]);
|
||||
},
|
||||
centerMap: function () {
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas;
|
||||
centerMap: function (canvas) {
|
||||
var offsetScale = canvas.scaleOffsetX;
|
||||
|
||||
canvas.scale(1/offsetScale,1/offsetScale);
|
||||
|
@ -1674,7 +1681,8 @@ Metamaps.JIT = {
|
|||
eX = Metamaps.Mouse.boxEndCoordinates.x,
|
||||
eY = Metamaps.Mouse.boxEndCoordinates.y;
|
||||
|
||||
Metamaps.JIT.centerMap();
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas;
|
||||
Metamaps.JIT.centerMap(canvas);
|
||||
|
||||
var height = $(document).height(),
|
||||
width = $(document).width();
|
||||
|
@ -1686,8 +1694,6 @@ Metamaps.JIT = {
|
|||
|
||||
var newRatio = Math.min(ratioX,ratioY);
|
||||
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas;
|
||||
|
||||
if(canvas.scaleOffsetX *newRatio<= 5 && canvas.scaleOffsetX*newRatio >= 0.2){
|
||||
canvas.scale(newRatio,newRatio);
|
||||
}
|
||||
|
@ -1711,15 +1717,14 @@ Metamaps.JIT = {
|
|||
Metamaps.Visualize.mGraph.plot();
|
||||
|
||||
},
|
||||
zoomExtents: function (event) {
|
||||
Metamaps.JIT.centerMap();
|
||||
var height = $(document).height(),
|
||||
width = $(document).width(),
|
||||
zoomExtents: function (event, canvas, denySelected) {
|
||||
Metamaps.JIT.centerMap(canvas);
|
||||
var height = canvas.getSize().height,
|
||||
width = canvas.getSize().width,
|
||||
maxX, minX, maxY, minY, counter = 0;
|
||||
var canvas = Metamaps.Visualize.mGraph.canvas;
|
||||
|
||||
|
||||
if (Metamaps.Selected.Nodes.length > 0) {
|
||||
if (!denySelected && Metamaps.Selected.Nodes.length > 0) {
|
||||
var nodes = Metamaps.Selected.Nodes;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -125,7 +125,7 @@
|
|||
if (Metamaps.Visualize.mGraph) {
|
||||
Metamaps.Visualize.mGraph.graph.empty();
|
||||
Metamaps.Visualize.mGraph.plot();
|
||||
Metamaps.JIT.centerMap();
|
||||
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
|
||||
}
|
||||
Metamaps.Famous.viz.show();
|
||||
Metamaps.Topic.end();
|
||||
|
@ -156,7 +156,7 @@
|
|||
if (Metamaps.Visualize.mGraph) {
|
||||
Metamaps.Visualize.mGraph.graph.empty();
|
||||
Metamaps.Visualize.mGraph.plot();
|
||||
Metamaps.JIT.centerMap();
|
||||
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
|
||||
}
|
||||
Metamaps.Famous.viz.show();
|
||||
Metamaps.Map.end();
|
||||
|
|
|
@ -3384,7 +3384,7 @@ Metamaps.Listeners = {
|
|||
case 69: //if e or E is pressed
|
||||
if (e.ctrlKey){
|
||||
e.preventDefault();
|
||||
Metamaps.JIT.zoomExtents();
|
||||
Metamaps.JIT.zoomExtents(null, Metamaps.Visualize.mGraph.canvas);
|
||||
}
|
||||
break;
|
||||
case 77: //if m or M is pressed
|
||||
|
@ -4203,6 +4203,130 @@ Metamaps.Map = {
|
|||
Metamaps.Map.sideLength = 1;
|
||||
Metamaps.Map.timeToTurn = 0;
|
||||
Metamaps.Map.turnCount = 0;
|
||||
},
|
||||
exportImage: function() {
|
||||
|
||||
var canvas = {};
|
||||
|
||||
canvas.canvas = document.createElement("canvas");
|
||||
canvas.canvas.width = 1880; // 960;
|
||||
canvas.canvas.height = 1260; // 630
|
||||
|
||||
canvas.scaleOffsetX = 1;
|
||||
canvas.scaleOffsetY = 1;
|
||||
canvas.translateOffsetY = 0;
|
||||
canvas.translateOffsetX = 0;
|
||||
canvas.denySelected = true;
|
||||
|
||||
canvas.getSize = function() {
|
||||
if(this.size) return this.size;
|
||||
var canvas = this.canvas;
|
||||
return this.size = {
|
||||
width: canvas.width,
|
||||
height: canvas.height
|
||||
};
|
||||
};
|
||||
canvas.scale = function(x, y) {
|
||||
var px = this.scaleOffsetX * x,
|
||||
py = this.scaleOffsetY * y;
|
||||
var dx = this.translateOffsetX * (x -1) / px,
|
||||
dy = this.translateOffsetY * (y -1) / py;
|
||||
this.scaleOffsetX = px;
|
||||
this.scaleOffsetY = py;
|
||||
this.getCtx().scale(x, y);
|
||||
this.translate(dx, dy);
|
||||
};
|
||||
canvas.translate = function(x, y) {
|
||||
var sx = this.scaleOffsetX,
|
||||
sy = this.scaleOffsetY;
|
||||
this.translateOffsetX += x*sx;
|
||||
this.translateOffsetY += y*sy;
|
||||
this.getCtx().translate(x, y);
|
||||
};
|
||||
canvas.getCtx = function() {
|
||||
return this.canvas.getContext("2d");
|
||||
};
|
||||
// center it
|
||||
canvas.getCtx().translate(1880/2, 1260/2);
|
||||
|
||||
var mGraph = Metamaps.Visualize.mGraph;
|
||||
|
||||
var id = mGraph.root;
|
||||
var root = mGraph.graph.getNode(id);
|
||||
var T = !!root.visited;
|
||||
|
||||
// pass true to avoid basing it on a selection
|
||||
Metamaps.JIT.zoomExtents(null, canvas, true);
|
||||
|
||||
var c = canvas.canvas,
|
||||
ctx = canvas.getCtx(),
|
||||
scale = canvas.scaleOffsetX;
|
||||
|
||||
// draw a grey background
|
||||
ctx.fillStyle = '#d8d9da';
|
||||
var xPoint = (-(c.width/scale)/2) - (canvas.translateOffsetX/scale),
|
||||
yPoint = (-(c.height/scale)/2) - (canvas.translateOffsetY/scale);
|
||||
ctx.fillRect(xPoint,yPoint,c.width/scale,c.height/scale);
|
||||
|
||||
// draw the graph
|
||||
mGraph.graph.eachNode(function(node) {
|
||||
var nodeAlpha = node.getData('alpha');
|
||||
node.eachAdjacency(function(adj) {
|
||||
var nodeTo = adj.nodeTo;
|
||||
if(!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
|
||||
mGraph.fx.plotLine(adj, canvas);
|
||||
}
|
||||
});
|
||||
if(node.drawn) {
|
||||
mGraph.fx.plotNode(node, canvas);
|
||||
}
|
||||
if(!mGraph.labelsHidden) {
|
||||
if(node.drawn && nodeAlpha >= 0.95) {
|
||||
mGraph.labels.plotLabel(canvas, node);
|
||||
} else {
|
||||
mGraph.labels.hideLabel(node, false);
|
||||
}
|
||||
}
|
||||
node.visited = !T;
|
||||
});
|
||||
|
||||
var imageData = {
|
||||
encoded_image: canvas.canvas.toDataURL()
|
||||
};
|
||||
|
||||
console.log(imageData.encoded_image);
|
||||
var map = Metamaps.Active.Map;
|
||||
|
||||
var today = new Date();
|
||||
var dd = today.getDate();
|
||||
var mm = today.getMonth()+1; //January is 0!
|
||||
var yyyy = today.getFullYear();
|
||||
if(dd<10) {
|
||||
dd='0'+dd
|
||||
}
|
||||
if(mm<10) {
|
||||
mm='0'+mm
|
||||
}
|
||||
today = mm+'/'+dd+'/'+yyyy;
|
||||
|
||||
var downloadMessage = "";
|
||||
downloadMessage += "Captured map screenshot! ";
|
||||
downloadMessage += "<a href='" + imageData.encoded_image + "' ";
|
||||
downloadMessage += "download='map-" + map.id + "-screenshot-" + today + ".png'>DOWNLOAD</a>";
|
||||
Metamaps.GlobalUI.notifyUser(downloadMessage);
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
dataType: 'json',
|
||||
url: "/maps/" + Metamaps.Active.Map.id + "/upload_screenshot",
|
||||
data: imageData,
|
||||
success: function (data) {
|
||||
console.log('successfully uploaded map screenshot');
|
||||
},
|
||||
error: function () {
|
||||
console.log('failed to save map screenshot');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -763,6 +763,18 @@
|
|||
background-position: 0 0;
|
||||
cursor:pointer;
|
||||
}
|
||||
.takeScreenshot {
|
||||
margin-bottom: 5px;
|
||||
border-radius: 2px;
|
||||
background-image: url(screenshot_sprite.png);
|
||||
display: none;
|
||||
}
|
||||
.takeScreenshot:hover {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.canEditMap .takeScreenshot {
|
||||
display: block;
|
||||
}
|
||||
.zoomExtents {
|
||||
margin-bottom:5px;
|
||||
border-radius: 2px;
|
||||
|
@ -883,6 +895,10 @@
|
|||
line-height:14px;
|
||||
}
|
||||
|
||||
.toast a {
|
||||
color: #4fc059;
|
||||
}
|
||||
|
||||
/* end toast */
|
||||
|
||||
/* feedback */
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class MapsController < ApplicationController
|
||||
|
||||
before_filter :require_user, only: [:create, :update, :destroy]
|
||||
before_filter :require_user, only: [:create, :update, :screenshot, :destroy]
|
||||
|
||||
respond_to :html, :json
|
||||
|
||||
|
@ -183,6 +183,30 @@ class MapsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# POST maps/:id/upload_screenshot
|
||||
def screenshot
|
||||
@current = current_user
|
||||
@map = Map.find(params[:id]).authorize_to_edit(@current)
|
||||
|
||||
if @map
|
||||
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
|
||||
StringIO.open(png) do |data|
|
||||
data.class.class_eval { attr_accessor :original_filename, :content_type }
|
||||
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
|
||||
data.content_type = "image/png"
|
||||
@map.screenshot = data
|
||||
end
|
||||
|
||||
if @map.save
|
||||
render :json => {:message => "Successfully uploaded the map screenshot."}
|
||||
else
|
||||
render :json => {:message => "Failed to upload image."}
|
||||
end
|
||||
else
|
||||
render :json => {:message => "Unauthorized to set map screenshot."}
|
||||
end
|
||||
end
|
||||
|
||||
# DELETE maps/:id
|
||||
def destroy
|
||||
@current = current_user
|
||||
|
|
|
@ -8,12 +8,12 @@ class Map < ActiveRecord::Base
|
|||
has_many :topics, :through => :topicmappings
|
||||
has_many :synapses, :through => :synapsemappings
|
||||
|
||||
after_touch :save_screenshot
|
||||
#after_touch :save_screenshot
|
||||
|
||||
# This method associates the attribute ":image" with a file attachment
|
||||
has_attached_file :screenshot, :styles => {
|
||||
:thumb => ['188x126#', :png],
|
||||
:full => ['940x630#', :png]
|
||||
:thumb => ['188x126#', :png]
|
||||
#:full => ['940x630#', :png]
|
||||
},
|
||||
:default_url => "/assets/missing-map.png"
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<div class="mapControls mapElement">
|
||||
<div class="takeScreenshot mapControl"></div>
|
||||
<div class="zoomExtents mapControl"></div>
|
||||
<div class="zoomIn mapControl"></div>
|
||||
<div class="zoomOut mapControl"></div>
|
||||
|
|
|
@ -30,6 +30,7 @@ Metamaps::Application.routes.draw do
|
|||
match 'maps/topics/:id', to: 'maps#index', via: :get, as: :topicmaps
|
||||
resources :maps, except: [:new, :edit]
|
||||
match 'maps/:id/contains', to: 'maps#contains', via: :get, as: :contains
|
||||
match 'maps/:id/upload_screenshot', to: 'maps#screenshot', via: :post, as: :screenshot
|
||||
|
||||
devise_for :users, controllers: { registrations: 'users/registrations', passwords: 'users/passwords', sessions: 'devise/sessions' }, :skip => [:sessions]
|
||||
|
||||
|
|
Loading…
Reference in a new issue