Initial commit

This commit is contained in:
zhongjin
2020-06-15 10:58:47 +08:00
commit 4f1dfe7564
8590 changed files with 1516878 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
var CoreView = require('backbone/core-view');
var template = require('./embed-banner.tpl');
const SIGN_UP_URL = 'https://carto.com/signup';
const REMOVE_BANNER_URL = 'https://carto.com/help/building-maps/remove-banner-from-map/';
var EmbedBannerView = CoreView.extend({
className: 'CDB-Embed-banner--inner',
events: {
'click .js-close': '_close'
},
initialize: function () {
this.template = template;
},
render: function () {
this.$el.html(this.template({
startNowUrl: this._getStartNowUrl(),
removeBannerUrl: REMOVE_BANNER_URL
}));
return this;
},
_getStartNowUrl: function () {
return SIGN_UP_URL +
'?utm_source=embed' +
'&utm_medium=referral' +
'&utm_campaing=Free_Public_Map_Banner';
},
_close: function () {
this.hide();
}
});
module.exports = EmbedBannerView;

View File

@@ -0,0 +1,6 @@
<div <div class="CDB-Embed-banner__inner">
<div class="CDB-Embed-banner__close js-close"></div>
<p class="CDB-Embed-banner__title">Want to create maps like this?</p>
<a class="CDB-Embed-banner__button" href="<%= startNowUrl %>" target="_blank"><span>Start now</span></a>
<a class="CDB-Embed-banner__link" href="<%= removeBannerUrl %>" target="_blank">Remove this banner</a>
</div>

View File

@@ -0,0 +1,82 @@
var checkAndBuildOpts = require('builder/helpers/required-opts');
var LegendManager = require('./legend-manager');
var REQUIRED_OPTS = [
'deepInsightsDashboard',
'layerStyleCollection'
];
/**
* Integration between embed view with cartodb.js and deep-insights.
*/
var EmbedIntegrations = function (opts) {
checkAndBuildOpts(opts, REQUIRED_OPTS, this);
this._getWidgets().each(function (model) {
this._bindWidgetChanges(model);
}, this);
LegendManager.trackLegends(this._getLayers());
};
EmbedIntegrations.prototype._bindWidgetChanges = function (model) {
// wait until the widget has the state from the url
model.bind('change:hasInitialState', function (model) {
model.bind('change:autoStyle', this._onWidgetAutoStyleChanged, this);
// In order to trigger legend update, we wait until the cartocss from autostyle is applied
if (model.isAutoStyle()) {
if (!model.layerModel.get('initialStyle')) {
model.layerModel.once('change:initialStyle', function () {
this._onWidgetAutoStyleChanged(model);
}, this);
} else {
this._onWidgetAutoStyleChanged(model);
}
}
}, this);
};
EmbedIntegrations.prototype._onWidgetAutoStyleChanged = function (model) {
var isAnyAutoStyleApplied = this._getWidgets().any(function (model) {
return model.isAutoStyle();
}, this);
var isAutoStyleApplied = model.isAutoStyle();
var layerId = model.layerModel.id;
var layerStyle;
if (isAutoStyleApplied) {
LegendManager.updateLegends(layerId);
layerStyle = this._layerStyleCollection.findById(layerId);
// setting this in order to restore initial style when disable autostyle
if (model.layerModel) {
model.layerModel.attributes.initialStyle = layerStyle.get('cartocss');
}
} else if (!isAnyAutoStyleApplied) {
LegendManager.resetLegends(layerId);
}
};
EmbedIntegrations.prototype._getLayer = function (model) {
return this.visMap().getLayerById(model.id);
};
EmbedIntegrations.prototype._getLayers = function (model) {
return this.visMap().layers;
};
EmbedIntegrations.prototype.visMap = function () {
return this._vis().map;
};
EmbedIntegrations.prototype._getWidgets = function () {
return this._deepInsightsDashboard._dashboard.widgets._widgetsCollection;
};
EmbedIntegrations.prototype._vis = function () {
return this._deepInsightsDashboard.getMap();
};
module.exports = EmbedIntegrations;

