Initial commit
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
require 'json'
|
||||
require 'ostruct'
|
||||
require_relative '../layer/presenter'
|
||||
require_relative '../layer_group/presenter'
|
||||
require_relative '../named_map/presenter'
|
||||
|
||||
module CartoDB
|
||||
module Visualization
|
||||
class VizJSON
|
||||
include Carto::HtmlSafe
|
||||
|
||||
VIZJSON_VERSION = '0.1.0'
|
||||
|
||||
def initialize(visualization, options = {}, configuration = {}, logger = nil)
|
||||
@visualization = visualization
|
||||
@map = visualization.map
|
||||
@options = default_options.merge(options)
|
||||
@configuration = configuration
|
||||
@user = options.fetch(:user, nil)
|
||||
logger.info(map.inspect) if logger
|
||||
end
|
||||
|
||||
def to_export_poro(version = 1)
|
||||
description = if visualization.description.blank?
|
||||
""
|
||||
else
|
||||
clean_description(markdown_html_safe(visualization.description))
|
||||
end
|
||||
|
||||
{
|
||||
id: visualization.id,
|
||||
version: VIZJSON_VERSION,
|
||||
title: visualization.qualified_name(@user),
|
||||
description: description,
|
||||
scrollwheel: map.scrollwheel,
|
||||
legends: map.legends,
|
||||
url: options.delete(:url),
|
||||
map_provider: map.provider,
|
||||
bounds: bounds_from(map),
|
||||
center: map.center,
|
||||
zoom: map.zoom,
|
||||
layers: all_layers_for(visualization),
|
||||
overlays: overlays_for(visualization),
|
||||
# Fields specific for this export
|
||||
export_version: version,
|
||||
# TODO: bug? @user is _viewer_user_, who might not be the owner
|
||||
owner: { id: @user.id }
|
||||
}
|
||||
end
|
||||
|
||||
# Return a PORO (Hash object) for easy JSONification
|
||||
# @see https://github.com/CartoDB/carto.js/blob/privacy-maps/doc/vizjson_format.md
|
||||
def to_poro
|
||||
poro_data = {
|
||||
id: visualization.id,
|
||||
version: VIZJSON_VERSION,
|
||||
title: visualization.qualified_name(@user),
|
||||
description: markdown_html_safe(visualization.description),
|
||||
scrollwheel: map.scrollwheel,
|
||||
legends: map.legends,
|
||||
url: options.delete(:url),
|
||||
map_provider: map.provider,
|
||||
bounds: bounds_from(map),
|
||||
center: map.center,
|
||||
zoom: map.zoom,
|
||||
updated_at: map.viz_updated_at,
|
||||
layers: layers_for(visualization),
|
||||
overlays: overlays_for(visualization),
|
||||
prev: visualization.prev_id,
|
||||
next: visualization.next_id,
|
||||
transition_options: visualization.transition_options
|
||||
}
|
||||
|
||||
auth_tokens = auth_tokens_for(visualization)
|
||||
poro_data.merge!(auth_tokens: auth_tokens) if auth_tokens.length > 0
|
||||
|
||||
unless visualization.parent_id.nil?
|
||||
poro_data[:title] = visualization.parent.qualified_name(@user)
|
||||
poro_data[:description] = markdown_html_safe(visualization.parent.description)
|
||||
end
|
||||
|
||||
poro_data
|
||||
end
|
||||
|
||||
def layer_group_for(visualization)
|
||||
LayerGroup::Presenter.new(visualization.layers(:cartodb), options, configuration).to_poro
|
||||
end
|
||||
|
||||
def named_map_layer_group_for(visualization)
|
||||
LayerGroup::Presenter.new(visualization.layers(:named_map), options, configuration).to_poro
|
||||
end
|
||||
|
||||
def other_layers_for(visualization, named_maps_presenter = nil)
|
||||
layer_index = visualization.layers(:cartodb).size
|
||||
|
||||
visualization.layers(:others).map do |layer|
|
||||
if named_maps_presenter.nil?
|
||||
decoration_data_to_apply = {}
|
||||
else
|
||||
decoration_data_to_apply = named_maps_presenter.get_decoration_for_layer(layer.kind, layer_index)
|
||||
end
|
||||
layer_index += 1
|
||||
CartoDB::LayerModule::Presenter.new(layer, options, configuration, decoration_data_to_apply).to_vizjson_v2
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :visualization, :map, :options, :configuration
|
||||
|
||||
# Redcarpet markdown renderer adds "garbage" that would otherwise get reimported
|
||||
def clean_description(description)
|
||||
description.sub(/^<p>/, "").sub(/<\/p> ?(\n)?$/, "")
|
||||
end
|
||||
|
||||
def bounds_from(map)
|
||||
::JSON.parse("[#{map.view_bounds_sw}, #{map.view_bounds_ne}]")
|
||||
rescue
|
||||
# Do nothing
|
||||
end
|
||||
|
||||
def all_layers_for(visualization)
|
||||
layers_data = []
|
||||
|
||||
basemap_layer = basemap_layer_for(visualization)
|
||||
layers_data.push(basemap_layer) if basemap_layer
|
||||
|
||||
data_layers = visualization.layers(:cartodb).map do |layer|
|
||||
CartoDB::LayerModule::Presenter.new(layer, options, configuration).to_vizjson_v2
|
||||
end
|
||||
layers_data.push(data_layers)
|
||||
|
||||
layers_data.push(other_layers_for(visualization))
|
||||
|
||||
layers_data += non_basemap_base_layers_for(visualization)
|
||||
|
||||
layers_data.compact.flatten
|
||||
end
|
||||
|
||||
def layers_for(visualization)
|
||||
basemap_layer = basemap_layer_for(visualization)
|
||||
layers_data = []
|
||||
layers_data.push(basemap_layer) if basemap_layer
|
||||
|
||||
if visualization.retrieve_named_map?
|
||||
presenter_options = {
|
||||
user_name: options.fetch(:user_name),
|
||||
api_key: options.delete(:user_api_key),
|
||||
https_request: options.fetch(:https_request, false),
|
||||
viewer_user: @user,
|
||||
owner: visualization.user
|
||||
}
|
||||
named_maps_presenter = CartoDB::NamedMapsWrapper::Presenter.new(
|
||||
visualization, layer_group_for_named_map(visualization), presenter_options, configuration
|
||||
)
|
||||
layers_data.push(named_maps_presenter.to_poro)
|
||||
else
|
||||
named_maps_presenter = nil
|
||||
layers_data.push(layer_group_for(visualization))
|
||||
end
|
||||
layers_data.push(other_layers_for(visualization, named_maps_presenter))
|
||||
|
||||
layers_data += non_basemap_base_layers_for(visualization)
|
||||
|
||||
layers_data.compact.flatten
|
||||
end
|
||||
|
||||
def layer_group_for_named_map(visualization)
|
||||
layer_group_poro = layer_group_for(visualization)
|
||||
# If there is *only* a torque layer, there is no layergroup
|
||||
return {} if layer_group_poro.nil?
|
||||
|
||||
layers_data = Array.new
|
||||
layer_num = 0
|
||||
layer_group_poro[:options][:layer_definition][:layers].each do |layer|
|
||||
layers_data.push(type: layer[:type],
|
||||
options: layer[:options],
|
||||
visible: layer[:visible],
|
||||
index: layer_num
|
||||
)
|
||||
layer_num += 1
|
||||
end
|
||||
layers_data
|
||||
end
|
||||
|
||||
# INFO: Assumes layers come always ordered by order (they do)
|
||||
def basemap_layer_for(visualization)
|
||||
layer = visualization.layers(:base).first
|
||||
CartoDB::LayerModule::Presenter.new(layer, options, configuration).to_vizjson_v2 unless layer.nil?
|
||||
end
|
||||
|
||||
# INFO: Assumes layers come always ordered by order (they do)
|
||||
def non_basemap_base_layers_for(visualization)
|
||||
base_layers = visualization.layers(:base)
|
||||
if base_layers.length > 0
|
||||
# Remove the basemap, which is always first
|
||||
base_layers.slice(1, visualization.layers(:base).length)
|
||||
.map do |layer|
|
||||
CartoDB::LayerModule::Presenter.new(layer, options, configuration).to_vizjson_v2
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def overlays_for(visualization)
|
||||
ordered_overlays_for(visualization).map do |overlay|
|
||||
Carto::Api::OverlayPresenter.new(overlay).to_vizjson_poro
|
||||
end
|
||||
end
|
||||
|
||||
def ordered_overlays_for(visualization)
|
||||
visualization.overlays.to_a
|
||||
end
|
||||
|
||||
def default_options
|
||||
{
|
||||
full: true,
|
||||
visualization_id: visualization.id,
|
||||
https_request: false,
|
||||
attributions: visualization.attributions_from_derived_visualizations,
|
||||
for_named_map: false
|
||||
}
|
||||
end
|
||||
|
||||
def auth_tokens_for(visualization)
|
||||
visualization.has_password? ? visualization.get_auth_tokens : []
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user