View File

@@ -0,0 +1,85 @@
var _ = require('underscore');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
var embedOverlayTemplate = require('./embed-overlay.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'title',
'description',
'showMenu'
];
var EmbedOverlayView = CoreView.extend({
className: 'CDB-Embed-overlay',
events: {
'click .js-toggle': '_toggle'
},
initialize: function (options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
if (!_.isUndefined(options.template)) {
this._template = options.template;
}
this._initModels();
this._initBinds();
},
render: function () {
this.$el.empty();
var opts = {
title: this._title,
description: this._description,
legends: true,
showMenu: this._showMenu
};
var content = this._renderOverlay(opts);
if (this._template) {
content = this._renderTemplate(opts);
}
this.$el.html(content);
return this;
},
_renderOverlay: function (opts) {
return embedOverlayTemplate(opts);
},
_renderTemplate: function (opts) {
return this._template({
content: this._renderOverlay(_.extend(opts, { legends: false }))
});
},
_initModels: function () {
this.model = new Backbone.Model({
collapsed: false
});
},
_initBinds: function () {
this.listenTo(this.model, 'change:collapsed', this._toggleCollapsed, this);
},
_toggle: function () {
this.model.set('collapsed', !this.model.get('collapsed'));
},
_toggleCollapsed: function () {
var collapsed = this.model.get('collapsed');
this.$('.CDB-Overlay-title').toggleClass('is-collapsed', collapsed);
this.$('.CDB-ArrowToogle').toggleClass('is-down', !collapsed);
this.$('.CDB-Overlay-inner').toggleClass('is-active', !collapsed);
}
});
module.exports = EmbedOverlayView;

View File

@@ -0,0 +1,17 @@
<div class="CDB-Overlay-title<% if (!description && !legends) { %> is-collapsed<% } %>">
<h1 class="CDB-Text CDB-Size-large u-ellipsis" title="<%= title %>"><%= title %></h1>
<% if (description || legends) { %>
<div class="CDB-Overlay-options">
<button class="CDB-Shape js-toggle u-lSpace">
<div class="CDB-ArrowToogle is-blue is-down is-mini"></div>
</button>
</div>
<% } %>
</div>
<% if (description || legends) { %>
<div class="CDB-Overlay-inner is-active<% if (!legends) { %> is-description<% } %>">
<% if (description) { %><div class="CDB-Embed-description<% if (legends) { %> is-legends<% } %> CDB-Text CDB-Size-medium u-altTextColor" title="<%= description %>"><%= description %></div><% } %>
</div>
<% } %>

View File

@@ -0,0 +1,2 @@
<h1 class="CDB-Text CDB-Size-large u-ellipsis" title="<%= title %>"><%= title %></h1>
<% if (description) { %><div class="CDB-Embed-description CDB-Text CDB-Size-medium u-altTextColor" title="<%= description %>"><%= description %></div><% } %>

View File

@@ -0,0 +1,161 @@
var Backbone = require('backbone');
var _ = require('underscore');
var Ps = require('perfect-scrollbar');
var CoreView = require('backbone/core-view');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var TabsView = require('./tabs/tabs-view');
var template = require('./embed.tpl');
var EmbedOverlayView = require('./embed-overlay-view');
var EmbedBannerView = require('./embed-banner-view');
var TAB_NAMES = {
map: 'map',
legends: 'legends'
};
var TAB_TITLES = {
map: 'map',
legends: 'legends',
layers: 'layers'
};
var MOBILE_VIEWPORT_BREAKPOINT = 599;
var FULLSCREEN_VIEWPORT_BREAKPOINT = 1199;
var REQUIRED_OPTS = [
'title',
'description',
'showMenu',
'showLegends',
'showLayerSelector',
'showBanner'
];
var EmbedView = CoreView.extend({
module: 'embed:embed-view',
className: 'CDB-Embed-view',
initialize: function (options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this._onlyLayerSelector = !this._showLegends && this._showLayerSelector;
this._showLegends = this._showLegends || this._showLayerSelector;
if (this._showLegends) {
var selectedTab = _.find(this._tabs, function (tab) { return tab.isSelected; });
this._tabsModel = new Backbone.Model({
selected: selectedTab ? selectedTab.name : TAB_NAMES.map
});
this._initBinds();
}
},
render: function () {
this.$el.html(template({
title: this._title,
description: this._description,
showMenu: this._showMenu,
showLegends: this._showLegends,
showBanner: this._showBanner
}));
var mapTabConfig = {
name: TAB_NAMES.map,
title: TAB_TITLES.map,
isSelected: true
};
var legendTabConfig = {
name: TAB_NAMES.legends,
title: this._onlyLayerSelector
? TAB_TITLES.layers
: TAB_NAMES.legends
};
if (this._showLegends) {
var tabsView = new TabsView({
model: this._tabsModel,
tabs: [ mapTabConfig, legendTabConfig ]
});
this.addView(tabsView);
this.$('.js-tabs').replaceWith(tabsView.render().$el);
}
if (this._showBanner) {
var embedView = new EmbedBannerView();
this.$('.js-embed-banner').append(embedView.render().el);
this.addView(embedView);
}
return this;
},
_initBinds: function () {
this.listenTo(this._tabsModel, 'change:selected', this._onSelectedTabChanged);
window.addEventListener('resize', this.onWindowResized.bind(this), { passive: true });
},
_onSelectedTabChanged: function () {
var contentId = '.js-embed-' + this._tabsModel.get('selected');
var content = this.$(contentId);
content.siblings().removeClass('is-active');
content.addClass('is-active');
// Update PerfectScrollbar
var perfectScrollbarContainer = content.find('.ps-container').get(0);
if (perfectScrollbarContainer) {
Ps.update(perfectScrollbarContainer);
}
},
injectTitle: function (mapEl) {
var legendsEl = mapEl.find('.CDB-Legends-canvasInner');
this.$scrollShadowTop = mapEl.find('.CDB-Legends-canvasShadow--top');
this.$scrollShadowBottom = mapEl.find('.CDB-Legends-canvasShadow--bottom');
this.titleView = new EmbedOverlayView({
title: this._title,
description: this._description,
showMenu: this._showMenu
});
this.addView(this.titleView);
this.listenTo(this.titleView.model, 'change:collapsed', function (model) {
// Hack because PS is not triggering events
if (model.get('collapsed')) {
this.$scrollShadowTop.removeClass('is-visible');
this.$scrollShadowBottom.removeClass('is-visible');
// This is the correct way of doing it, the lines above are a hack, because PS is not triggering events
legendsEl.scrollTop(0);
Ps.update(legendsEl.get(0));
} else {
// Hack as well, see comment above
if (legendsEl.get(0).scrollHeight > legendsEl.height()) {
this.$scrollShadowBottom.addClass('is-visible');
}
}
});
legendsEl.prepend(this.titleView.render().el);
legendsEl.find('.CDB-LayerLegends')
.detach()
.appendTo(legendsEl.find('.CDB-Overlay-inner'));
},
onWindowResized: function () {
if (window.innerWidth > MOBILE_VIEWPORT_BREAKPOINT && this._tabsModel.get('selected') !== TAB_NAMES.map) {
this._tabsModel.set({ selected: TAB_NAMES.map });
}
if (this.titleView && window.innerWidth > FULLSCREEN_VIEWPORT_BREAKPOINT) {
this.titleView.model.set('collapsed', false);
}
}
});
module.exports = EmbedView;

View File

@@ -0,0 +1,21 @@
<% if (showMenu && showLegends) { %>
<header class="CDB-Embed-header <% if (!showLegends) { %> CDB-Embed-header--shadow <% } %>">
<h1 class="CDB-Text CDB-Size-large u-ellipsis" title="<%= title %>"><%= title %></h1>
<% if (description) { %><div class="CDB-Embed-description CDB-Text CDB-Size-medium u-altTextColor" title="<%= description %>"><%= description %></div><% } %>
</header>
<% } %>
<% if (showLegends) { %>
<div class="CDB-Embed-tabs CDB-NavMenu js-tabs"></div>
<% } %>
<div class="CDB-Embed-content">
<div class="CDB-Embed-tab <% if (showMenu) { %> CDB-Embed-tab--menu <% } %> is-active js-embed-map"></div>
<% if (showLegends) { %>
<div class="CDB-Embed-tab CDB-Embed-legends js-embed-legends"></div>
<% } %>
</div>
<% if (showBanner) { %>
<div class="CDB-Embed-banner js-embed-banner"></div>
<% } %>

View File

@@ -0,0 +1,49 @@
var _ = require('underscore');
var legendsMetadata = require('builder/data/legends/legends-metadata');
var legends;
var LEGENDS_METADATA = _.keys(legendsMetadata);
var LEGENDS_COLOR = ['category', 'choropleth'];
var LegendManager = {
trackLegends: function (layers) {
legends = {};
_.each(layers.models, function (layerModel) {
var legendsLayer;
var options = {};
if (layerModel.legends != null) {
legendsLayer = layerModel.legends;
_.each(LEGENDS_METADATA, function (legend) {
var legendModel = legendsLayer[legend];
if (legendModel.get('visible') === true) {
options[legend] = legendModel;
}
});
legends[layerModel.id] = options;
}
});
},
getLegends: function () {
return legends;
},
updateLegends: function (layerId) {
var legendsLayer = legends[layerId];
_.each(LEGENDS_COLOR, function (legend) {
var legendModel = legendsLayer[legend];
legendModel && legendModel.set({visible: false});
});
},
resetLegends: function (layerId) {
var legendsLayer = legends[layerId];
_.each(legendsLayer, function (legend) {
legend.set({visible: true});
});
}
};
module.exports = LegendManager;

View File

@@ -0,0 +1,21 @@
var Backbone = require('backbone');
module.exports = Backbone.Collection.extend({
model: function (d, opts) {
var attrs = {};
attrs.id = d.id;
if (d.options.tile_style) {
attrs.cartocss = d.options.tile_style;
}
return new Backbone.Model(attrs);
},
resetByLayersData: function (data) {
this.reset(data, {
silent: true
});
},
findById: function (id) {
return this.findWhere({id: id});
}
});

View File

@@ -0,0 +1,3 @@
<li class="CDB-NavMenu-item js-tab<% if (isSelected) { %> is-selected<% } %>" data-tab="<%= name %>">
<button class="CDB-NavMenu-link u-upperCase"><%= title %></button>
</li>

View File

@@ -0,0 +1,61 @@
var CoreView = require('backbone/core-view');
var template = require('./tabs.tpl');
var tabItemTemplate = require('./tab-item.tpl');
var checkAndBuildOpts = require('builder/helpers/required-opts');
var REQUIRED_OPTS = [
'tabs'
];
var TabsView = CoreView.extend({
module: 'embed:tabs:tabs-view',
tagName: 'nav',
className: 'CDB-Embed-tabs CDB-NavMenu js-tabs',
events: {
'click .js-tab': '_onTabClicked'
},
initialize: function (options) {
checkAndBuildOpts(options, REQUIRED_OPTS, this);
this.listenTo(this.model, 'change:selected', this._onSelectedTabChanged);
},
render: function () {
this.$el.empty();
this.$el.html(template());
this._tabs.map(function (tab) {
this.$('.js-tabs-container').append(tabItemTemplate({
name: tab.name,
title: tab.title || tab.name,
isSelected: tab.isSelected
}));
}.bind(this));
return this;
},
_onSelectedTabChanged: function () {
var tabName = this.model.get('selected');
var tab = this.$('[data-tab="' + tabName + '"]');
tab.siblings().removeClass('is-selected');
tab.addClass('is-selected');
},
_onTabClicked: function (event) {
var tab = this.$(event.currentTarget);
var tabName = tab.data('tab');
this.model.set({
selected: tabName
});
}
});
module.exports = TabsView;

View File

@@ -0,0 +1 @@
<ul class="CDB-NavMenu-inner CDB-NavMenu-inner--legends CDB-Text is-semibold CDB-Size-medium js-tabs-container"></ul>