Skip to content

Instantly share code, notes, and snippets.

@bertday
Created January 17, 2018 21:54
Show Gist options
  • Save bertday/1c4f47ffda1ecb76e0efb36509de65be to your computer and use it in GitHub Desktop.
Save bertday/1c4f47ffda1ecb76e0efb36509de65be to your computer and use it in GitHub Desktop.
Mapboard build.js using rollup-plugin-node-builtins, throws error
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('vue'), require('vuex'), require('leaflet'), require('jquery'), require('axios'), require('turf')) :
typeof define === 'function' && define.amd ? define(['exports', 'vue', 'vuex', 'leaflet', 'jquery', 'axios', 'turf'], factory) :
(factory((global.Mapboard = {}),global.Vue,global.Vuex,global.L,global.$,global.axios,global.turf));
}(this, (function (exports,Vue,Vuex,L$1,$$1,axios$1,turf) { 'use strict';
Vue = Vue && Vue.hasOwnProperty('default') ? Vue['default'] : Vue;
Vuex = Vuex && Vuex.hasOwnProperty('default') ? Vuex['default'] : Vuex;
var L$1__default = 'default' in L$1 ? L$1['default'] : L$1;
$$1 = $$1 && $$1.hasOwnProperty('default') ? $$1['default'] : $$1;
axios$1 = axios$1 && axios$1.hasOwnProperty('default') ? axios$1['default'] : axios$1;
turf = turf && turf.hasOwnProperty('default') ? turf['default'] : turf;
// when you load vuex from a script tag this seems to happen automatically
// Vue.use(Vuex);
// this grabs horizontal table ids from an array of topic components,
// recursively
function getTableIdsFromComps(comps) {
if ( comps === void 0 ) comps = [];
// const topics = config.topics;
var tableIds = [];
for (var i = 0, list = comps; i < list.length; i += 1) {
var comp = list[i];
var options = comp.options || {};
var innerComps = options.components;
// if this is a "group" component, recurse
if (innerComps) {
var innerTableIds = getTableIdsFromComps(innerComps);
tableIds = tableIds.concat(innerTableIds);
continue;
}
// skip comps that aren't horizontal tables
if (comp.type !== 'horizontal-table') {
continue;
}
var tableId = comp._id;
tableIds.push(tableId);
}
return tableIds;
}
// this makes the empty filtered data object given a list of topics.
function createFilteredData(config) {
var topics = config.topics;
var tableIds = [];
for (var i = 0, list = topics; i < list.length; i += 1) {
var topic = list[i];
var comps = topic.components;
var compTableIds = getTableIdsFromComps(comps);
tableIds = tableIds.concat(compTableIds);
}
var filteredData = tableIds.reduce(function (acc, tableId) {
acc[tableId] = [];
return acc;
}, {});
return filteredData;
}
// this grabs table group ids from an array of topic components
function getTableGroupIdFromComps(comps) {
if ( comps === void 0 ) comps = [];
var tableGroupId;
for (var i = 0, list = comps; i < list.length; i += 1) {
var comp = list[i];
var options = comp.options || {};
var innerComps = options.components;
// if this is a "group" component, recurse
if (!innerComps) {
continue;
}
// skip comps that aren't horizontal tables
if (comp.type !== 'table-group') {
continue;
}
tableGroupId = comp._id;
}
return tableGroupId;
}
// this makes the empty tableGroups object given a list of topics.
function createTableGroups(config) {
var topics = config.topics;
var tableGroupIds = [];
for (var i = 0, list = topics; i < list.length; i += 1) {
var topic = list[i];
var comps = topic.components;
var compTableGroupId = getTableGroupIdFromComps(comps);
if (compTableGroupId) { tableGroupIds.push(compTableGroupId); }
}
var tableGroups = {};
for (var i$1 = 0, list$1 = tableGroupIds; i$1 < list$1.length; i$1 += 1) {
var tableGroupId = list$1[i$1];
tableGroups[tableGroupId] = {
activeTable: null,
activeTableId: null
};
}
return tableGroups;
}
function createStore(config) {
var defaultTopic = config.topics[0];
// create initial state for sources. data key => {}
var sourceKeys = Object.keys(config.dataSources || {});
var sources = sourceKeys.reduce(function (o, key) {
var val;
// if the source has targets, just set it to be an empty object
if (config.dataSources[key].targets) {
val = {
targets: {}
};
} else {
val = {
// we have to define these here, because vue can't observe properties that
// are added later.
status: null,
secondaryStatus: null,
data: null
};
}
o[key] = val;
return o;
}, {});
var parcelKeys = Object.keys(config.parcels || {});
var parcels = parcelKeys.reduce(function (o, key) {
var val;
if (config.parcels[key].multipleAllowed) {
val = {
data: [],
status: null,
activeParcel: null,
activeAddress: null,
activeMapreg: null
};
} else {
val = null;
// val = {
// geometry: null,
// id: null,
// properties: null,
// type: null
// };
}
o[key] = val;
return o;
}, {});
var initialState = {
is_mobile_or_tablet: false,
activeTopic: defaultTopic.key,
activeParcelLayer: defaultTopic.parcels,
// the ais feature
clickCoords: null,
geocode: {
status: null,
data: null,
input: null,
related: null,
// forwardStatus: null,
// reverseStatus: null,
},
lastSearchMethod: 'geocode',
// the leaflet map object
map: {
location: {
lat: null,
lng: null
},
center: config.map.center,
zoom: config.map.zoom,
map: null,
basemap: defaultTopic.basemap,
imagery: 'imagery2017',
shouldShowImagery: false,
// circleMarkers: [],
// this is the key for the active overlay image (eg regmap)
imageOverlay: null,
imageOverlayOpacity: null,
filters: [],
watchPositionOn: false,
// features: {
// markers: [
// // {
// // geometry: '',
// // // optional - mainly for symbology
// // options: {}
// // }
// ],
// polygons: [
//
// ]
// }
},
parcels: parcels,
// dorParcels: {
// data: [],
// status: null
// },
// activeDorParcel: null,
// activeDorAddress: null,
// activeDorMapreg: null,
// pwdParcel: null,
sources: sources,
cyclomedia: {
active: false,
viewer: null,
recordings: [],
locFromApp: null,
locFromViewer: null,
},
// we need this to know whether or not to force an update on the first show
pictometry: {
ipa: null,
active: false,
shapeIds: [],
pngMarkerIds: [],
zoom: null,
// this is the state of the main leaflet map. when these values change
// the pictometry widget should react. the reason these are duplicated
// here is to avoid an infinite loop in the Map component when the
// viewport changes.
map: {
center: config.map.center,
zoom: config.map.zoom
}
},
tables: {
// table id => filtered rows
filteredData: createFilteredData(config),
},
tableGroups: createTableGroups(config),
activeFeature: {
featureId: null,
tableId: null
}
};
// TODO standardize how payloads are passed around/handled
return new Vuex.Store({
state: initialState,
// getters: {
// topicTables: (state, getters) => (activeTopicKey) => {
// console.log(state.tables);
// return state.tables.filter(table => table.key === activeTopicKey);
// }
// },
getters: {
visibleTableIds: function visibleTableIds(state) {
// get active topic
var activeTopic = state.activeTopic;
if (!activeTopic) {
return [];
}
// get horizontal table ids for that topic
var activeTopicConfig = (config.topics.filter(function (topic) { return topic.key === activeTopic; }) || [])[0];
var comps = activeTopicConfig.components;
var compTableGroup = getTableGroupIdFromComps(comps);
if (compTableGroup) {
// even though there is only 1 value, it has to be in array form in the state
var array = [];
array.push(state.tableGroups[compTableGroup].activeTableId);
return array;
} else {
var compTables = getTableIdsFromComps(comps);
return compTables;
}
}
},
mutations: {
setIsMobileOrTablet: function setIsMobileOrTablet(state, payload) {
state.is_mobile_or_tablet = payload;
},
setLocation: function setLocation(state, payload) {
state.map.location.lat = payload.lat;
state.map.location.lng = payload.lng;
},
setWatchPositionOn: function setWatchPositionOn(state, payload) {
state.map.watchPositionOn = payload;
},
setClickCoords: function setClickCoords(state, payload) {
state.clickCoords = payload;
},
setTables: function setTables(state, payload) {
state.tables = payload;
},
setTableGroupActiveTable: function setTableGroupActiveTable(state, payload) {
state.tableGroups[payload.tableGroupId].activeTableId = payload.activeTableId;
state.tableGroups[payload.tableGroupId].activeTable = payload.activeTable;
},
setTableFilteredData: function setTableFilteredData(state, payload) {
var tableId = payload.tableId;
var data = payload.data;
// check for not-null table id
if (!tableId) { return; }
state.tables.filteredData[tableId] = data;
},
setActiveTopic: function setActiveTopic(state, payload) {
state.activeTopic = payload;
},
setActiveParcelLayer: function setActiveParcelLayer(state, payload) {
state.activeParcelLayer = payload;
},
setSourceStatus: function setSourceStatus(state, payload) {
var key = payload.key;
var status = payload.status;
// if a target id was passed in, set the status for that target
var targetId = payload.targetId;
if (targetId) {
state.sources[key].targets[targetId].status = status;
} else {
state.sources[key].status = status;
}
},
setSecondarySourceStatus: function setSecondarySourceStatus(state, payload) {
var key = payload.key;
var secondaryStatus = payload.secondaryStatus;
// if a target id was passed in, set the status for that target
var targetId = payload.targetId;
// if (targetId) {
// state.sources[key].targets[targetId].status = status;
// } else {
state.sources[key].secondaryStatus = secondaryStatus;
// }
},
setSourceData: function setSourceData(state, payload) {
// console.log('store setSourceData payload:', payload);
var key = payload.key;
var data = payload.data;
// if a target id was passed in, set the data object for that target
var targetId = payload.targetId;
if (targetId) {
if (state.sources[key].targets[targetId]) {
state.sources[key].targets[targetId].data = data;
}
} else {
state.sources[key].data = data;
}
},
setSourceDataMore: function setSourceDataMore(state, payload) {
var key = payload.key;
var data = payload.data;
var nextPage = payload.page;
var oldData = state.sources[key].data;
// console.log('oldData features', oldData.features, 'data features', data.features);
var allData = oldData.features.concat(data.features);
// console.log('allData', allData);
// if a target id was passed in, set the data object for that target
// const targetId = payload.targetId;
// if (targetId) {
// state.sources[key].targets[targetId].data = data;
// } else {
state.sources[key].data.features = allData;
state.sources[key].data.page = nextPage;
// }
},
setMapFilters: function setMapFilters(state, payload) {
state.map.filters = payload;
},
// this sets empty targets for a data source
createEmptySourceTargets: function createEmptySourceTargets(state, payload) {
var key = payload.key;
var targetIds = payload.targetIds;
state.sources[key].targets = targetIds.reduce(function (acc, targetId) {
acc[targetId] = {
status: null,
data: null
};
return acc;
}, {});
},
clearSourceTargets: function clearSourceTargets(state, payload) {
var key = payload.key;
state.sources[key].targets = {};
},
setMap: function setMap(state, payload) {
state.map.map = payload.map;
},
// this is the map center as an xy coordinate array (not latlng)
setMapCenter: function setMapCenter(state, payload) {
state.map.center = payload;
},
setMapZoom: function setMapZoom(state, payload) {
state.map.zoom = payload;
},
setParcelData: function setParcelData(state, payload) {
// console.log('store setParcelData payload:', payload);
var ref = payload || {};
var parcelLayer = ref.parcelLayer;
var data = ref.data;
var multipleAllowed = ref.multipleAllowed;
var status = ref.status;
var activeParcel = ref.activeParcel;
var activeAddress = ref.activeAddress;
var activeMapreg = ref.activeMapreg;
// console.log('store setParcelData parcelLayer:', parcelLayer, 'data:', data, 'multipleAllowed:', multipleAllowed, 'status:', status, 'activeParcel:', activeParcel);
if (!multipleAllowed) {
state.parcels[parcelLayer] = data;
} else {
state.parcels[parcelLayer].data = data;
state.parcels[parcelLayer].status = status;
state.parcels[parcelLayer].activeParcel = activeParcel;
state.parcels[parcelLayer].activeAddress = activeAddress;
state.parcels[parcelLayer].activeMapreg = activeMapreg;
}
},
setActiveParcel: function setActiveParcel(state, payload) {
console.log('store setActiveParcel:', payload);
var ref = payload || {};
var parcelLayer = ref.parcelLayer;
var activeParcel = ref.activeParcel;
var activeAddress = ref.activeAddress;
var activeMapreg = ref.activeMapreg;
state.parcels[parcelLayer].activeParcel = activeParcel;
state.parcels[parcelLayer].activeAddress = activeAddress;
state.parcels[parcelLayer].activeMapreg = activeMapreg;
},
// setDorParcelData(state, payload) {
// state.dorParcels.data = payload;
// // state.parcels.dor.data = payload;
// },
// setDorParcelStatus(state, payload) {
// state.dorParcels.status = payload;
// // state.parcels.dor.status = payload;
// },
// setActiveDorParcel(state, payload) {
// state.activeDorParcel = payload;
// // state.parcels.dor.activeParcel = payload;
// },
// setActiveDorAddress(state, payload) {
// state.activeDorAddress = payload;
// // state.parcels.dor.activeAddress = payload;
// },
// setActiveDorMapreg(state, payload) {
// state.activeDorMapreg = payload;
// // state.parcels.dor.activeMapreg = payload;
// },
// setPwdParcel(state, payload) {
// state.pwdParcel = payload;
// // state.parcels.pwd = payload;
// },
setGeocodeStatus: function setGeocodeStatus(state, payload) {
state.geocode.status = payload;
},
setGeocodeData: function setGeocodeData(state, payload) {
state.geocode.data = payload;
},
setGeocodeRelated: function setGeocodeRelated(state, payload) {
state.geocode.related = payload;
},
setGeocodeInput: function setGeocodeInput(state, payload) {
state.geocode.input = payload;
},
setBasemap: function setBasemap(state, payload) {
state.map.basemap = payload;
},
setImagery: function setImagery(state, payload) {
state.map.imagery = payload;
},
setShouldShowImagery: function setShouldShowImagery(state, payload) {
state.map.shouldShowImagery = payload;
},
setPictometryActive: function setPictometryActive(state, payload) {
if (!config.pictometry.enabled) {
return;
}
state.pictometry.active = payload;
},
setCyclomediaActive: function setCyclomediaActive(state, payload) {
if (!config.cyclomedia.enabled) {
return;
}
state.cyclomedia.active = payload;
},
setCyclomediaViewer: function setCyclomediaViewer(state, payload) {
state.cyclomedia.viewer = payload;
},
setCyclomediaRecordings: function setCyclomediaRecordings(state, payload) {
state.cyclomedia.recordings = payload;
},
setCyclomediaLocFromApp: function setCyclomediaLocFromApp(state, payload) {
state.cyclomedia.locFromApp = payload;
},
setCyclomediaLocFromViewer: function setCyclomediaLocFromViewer(state, payload) {
state.cyclomedia.locFromViewer = payload;
},
setActiveFeature: function setActiveFeature(state, payload) {
var ref = payload || {};
var featureId = ref.featureId;
var tableId = ref.tableId;
var nextActiveFeature = { featureId: featureId, tableId: tableId };
state.activeFeature = nextActiveFeature;
},
setLastSearchMethod: function setLastSearchMethod(state, payload) {
state.lastSearchMethod = payload;
},
setPictometryIpa: function setPictometryIpa(state, payload) {
state.pictometry.ipa = payload;
},
setPictometryShapeIds: function setPictometryShapeIds(state, payload) {
state.pictometry.shapeIds = payload;
},
setPictometryPngMarkerIds: function setPictometryPngMarkerIds(state, payload) {
state.pictometry.pngMarkerIds = payload;
},
// this is the leaflet map center updated when the map is moved
setPictometryMapCenter: function setPictometryMapCenter(state, payload) {
state.pictometry.map.center = payload;
},
setPictometryMapZoom: function setPictometryMapZoom(state, payload) {
state.pictometry.map.zoom = payload;
},
setPictometryZoom: function setPictometryZoom(state, payload) {
state.pictometry.zoom = payload;
},
setImageOverlay: function setImageOverlay(state, payload) {
state.map.imageOverlay = payload;
},
setImageOverlayOpacity: function setImageOverlayOpacity(state, payload) {
state.map.imageOverlayOpacity = payload;
},
// setCircleMarkers(state, payload) {
// state.map.circleMarkers.push(payload);
// }
}
});
}
// shout out to airyland
// https://github.com/airyland/vue-config/blob/master/index.js
function configMixin (Vue$$1, config) {
Vue$$1.mixin({
created: function created() {
this.$config = config;
}
});
}
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var TopicComponent = {
props: ['slots', 'options', 'item'],
computed: {
nullValue: function nullValue() {
var options = this.options || {};
return options.nullValue;
},
},
methods: {
evaluateSlot: function evaluateSlot(valOrGetter, transforms, nullValue) {
var this$1 = this;
if ( transforms === void 0 ) transforms = [];
if ( nullValue === void 0 ) nullValue = '';
// check for null val/getter
if (!valOrGetter) {
return valOrGetter;
}
var valOrGetterType = typeof valOrGetter;
var val;
// fn
if (valOrGetterType === 'function') {
var state = this.$store.state;
var getter = valOrGetter;
// const getterText = String(getter);
// const depsRe = /state(\.\w+)+/g;
// const depsText = getterText.match(depsRe);
// const deps = depsText.map(eval);
var item = this.item;
// if this comp is associated with an "item" (generally some object
// from a list of things, e.g. dor parcels), pass the item itself
// as well when evaluating
if (item) {
val = getter(state, item);
} else {
val = getter(state);
}
} else {
val = valOrGetter;
}
// format nulls but not falses
if (val === false) {
} else if (!val) {
return nullValue;
}
// apply transforms
var loop = function () {
// get transform definition from config by name
var transformKey = list[i];
var transform = this$1.$config.transforms[transformKey];
// make object of (relevant) globals by filtering window object
var globals = (void 0);
var globalKeys = transform.globals;
if (globalKeys) {
globals = Object.keys(window)
.filter(function (key) { return globalKeys.includes(key); })
.reduce(function (obj, key) {
obj[key] = window[key];
return obj;
}, {});
}
// run transform
var fn = transform.transform;
val = fn(val, globals);
};
for (var i = 0, list = transforms; i < list.length; i += 1) loop();
return val;
},
// not sure how children can use this. `this` isn't binding correctly at
// the time the child gets instantiated.
// getComputedProperties() {
// const slots = this.slots;
// return Object.keys(slots).reduce((o, key) => {
// const valOrGetter = slots[key];
// // wrap slot val/getter in evaluator fn
// o[key] = () => {
// this.evaluateSlot(valOrGetter);
// }
// return o;
// }, {});
// }
},
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .mb-badge[data-v-6cc90a8b] { /*width: 300px;*/ padding: 0; margin: 0 auto; margin-bottom: inherit; } @media (max-width: 640px) { .mb-badge[data-v-6cc90a8b] { width: 100%; } } /*REVIEW this should use foundation classes*/ @media (min-width: 640px) { .mb-badge[data-v-6cc90a8b] { width: 325px; } } .mb-badge-header[data-v-6cc90a8b] { color: #fff; font-weight: bold; text-align: center; padding-top: 2px; padding-bottom: 2px; } .mb-badge-body[data-v-6cc90a8b] { padding: 12px; } .mb-badge-body > h1[data-v-6cc90a8b] { margin: 0; margin-bottom: 5px; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Badge = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"mb-badge panel center"},[_c('div',{staticClass:"mb-badge-header",style:(_vm.style)},[_vm._v(" "+_vm._s(_vm.evaluateSlot(_vm.slots.title))+" ")]),_vm._v(" "),_c('div',{staticClass:"mb-badge-body"},[_c('h1',[_vm._v(_vm._s(_vm.evaluateSlot(_vm.slots.value)))]),_vm._v(" "),_c('strong',[_vm._v(_vm._s(_vm.evaluateSlot(_vm.slots.description)))])])])},staticRenderFns: [],_scopeId: 'data-v-6cc90a8b',
computed: {
style: function style() {
var titleBackgroundValOrFn = (this.options || {}).titleBackground;
var titleBackground;
if (titleBackgroundValOrFn) {
if (typeof titleBackgroundValOrFn === 'function') {
titleBackground = titleBackgroundValOrFn(this.$store.state);
} else {
titleBackground = titleBackgroundValOrFn;
}
} else {
titleBackground = '#444';
}
return { background: titleBackground };
}
},
mixins: [TopicComponent]
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .active[data-v-663d0390] { background: #F3D661; } td[data-v-663d0390] { font-size: 15px; text-align: left; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var HorizontalTableRow = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('tr',{class:{ active: _vm.item._featureId === _vm.activeFeature.featureId && _vm.tableId === _vm.activeFeature.tableId },on:{"mouseover":_vm.handleRowMouseover,"click":_vm.handleRowClick,"mouseout":_vm.handleRowMouseout}},_vm._l((_vm.fields),function(field){return _c('td',{domProps:{"innerHTML":_vm._s(_vm.evaluateSlot(field.value, field.transforms, field.nullValue))}})}))},staticRenderFns: [],_scopeId: 'data-v-663d0390',
mixins: [TopicComponent],
props: ['fields', 'hasOverlay', 'tableId'],
computed: {
activeFeature: function activeFeature() {
return this.$store.state.activeFeature;
},
isActive: function isActive() {
return this.activeFeature.featureId === this.$props.item._featureId;
},
isMobileOrTablet: function isMobileOrTablet() {
return this.$store.state.is_mobile_or_tablet;
},
},
watch: {
isActive: function isActive(value) {
if (value === true) {
var el = this.$el;
var visible = this.isElementInViewport(el);
console.log('visible?', visible ? 'YES' : 'NO');
if (!visible) {
el.scrollIntoView();
}
}
}
},
methods: {
handleRowMouseover: function handleRowMouseover(e) {
console.log('handleRowMouseover is starting');
if(!this.isMobileOrTablet) {
console.log('handleRowMouseover actions are running');
if (!this.hasOverlay) { return; }
var featureId = this.item._featureId;
var tableId = this.tableId;
this.$store.commit('setActiveFeature', { featureId: featureId, tableId: tableId });
}
},
handleRowClick: function handleRowClick(e) {
console.log('handleRowClick is starting');
if(this.isMobileOrTablet) {
console.log('handleRowClick actions are running');
if (!this.hasOverlay) { return; }
var featureId = this.item._featureId;
var tableId = this.tableId;
this.$store.commit('setActiveFeature', { featureId: featureId, tableId: tableId });
}
},
handleRowMouseout: function handleRowMouseout(e) {
console.log('handleRowMouseout is starting');
// if(!this.isMobileOrTablet) {
console.log('handleRowMouseout actions are running');
if (!this.hasOverlay) { return; }
this.$store.commit('setActiveFeature', null);
// }
},
// REVIEW there's very similar code in the controller. if these can be
// the same thing, make it into a util.
isElementInViewport: function isElementInViewport(el) {
var rect = el.getBoundingClientRect();
console.log('bounding box', rect);
var visibility = {
// TODO the 108 below is account for the combined height of the
// app header and address header. this is not a good long-term
// solution - instead, use the `bottom` value of the address header's
// bounding rect. however, this should only fire on small devices,
// which would require again hard-coding screen breakpoints from
// standards or some other magic, which might not a huge
// improvement in terms of decoupling logic and presentation. hmm.
top: rect.top >= 108,
left: rect.left >= 0,
bottom: rect.bottom <= (window.innerHeight || document.documentElement.clientHeight),
right: rect.right <= (window.innerWidth || document.documentElement.clientWidth),
};
console.log('visibility', visibility);
// return if all sides are visible
return Object.values(visibility).every(function (val) { return val; });
},
featuresMatch: function featuresMatch(a, b) {
return a.featureId === b.featureId && a.tableId === b.tableId;
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .inline-block[data-v-43e19572] { display: inline-block; } .vertically-centered[data-v-43e19572] { display: inline-block; vertical-align: middle; } .mb-horizontal-table-controls[data-v-43e19572] { text-align: center; vertical-align: middle; margin-bottom: 10px; } /* dropdown filters */ .mb-select-text[data-v-43e19572] { font-size: 16px; padding-right: 5px; padding-left: 5px; } .mb-select[data-v-43e19572] { width: auto; height: 40px; vertical-align: middle; /*padding-right: 20px;*/ } .mb-select-option[data-v-43e19572] { display: inline-block; padding-right: 100px; margin-right: 100px; } /* input filters using text */ .mb-search-control-input[data-v-43e19572] { height: 40px !important; line-height: 48px; padding: 8px; font-size: 16px; width: 300px; /*margin-left: 10px;*/ } /*REVIEW this repeats a lot of .mb-search-control-input. can it be refactored?*/ .mb-search-control-input-full[data-v-43e19572] { height: 40px !important; line-height: 48px; padding: 8px; font-size: 16px; width: 260px; } .mb-search-control-button[data-v-43e19572] { width: 40px; background: #ccc; line-height: 40px; float: right; } .group[data-v-43e19572]:after { content: \"\"; display: table; clear: both; } .mb-horizontal-table-body[data-v-43e19572] { padding-top: 1rem; } .center-button[data-v-43e19572] { display: flex; align-items: center; justify-content: center; } .loading[data-v-43e19572] { float: right; } .filter-by-text-form[data-v-43e19572] { border: 2px solid #0f4d90; } table[data-v-43e19572] { margin: 0; } .external-link[data-v-43e19572] { padding-top: 5px; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var DEFAULT_SORT_METHODS = [
'date',
'distance'
];
var HorizontalTable = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.shouldShowTable)?_c('div',[_c('div',{staticClass:"mb-horizontal-table-controls"},[(!!_vm.options.filters)?_c('div',{staticClass:"vertically-centered"},_vm._l((_vm.filters),function(filter,index){return _c('div',{staticClass:"inline-block",attrs:{"id":'filter-' + index}},[_c('div',{staticClass:"vertically-centered mb-select-text"},[_vm._v(_vm._s(filter.label))]),_vm._v(" "),_c('select',{staticClass:"mb-select",on:{"change":_vm.handleFilterValueChange}},[_c('optgroup',_vm._l((filter.values),function(filterValue){return _c('option',{staticClass:"mb-select-option",domProps:{"value":_vm.slugifyFilterValue(filterValue)}},[_vm._v(" "+_vm._s(filterValue.label)+" ")])}))])])})):_vm._e(),_vm._v(" "),(!!_vm.options.sort && !!_vm.options.sort.select)?_c('div',{staticClass:"vertically-centered"},[_c('div',{staticClass:"vertically-centered mb-select-text"},[_vm._v("Sort by")]),_vm._v(" "),_c('select',{staticClass:"mb-select",on:{"change":_vm.handleSortValueChange}},[_c('optgroup',_vm._l((_vm.sortMethods),function(sortMethod){return _c('option',{staticClass:"mb-select-option",domProps:{"value":sortMethod}},[_vm._v(" "+_vm._s(sortMethod)+" ")])}))])]):_vm._e(),_vm._v(" "),(_vm.filterByTextFields)?_c('div',{staticClass:"vertically-centered"},[_c('div',{staticClass:"mb-select-text inline-block"},[_vm._v(" "+_vm._s(_vm.options.filterByText.label)+" ")]),_vm._v(" "),_c('form',{staticClass:"inline-block filter-by-text-form",on:{"submit":function($event){$event.preventDefault();_vm.handleFilterFormX($event);}}},[_c('input',{class:this.inputClass,attrs:{"id":"theInput"},on:{"keyup":_vm.handleFilterFormKeyup}}),_vm._v(" "),(this.searchText != '')?_c('button',{staticClass:"mb-search-control-button"},[_c('i',{staticClass:"fa fa-times fa-lg"})]):_vm._e()])]):_vm._e()]),_vm._v(" "),_c('div',{staticClass:"mb-horizontal-table-body"},[(_vm.slots.title)?_c('div',[_c('h4',{staticStyle:{"display":"inline-block"}},[_vm._v(" "+_vm._s(_vm.evaluateSlot(_vm.slots.title))+" "+_vm._s(_vm.countText)+" ")]),_vm._v(" "),_c('h5',{staticStyle:{"display":"inline-block","color":"gray"}},[_vm._v(" "+_vm._s(_vm.evaluateSlot(_vm.slots.subtitle))+" ")])]):_vm._e(),_vm._v(" "),_c('table',{staticClass:"stack",attrs:{"role":"grid"}},[_c('thead',[_c('tr',_vm._l((_vm.fields),function(field){return _c('th',[_vm._v(_vm._s(_vm.evaluateSlot(field.label)))])}))]),_vm._v(" "),_c('tbody',_vm._l((_vm.itemsLimited),function(item){return _c('horizontal-table-row',{key:item._featureId,attrs:{"item":item,"fields":_vm.fields,"hasOverlay":_vm.hasOverlay,"tableId":_vm.options.tableId}})}))]),_vm._v(" "),_c('div',{staticClass:"external-link"},[(_vm.options.externalLink && _vm.shouldShowExternalLink)?_c('a',{staticClass:"external",attrs:{"href":_vm.externalLinkHref,"target":"_blank"}},[_vm._v(" "+_vm._s(_vm.externalLinkText)+" ")]):_vm._e()])]),_vm._v(" "),(this.shouldShowRetrieveButton)?_c('a',{staticClass:"button center-button",on:{"click":this.showMoreRecords}},[_vm._v(" Retrieve "+_vm._s(this.nextIncrement)+" More "+_vm._s(this.nextIncrement === 1? 'Record' : 'Records')+" "),_c('span',{directives:[{name:"show",rawName:"v-show",value:(_vm.secondaryStatus === 'waiting'),expression:"secondaryStatus === 'waiting'"}],staticClass:"loading"},[_c('i',{staticClass:"fa fa-spinner fa-lg spin"})])]):_vm._e()]):_vm._e()])},staticRenderFns: [],_scopeId: 'data-v-43e19572',
mixins: [TopicComponent],
data: function data() {
var filters = this.options.filters || [];
var defaultFilterSelections = Object.keys(filters).reduce(function (acc, i) {
var key = "filter-" + i;
acc[key] = {};
return acc;
}, {});
var methods;
if (this.options.sort){
methods = this.options.sort.methods || [];
}
var sortMethod;
if (methods) {
sortMethod = methods[0];
} else {
sortMethod = DEFAULT_SORT_METHODS[0];
}
var highestRowRetrieved = this.options.defaultIncrement;
var initialData = {
filterSelections: defaultFilterSelections,
searchText: '',
sortMethod: sortMethod,
highestRowRetrieved: highestRowRetrieved
};
return initialData;
},
components: {
HorizontalTableRow: HorizontalTableRow
},
created: function created() {
var this$1 = this;
// console.log('horiz table created props slots items', this.$props.slots.items);
if (this.filters) {
for (var i = 0, list = this$1.filters.entries(); i < list.length; i += 1) {
var ref = list[i];
var index = ref[0];
var filter = ref[1];
var key = "filter-" + index;
var defaultValue = filter.values[0] || {};
this$1.filterSelections[key] = defaultValue;
}
}
// put row data in state once on load
// const data = this.itemsAfterSearch;
// const tableId = this.options.tableId;
// this.$store.commit('setTableFilteredData', {
// tableId,
// data
// });
},
mounted: function mounted() {
// console.log('horiz table mounted props slots items', this.$props.slots.items);
this.updateTableFilteredData();
},
watch: {
itemsAfterFilters: function itemsAfterFilters(nextItems) {
// console.log('WATCH items after filters', nextItems);
// this.$nextTick(() => {
this.updateTableFilteredData();
// })
}
},
computed: {
secondaryStatus: function secondaryStatus() {
return this.$store.state.sources[this.options.id].secondaryStatus;
},
shouldShowTable: function shouldShowTable() {
var result = true;
// if the table is in a tab group or table group, it will have an "item" in props
if (this.item) {
// if it is in a table group, the item will contain an "activeTable" for the group
if (this.item.activeTable) {
var id = this.options.id;
if (this.item.activeTable != id) {
result = false;
}
}
}
// if there is no data, and the table should not show at all if it is empty
if (this.$props.options.showOnlyIfData && this.items.length === 0) {
result = false;
}
return result;
},
shouldShowRetrieveButton: function shouldShowRetrieveButton() {
return this.highestRowRetrieved < this.count;
},
leftToRetrieve: function leftToRetrieve() {
return this.count - this.highestRowRetrieved;
},
nextIncrement: function nextIncrement() {
if (!this.options.showAllRowsOnFirstClick) {
if (this.leftToRetrieve < this.options.defaultIncrement) {
return this.leftToRetrieve;
} else {
return this.options.defaultIncrement;
}
} else {
return this.leftToRetrieve;
}
},
highestPageRetrieved: function highestPageRetrieved() {
return this.evaluateSlot(this.slots.highestPageRetrieved);
},
pageCount: function pageCount() {
return this.evaluateSlot(this.slots.pageCount);
},
totalSize: function totalSize() {
return this.evaluateSlot(this.slots.totalSize);
},
limit: function limit() {
return this.options.limit;
},
// REVIEW what does this do? can this be simplified?
inputClass: function inputClass() {
if (this.searchText === '') {
return 'mb-search-control-input';
} else {
return 'mb-search-control-input-full';
}
},
filters: function filters() {
return this.options.filters;
},
activeFilters: function activeFilters() {
//TODO make this work with not-always-on filters
return this.filters;
},
fields: function fields() {
return this.options.fields;
},
hasOverlay: function hasOverlay() {
return !!this.options.mapOverlay;
},
items: function items() {
var itemsSlot = this.slots.items;
var items = this.evaluateSlot(itemsSlot) || [];
// console.log('horiz table items', items);
return items
},
filterByTextFields: function filterByTextFields() {
if (this.options.filterByText) {
return this.options.filterByText.fields;
} else {
return null;
}
},
itemsAfterSearch: function itemsAfterSearch() {
// console.log('itemsAfterSearch is running');
var items = this.items;
var searchText = this.searchText;
if (!searchText) {
return items;
}
var searchTextLower = searchText.toLowerCase();
// get full set of items
// if text search is not enabled, return all items
var searchFields = this.filterByTextFields || [];
if (searchFields.length === 0) {
return items;
}
// get items that contain the search text in one of their filter fields
var matchingItems = items.filter(function (item) {
var searchVals = searchFields.map(function (filterField) {
var props = item.properties;
var searchVal = props ? props[filterField] : item[filterField];
// console.log('props', props, 'searchVal', searchVal);
return searchVal.toLowerCase();
});
var boolean = false;
for (var i = 0, list = searchVals; i < list.length; i += 1) {
// console.log('searchVal', searchVal, 'searchTextLower', searchTextLower);
var searchVal = list[i];
if (searchVal.includes(searchTextLower)) {
boolean = true;
}
}
return boolean;
});
return matchingItems;
},
// this takes itemsAfterSearch and applies selected filters
itemsAfterFilters: function itemsAfterFilters() {
// console.log('itemsAfterFilters is running');
var itemsAfterSearch = this.itemsAfterSearch;
var items = this.filterItems(itemsAfterSearch,
this.filters,
this.filterSelections);
// console.log('horiz table itemsAfterFilters', items);
return items;
},
itemsAfterSort: function itemsAfterSort() {
var itemsAfterFilters = this.itemsAfterFilters;
var sortOpts = this.options.sort;
// determine if the user selected a sort method
// let sortMethod;
// if (this.sortMethod && this.sortMethod.length > 0) {
// sortMethod = this.sortMethod;
// }
// let itemsAfterSort = itemsAfterFilters;
// if (sortMethod) {
// // get field to sort on
// // and then sort
// console.log('we got a sort method', sortMethod);
//
// itemsAfterSort
// // otherwise, if there are sort opts, use those and this.sortItems
// } else if (sortOpts) {
// itemsAfterSort = this.sortItems(itemsAfterFilters, sortOpts);
// }
// itemsAfterSort = ;
return this.sortItems(itemsAfterFilters, sortOpts);
},
sortMethods: function sortMethods() {
if (this.options.sort.methods) {
return this.options.sort.methods;
} else {
return DEFAULT_SORT_METHODS;
}
},
// this takes filtered items and applies the max number of rows
itemsLimited: function itemsLimited() {
// console.log('items limited', this.itemsAfterSort.slice(0, this.limit));
if (this.options.limit) {
return this.itemsAfterSort.slice(0, this.options.limit);
} else if (this.options.defaultIncrement) {
return this.itemsAfterSort.slice(0, this.highestRowRetrieved);
} else {
return this.itemsAfterSort;
}
},
count: function count() {
if (this.$props.options.useApiCount) {
return this.totalSize;
} else {
return this.itemsAfterFilters.length;
}
},
countText: function countText() {
if (this.$props.options.noCount) {
return '';
} else if (this.highestRowRetrieved < this.count) {
return ("(1 - " + (this.count < this.highestRowRetrieved ? this.count : this.highestRowRetrieved) + " of " + (this.count) + ")");
} else {
return ("(" + (this.count) + ")");
}
},
shouldShowExternalLink: function shouldShowExternalLink() {
if (this.options.externalLink.forceShow) {
return this.options.externalLink.forceShow;
} else {
return this.itemsAfterSearch.length > this.limit;
}
},
externalLinkAction: function externalLinkAction() {
return this.options.externalLink.action || 'See more';
},
externalLinkText: function externalLinkText() {
var externalLinkConf = this.options.externalLink;
var actionFn = externalLinkConf.action;
var actionText = actionFn(this.externalLinkCount);
var name = externalLinkConf.name;
return ("" + actionText);
// return `${actionText} at ${name}`;
},
externalLinkHref: function externalLinkHref() {
return this.evaluateSlot(this.options.externalLink.href);
},
// the number of items that aren't being shown (e.g. See 54 more...)
externalLinkCount: function externalLinkCount() {
return this.count - this.limit;
},
},
methods: {
showMoreRecords: function showMoreRecords() {
// if there is only 1 page to return (from AIS);
if (!this.pageCount) {
this.compareAndSetHighestRowRetrieved();
// if there are multiple pages to return (from AIS) and there are not enough items in the table state (itemsFiltered) to cover the increment;
} else if (this.itemsAfterFilters.length < this.highestRowRetrieved + this.options.defaultIncrement) {
// if there is another page to return (from AIS)
if (this.pageCount > this.highestPageRetrieved) {
this.getMoreRecords();
this.compareAndSetHighestRowRetrieved();
// if there are no more pages to return (from AIS)
} else {
this.highestRowRetrieved = this.count;
}
// if there are multiple pages to return (from AIS) but there are already enough items in the table state (itemsFiltered) to cover the increment;
} else {
if (!this.options.showAllRowsOnFirstClick) {
this.highestRowRetrieved = this.highestRowRetrieved + this.options.defaultIncrement;
} else {
this.highestRowRetrieved = this.count;
}
}
},
compareAndSetHighestRowRetrieved: function compareAndSetHighestRowRetrieved() {
if (!this.options.showAllRowsOnFirstClick) {
if (this.count < this.highestRowRetrieved + this.options.defaultIncrement) {
this.highestRowRetrieved = this.count;
} else {
this.highestRowRetrieved = this.highestRowRetrieved + this.options.defaultIncrement;
}
} else {
this.highestRowRetrieved = this.count;
}
},
getMoreRecords: function getMoreRecords() {
var dataSource = this.options.id;
var highestPageRetrieved = this.highestPageRetrieved;
this.$controller.getMoreRecords(dataSource, highestPageRetrieved);
},
slugifyFilterValue: function slugifyFilterValue(filterValue) {
var direction = filterValue.direction;
var value = filterValue.value;
var unit = filterValue.unit;
return [direction, value, unit].join('-');
},
deslugifyFilterValue: function deslugifyFilterValue(slug) {
var parts = slug.split('-');
var direction = parts[0];
var value = parts[1];
var unit = parts[2];
return {value: value, unit: unit, direction: direction};
},
handleSortValueChange: function handleSortValueChange(e) {
// console.log('handleSortValueChange running', e);
var value = e.target.value;
this.sortMethod = value;
},
handleFilterValueChange: function handleFilterValueChange(e) {
// console.log('handle filter value change', e);
var target = e.target;
var slug = target.value;
// deslugify filter value
var valueObj = this.deslugifyFilterValue(slug);
var parent = target.parentElement;
var parentId = parent.id;
// patch and replace filter selections
var prevFilterSelections = this.filterSelections;
var nextFilterSelections = Object.assign({}, prevFilterSelections);
nextFilterSelections[parentId] = valueObj;
this.filterSelections = nextFilterSelections;
},
values: function values(item) {
var fields = this.options.fields;
var sourceFields = fields.map(function (field) { return field.sourceField; });
return sourceFields.map(function (sourceField) { return item[sourceField]; })
},
handleFilterFormKeyup: function handleFilterFormKeyup(e) {
var input = e.target.value;
this.searchText = input;
},
handleFilterFormX: function handleFilterFormX(e) {
e.target[0].value = '';
this.searchText = "";
},
filterItems: function filterItems(items, filters, filterSelections) {
// console.log('FILTER ITEMS is running, items:', items, 'filters:', filters, 'filterSelections:', filterSelections);
var itemsFiltered = items.slice();
if (filters) {
var loop = function () {
var ref = list[i];
var index = ref[0];
var filter = ref[1];
var key = "filter-" + index;
var data = filterSelections[key];
var type = filter.type;
var getValue = filter.getValue;
var unit = data.unit;
var value = data.value;
var direction = data.direction || 'subtract';
// TODO put these in separate methods
switch(type) {
case 'data':
// console.log('DATA FILTER');
// itemsFiltered = itemsFiltered.filter(item => {
// const itemValue = getValue(item);
// console.log('horiz table itemValue:', itemValue);
// return itemValue;
// });
break;
case 'time':
// console.log('TIME FILTER direction', direction);
var min = (void 0), max = (void 0);
if (direction === 'subtract') {
max = moment();
min = moment().subtract(value, unit);
// console.log('max:', max, 'min', min);
} else if (direction === 'add') {
min = moment();
max = min.add(value, unit);
} else {
throw ("Invalid time direction: " + direction);
}
itemsFiltered = itemsFiltered.filter(function (item) {
var itemValue = getValue(item);
var itemMoment = moment(itemValue);
var isBetween = itemMoment.isBetween(min, max);
return isBetween;
});
// console.log('ITEMS FILTERED BY TIME FILTER', itemsFiltered);
break;
default:
throw ("Unhandled filter type: " + type);
break;
}
};
for (var i = 0, list = filters.entries(); i < list.length; i += 1) loop();
}
return itemsFiltered;
},
// sortItems(items, sortOpts) {
sortItems: function sortItems(items, sortOpts) {
// console.log('sortItems, sortOpts:', sortOpts);
// TODO finish this
// if (Object.keys(this.filterData).length) {
// console.log('there is filterData', this.filterData);
// return this.itemsFiltered;
// } else {
// console.log('there is no filterData');
// return this.items;
// }
// const items = this.itemsFiltered;
// const sortOpts = this.options.sort;
// console.log(sortOpts)
// if there's no no sort config, just return the items.
if (!sortOpts) {
// console.log('noSortOpts');
return items;
}
// const getValueFn = sortOpts.getValue;
// const order = sortOpts.order;
// get sort fn or use this basic one
var sortFn = sortOpts.compare || this.defaultSortFn;
// console.log('sortFn', sortFn);
// console.log('sortFn', sortFn)
return items.sort(sortFn);
},
defaultSortFn: function defaultSortFn(a, b) {
// console.log('defaultSortFn is running, a:', a, 'b:', b);
var sortOpts = this.options.sort;
var getValueFn = sortOpts.getValue;
var sortMethod = this.sortMethod;
var order = sortOpts.order;
var valA = getValueFn(a, sortMethod);
var valB = getValueFn(b, sortMethod);
var result;
if (valA === null) {
if (order === 'desc') {
result = -1;
} else {
result = 1;
}
} else if (valB === null) {
if (order === 'desc') {
result = 1;
} else {
result = -1;
}
} else if (valA < valB) {
result = -1;
} else if (valB < valA) {
result = 1;
} else {
result = 0;
}
// reverse if we have an order and the target order is desc
if (order) {
if (order === 'desc') {
result = result * -1;
} else if (order !== 'asc') {
throw ("Unknown sort order: " + order);
}
}
// console.log('compare', valA, 'to', valB, ', result:', result);
return result;
},
// this updates the global state that stores filtered table rows
updateTableFilteredData: function updateTableFilteredData() {
// console.log('update table filtered data');
// get table id
var ref = this.options;
var tableId = ref.tableId;
// update global state
this.$store.commit('setTableFilteredData', {
tableId: tableId,
data: this.itemsAfterFilters
});
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" table[data-v-0524eb40] { margin: 0; } th[data-v-0524eb40], td[data-v-0524eb40] { font-size: 15px; text-align: left; } th[data-v-0524eb40] { width: 30%; } .external-link[data-v-0524eb40] { padding-top: 5px; } .table-title[data-v-0524eb40] { /*too much*/ /*margin-top: 1rem;*/ } .table-container[data-v-0524eb40] { /*this was too much padding for the parcel table, taking out for now*/ /*padding-top: 1rem;*/ } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var VerticalTable = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.shouldShowTable)?_c('div',{staticClass:"table-container"},[(_vm.slots.title)?_c('h4',{staticClass:"table-title"},[_vm._v(" "+_vm._s(_vm.evaluateSlot(_vm.slots.title))+" ")]):_vm._e(),_vm._v(" "),_c('table',[_c('tbody',_vm._l((_vm.slots.fields),function(field){return _c('tr',[_c('th',{domProps:{"innerHTML":_vm._s(_vm.evaluateSlot(field.label))}}),_vm._v(" "),_c('td',{domProps:{"innerHTML":_vm._s(_vm.evaluateSlot(field.value, field.transforms, _vm.nullValue))}})])}))]),_vm._v(" "),_c('div',{staticClass:"external-link"},[(_vm.options && _vm.options.externalLink)?_c('a',{staticClass:"external external-link",attrs:{"href":_vm.externalLinkHref,"target":"_blank"}},[_vm._v(" "+_vm._s(_vm.externalLinkText)+" ")]):_vm._e()])]):_vm._e()},staticRenderFns: [],_scopeId: 'data-v-0524eb40',
mixins: [TopicComponent],
computed: {
shouldShowTable: function shouldShowTable() {
if (this.item) {
if (this.item.activeTable) {
var filterValue = this.item.activeTable;
var id = this.options.id;
if (filterValue === id) {
return true
} else {
return false;
}
} else {
return true;
}
} else {
return true;
}
},
externalLinkAction: function externalLinkAction() {
return this.options.externalLink.action || 'See more';
},
externalLinkText: function externalLinkText() {
var externalLinkConf = this.options.externalLink;
var actionFn = externalLinkConf.action;
var actionText = actionFn(this.externalLinkCount);
var name = externalLinkConf.name;
return (actionText + " at " + name);
},
externalLinkHref: function externalLinkHref() {
return this.evaluateSlot(this.options.externalLink.href);
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" img[data-v-8af9077a] { display: block; margin: 0 auto; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Image_ = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('img',{attrs:{"src":_vm.slots.source}})},staticRenderFns: [],_scopeId: 'data-v-8af9077a',
mixins: [TopicComponent]
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .mb-panel-topics-greeting[data-v-2d681dc9] { padding-top: 20px; } .greeting[data-v-2d681dc9] { font-size: 20px; color: #444; padding: 14px; } .greeting-error[data-v-2d681dc9] { border-left-color: #ff0000; } /*medium*/ @media screen and (min-width: 750px) { .mb-panel-topics-greeting[data-v-2d681dc9] { /*make this scroll on medium screens*/ /*REVIEW this is a little hacky. the 120px shouldn't be hard-coded.*/ height: calc(100vh - 120px); overflow: auto; } } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// TODO find a less explicit way of importing everything
// import Callout from './topic-components/Callout';
var Greeting = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"mb-panel-topics-greeting"},[_c('div',{staticClass:"columns medium-20 medium-centered"},[(!_vm.components && !_vm.hasError)?_c('div',{staticClass:"greeting",domProps:{"innerHTML":_vm._s(_vm.initialMessage)}}):_vm._e(),_vm._v(" "),(!_vm.components && _vm.hasError)?_c('div',{staticClass:"greeting greeting-error",domProps:{"innerHTML":_vm._s(_vm.errorMessage)}}):_vm._e(),_vm._v(" "),_vm._l((_vm.components),function(topicComp,topicCompIndex){return (_vm.components)?_c(topicComp.type,{key:'greeting',tag:"component",staticClass:"topic-comp",attrs:{"slots":topicComp.slots}}):_vm._e()})],2)])},staticRenderFns: [],_scopeId: 'data-v-2d681dc9',
components: {
Image_: Image_
},
computed: {
components: function components() {
var greetingConfig = this.$config.greeting || {};
return greetingConfig.components;
},
hasError: function hasError() {
return this.$store.state.geocode.status === 'error';
},
initialMessage: function initialMessage() {
var greetingConfig = this.$config.greeting || {};
return greetingConfig.initialMessage;
},
errorMessage: function errorMessage() {
var input = this.$store.state.geocode.input;
return ("\n <p>\n We couldn't find\n " + (input ? '<strong>' + input + '</strong>' : 'that address') + ".\n Are you sure everything was spelled correctly?\n </p>\n <p>\n Here are some examples of things you can search for:\n </p>\n <ul>\n <li>1234 Market St</li>\n <li>1001 Pine Street #201</li>\n <li>12th & Market</li>\n </ul>\n ");
}
}
};
function generateUniqueId() {
return Math.random().toString(36).substring(7);
}
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .callout[data-v-2708dc98] { position: inherit; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Callout = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"callout"},[_c('p',{domProps:{"innerHTML":_vm._s(this.message)}})])},staticRenderFns: [],_scopeId: 'data-v-2708dc98',
mixins: [TopicComponent],
computed: {
message: function message() {
return this.evaluateSlot(this.$props.slots.text)
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*# sourceMappingURL=CollectionSummary.vue.map */"; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var CollectionSummary = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('h3',[_vm._v(" "+_vm._s(_vm.summary)+" ")])},staticRenderFns: [],_scopeId: 'data-v-47166f90',
mixins: [TopicComponent],
computed: {
// the final stringified output
summary: function summary() {
// get value quantity map
var valueQuantities = this.valueQuantities;
// check if plural
var isPlural = this.isPlural(valueQuantities);
// get context renderer
var contextFnKey = 'context' + (isPlural ? 'Plural' : 'Singular');
var contextFn = this[contextFnKey];
// get a natural list
var naturalList = this.naturalList;
// summarize
var summary = contextFn(naturalList);
return summary;
},
contextSingular: function contextSingular() {
var context = this.options.context;
return context.singular || context;
},
contextPlural: function contextPlural() {
var context = this.options.context;
return context.plural || context;
},
descriptorSingular: function descriptorSingular() {
var descriptor = this.options.descriptor;
return descriptor.singular || descriptor;
},
descriptorPlural: function descriptorPlural() {
var descriptor = this.options.descriptor;
return descriptor.plural || descriptor + 's';
},
// serializes naturalized quantities into a list
// e.g. "1 apple and 2 oranges"
naturalList: function naturalList() {
var valueQuantities = this.valueQuantities;
var items = this.naturalizeQuantities(valueQuantities);
var len = items.length;
if (Array.isArray(items) && len > 0) {
if (len === 1) {
return items[0];
} else if (len === 2) {
return items.join(' and ');
}
var leadingItems = items.slice(0, items.length - 1).join(', ');
var lastItem = items[items.length - 1];
return (leadingItems + ", and " + lastItem);
}
// TODO should this text be an option?
return ("no " + (this.descriptorPlural));
},
valueQuantities: function valueQuantities() {
var items = this.slots.items(this.$store.state);
var getValue = this.options.getValue;
// make an object of value => quantity
var valueQuantities = items.reduce(function (obj, item) {
var val = getValue(item);
obj[val] = obj[val] || 0;
obj[val]++;
return obj;
}, {});
return valueQuantities;
},
},
methods: {
// takes the value of the valueQuantities computed property and returns
// the appropriate grammatical number.
isPlural: function isPlural(valueQuantities) {
if ( valueQuantities === void 0 ) valueQuantities = {};
var values = Object.keys(valueQuantities);
if (values.length === 1) {
var firstValue = values[0];
var quantity = valueQuantities[firstValue];
if (quantity === 1) {
return false;
}
}
return true;
},
// takes the value quantity map and converts values to natural language
// quantities (e.g. {apple: 2} => "2 apples")
naturalizeQuantities: function naturalizeQuantities(valueQuantities) {
if ( valueQuantities === void 0 ) valueQuantities = {};
// get some options
var types = this.options.types;
var includeZeroes = this.options.includeZeroes;
// convert to natural language and sort per order of types option
var quantities = types.reduce(function (acc, type) {
var value = type.value;
var quantity = valueQuantities[value] || 0;
if (quantity === 0) {
if (!includeZeroes) {
return acc;
}
// natural zero => "no"
quantity = 'no';
}
var labelSingular = type.label;
var labelWithNumber;
// singular
if (quantity !== 1) {
var labelPlural = type.plural || labelSingular + 's';
labelWithNumber = labelPlural;
// plural
} else {
labelWithNumber = labelSingular;
}
// make label and push
var quantityWithLabel = quantity + " " + labelWithNumber;
acc.push(quantityWithLabel);
return acc;
}, []);
return quantities;
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .container[data-v-0407ab3a] { margin-bottom: 30px; } .button[data-v-0407ab3a] { margin-right: 10px; margin-top: 0px; margin-bottom: 0px; } .overlay-toggle[data-v-0407ab3a] { border: 1px solid #f99300; color: #f99300; background: #fff; } .overlay-toggle.active[data-v-0407ab3a] { background: #f99300; color: #fff; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var OverlayToggleGroup = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.items.length)?_c('div',[_c('div',{staticClass:"container"},[(_vm.slots.title)?_c('h4',[_vm._v(" "+_vm._s(_vm.evaluateSlot(_vm.slots.title))+" ")]):_vm._e(),_vm._v(" "),_vm._l((_vm.items),function(item){return _c('a',{staticClass:"button overlay-toggle",class:{'active': _vm.isActive(item)},attrs:{"href":"#","data-key":_vm.keyForItem(item)},on:{"click":_vm.handleClick}},[_vm._v(" "+_vm._s(_vm.keyForItem(item))+" ")])})],2)]):_vm._e()},staticRenderFns: [],_scopeId: 'data-v-0407ab3a',
mixins: [TopicComponent],
computed: {
items: function items() {
return this.evaluateSlot(this.slots.items);
},
},
methods: {
isActive: function isActive(item) {
var imageOverlay = this.$store.state.map.imageOverlay;
var itemKey = this.keyForItem(item);
return imageOverlay === itemKey;
},
keyForItem: function keyForItem(item) {
var getKeyFn = this.options.getKey;
return getKeyFn(item);
},
handleClick: function handleClick(e) {
var prevImageOverlay = this.$store.state.map.imageOverlay;
var nextImageOverlay = e.target.getAttribute('data-key');
// console.log(nextImageOverlay);
if (prevImageOverlay === nextImageOverlay) {
this.$store.commit('setImageOverlay', null);
} else {
this.$store.commit('setImageOverlay', nextImageOverlay);
}
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .list[data-v-9aa0b734] { position: inherit; margin-bottom: 0px !important; } ul[data-v-9aa0b734] { list-style: none; padding-left: 0; margin-left: 0; } .message-p[data-v-9aa0b734] { margin-bottom: 0px; } /*.topic-body { margin-bottom: 0px; }*/ "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var List = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"list"},[(_vm.evaluateSlot(_vm.slots.relatedAddresses))?_c('ul',_vm._l((_vm.evaluateSlot(_vm.slots.relatedAddresses)),function(relatedAddress){return _c('li',[_c('a',{attrs:{"href":'#/' + encodeURIComponent(relatedAddress.properties.street_address)}},[_vm._v(" "+_vm._s(relatedAddress.properties.street_address)+" ")])])})):_c('p',{staticClass:"message-p"},[_vm._v(" No related addresses were found for this address. ")])])},staticRenderFns: [],_scopeId: 'data-v-9aa0b734',
mixins: [TopicComponent],
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .topic-component[data-v-6c6d5231] { margin-bottom: 10px !important; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var TopicComponentGroup = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',_vm._l((_vm.topicComponents),function(comp,compIndex){return _c(comp.type,{key:_vm.getCompKey(_vm.key, compIndex),tag:"component",staticClass:"topic-component",attrs:{"slots":comp.slots,"options":comp.options,"item":_vm.item}})}))},staticRenderFns: [],_scopeId: 'data-v-6c6d5231',
props: ['topicComponents', 'item', 'filterData'],
components: {
Badge: Badge,
Callout: Callout,
CollectionSummary: CollectionSummary,
HorizontalTable: HorizontalTable,
Image_: Image_,
VerticalTable: VerticalTable,
OverlayToggleGroup: OverlayToggleGroup,
List: List
},
beforeCreate: function beforeCreate() {
// TabGroup imports TopicComponentGroup, which causes a circular
// reference issue in webpack. so register the component here.
this.$options.components.TabGroup = require('./topic-components/TabGroup.vue');
this.$options.components.TableGroup = require('./topic-components/TableGroup.vue');
},
data: function data() {
return {
// generate a (basically) unique id for the group. the go-to npm packages
// for uuid generation aren't available as umd builds on unpkg and
// therefore won't work with the examples. this is good enough :)
key: generateUniqueId()
};
},
methods: {
getCompKey: function getCompKey(compGroupKey, compIndex) {
return ("topic-comp-" + compGroupKey + "-" + compIndex);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*REVIEW these aren't prefixed `mb-`because they're scoped, but it feels inconsistent?*/ .topic-header[data-v-2db893cf] { background: #f5f5f5; border: 1px solid #ddd; display: block; font-size: 18px; font-weight: normal; height: 70px; line-height: 45px; padding: 10px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); margin-bottom: 8px; } .topic-header[data-v-2db893cf]:hover { background: #fff; color: inherit; } .topic-header-icon[data-v-2db893cf] { padding-left: 10px; padding-right: 10px; } .topic-body[data-v-2db893cf] { padding: 5px; margin-bottom: 10px; } .loading[data-v-2db893cf] { float: right; } .topic-body-enter-active[data-v-2db893cf], .topic-body-leave-active[data-v-2db893cf] { transition: opacity 0.18s; } .topic-body-enter[data-v-2db893cf], .topic-body-leave-to[data-v-2db893cf] { opacity: 0; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// import { mapMutations } from 'vuex';
var Topic = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return (_vm.shouldShowTopic)?_c('div',[(_vm.shouldShowHeader)?_c('a',{staticClass:"topic-header",attrs:{"href":"#","data-topic-key":_vm.topicKey},on:{"click":function($event){$event.preventDefault();_vm.handleTopicHeaderClick($event);}}},[_c('span',{directives:[{name:"show",rawName:"v-show",value:(_vm.status === 'waiting'),expression:"status === 'waiting'"}],staticClass:"loading"},[_c('i',{staticClass:"fa fa-spinner fa-lg spin"})]),_vm._v(" "),_c('i',{class:['fa', 'fa-' + _vm.icon, 'topic-header-icon'],attrs:{"aria-hidden":"true"}}),_vm._v(" "+_vm._s(_vm.topic.label)+" ")]):_vm._e(),_vm._v(" "),_c('transition',{attrs:{"name":"topic-body"}},[(_vm.shouldShowBody)?_c('div',{staticClass:"topic-body"},[_c('topic-component-group',{attrs:{"topic-components":_vm.topic.components}})],1):_vm._e()]),_vm._v(" "),_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.shouldShowError),expression:"shouldShowError"}],staticClass:"topic-body",domProps:{"innerHTML":_vm._s(this.errorMessage)}})],1):_vm._e()},staticRenderFns: [],_scopeId: 'data-v-2db893cf',
props: ['topicKey'],
components: {
TopicComponentGroup: TopicComponentGroup
},
computed: {
// returns the full config object for the topic
topic: function topic() {
var this$1 = this;
var topicKey = this.$props.topicKey;
var topicsFiltered = this.$config.topics.filter(function (topic) {
return topic.key === this$1.$props.topicKey;
});
if (topicsFiltered.length !== 1) {
throw ("Could not get single config object for topic '" + topicKey + "'.");
}
var config = topicsFiltered[0];
return config;
},
icon: function icon() {
return this.topic.icon;
},
isActive: function isActive() {
var key = this.topic.key;
var activeTopic = this.$store.state.activeTopic;
return activeTopic === key;
},
shouldShowHeader: function shouldShowHeader() {
return this.$config.topics.length > 1;
},
dataSources: function dataSources() {
return this.topic.dataSources || [];
},
hasData: function hasData() {
var this$1 = this;
return this.dataSources.every(function (dataSource) {
var targetsFn = this$1.$config.dataSources[dataSource].targets;
if (targetsFn) {
var targetsMap = this$1.$store.state.sources[dataSource].targets;
var targets = Object.values(targetsMap);
// console.log('topic has data targets:', targets);
if (targets.length === 0) {
// console.log('targets doesnt exist');
return false;
}
return targets.every(function (target) { return target.status !== 'waiting'; });
} else {
return this$1.$store.state.sources[dataSource].data;
}
});
// }
},
shouldShowBody: function shouldShowBody() {
var succeeded = this.status === 'success';
var hasData = this.hasData;
var should = succeeded && hasData && this.isActive;
return should;
},
shouldShowTopic: function shouldShowTopic() {
var this$1 = this;
if (!this.topic.onlyShowTopicIfDataExists) {
return true;
} else {
var result = true;
var requiredDataSources = Object.keys(this.topic.onlyShowTopicIfDataExists);
// console.log('requiredDataSources', requiredDataSources);
for (var i = 0, list = requiredDataSources; i < list.length; i += 1) {
var requiredDataSource = list[i];
var dataSource = this$1.topic.onlyShowTopicIfDataExists[requiredDataSource];
var pathToDataArray = dataSource.pathToDataArray;
var minDataLength = dataSource.minDataLength;
// console.log('requiredDataSource', requiredDataSource, 'dataSource', dataSource);
var dataArray = (void 0);
if (!this$1.$store.state.sources[requiredDataSource].data) {
// if there is no data (yet)
return false;
} else {
if (!pathToDataArray) {
dataArray = this$1.$store.state.sources[requiredDataSource].data;
} else if (pathToDataArray.length === 1) {
dataArray = this$1.$store.state.sources[requiredDataSource].data[pathToDataArray[0]];
}
// TODO - implement system if the path to the data is longer than a single step
// else {
// dataArray = this.$store.state.sources[requiredDataSource].data[pathToDataArray[0]].[pathToDataArray[1]];
// }
if (dataArray.length < minDataLength) {
result = false;
}
}
}
return result;
}
},
shouldShowError: function shouldShowError() {
return (
// topic must be active and
this.isActive && (
// there either has to be an error or
this.status === 'error' ||
// we got the response and it's empty
(this.status !== 'waiting' && !this.hasData)
)
);
},
errorMessage: function errorMessage() {
if (this.topic.errorMessage) {
console.log('errorMessage exists', this.topic.errorMessage(this.$store.state));
return this.topic.errorMessage(this.$store.state);
} else {
return 'Could not locate records for that address.';
}
},
// REVIEW this is getting cached and not updating when the deps update
status: {
cache: false,
get: function get() {
var this$1 = this;
// get the status of each source
var dataSources = this.topic.dataSources || [];
// if no sources, return success
if (dataSources.length === 0) {
return 'success';
}
var topicStatus;
var sourceStatuses = dataSources.map(function (dataSource) {
// this is what should be observed. when it changes,
// it's not causing this to re-evaluate.
return this$1.$store.state.sources[dataSource].status;
});
// if any sources are still waiting, return waiting
if (sourceStatuses.some(function (x) { return x === 'waiting'; })) {
topicStatus = 'waiting';
}
// if any sources have errors, return error
else if (sourceStatuses.some(function (x) { return x === 'error'; })) {
topicStatus = 'error';
}
else {
topicStatus = 'success';
}
return topicStatus;
}
},
},
methods: {
configForBasemap: function configForBasemap(key) {
return this.$config.map.basemaps[key];
},
handleTopicHeaderClick: function handleTopicHeaderClick(e) {
var topic = this.$props.topicKey;
var nextTopic;
if (topic !== this.$store.state.activeTopic) {
nextTopic = topic;
}
// notify controller (which will handle routing)
this.$controller.handleTopicHeaderClick(nextTopic);
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .address-header[data-v-c37cf8b6] { background: #daedfe; color: #0f4d90; padding: 20px; /*this keeps the box shadow over the scrollable part of the panel*/ position: relative; z-index: 1; -webkit-box-shadow: 0px 5px 7px -2px rgba(0,0,0,0.18); -moz-box-shadow: 0px 5px 7px -2px rgba(0,0,0,0.18); box-shadow: 0px 5px 7px -2px rgba(0,0,0,0.18); } .address-header-line-1[data-v-c37cf8b6] { margin-bottom: 0; margin-top: 0; } .topics-container[data-v-c37cf8b6] { padding: 20px; } @media screen and (min-width: 40em) { .topics-container[data-v-c37cf8b6] { height: calc(100vh - 210px); } } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var TopicPanel = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"cell medium-12 small-order-2 medium-order-1"},[_c('greeting',{directives:[{name:"show",rawName:"v-show",value:(_vm.shouldShowGreeting),expression:"shouldShowGreeting"}]}),_vm._v(" "),(!_vm.shouldShowGreeting)?_c('div',{staticClass:"cell"},[_c('div',{staticClass:"address-header"},[_c('h1',{staticClass:"address-header-line-1"},[_c('i',{staticClass:"fa fa-map-marker"}),_vm._v(" "+_vm._s(_vm.address)+" ")]),_vm._v(" "),_c('div',{staticClass:"address-header-line-2"},[_vm._v("PHILADELPHIA, PA "+_vm._s(_vm.zipCode))])]),_vm._v(" "),_c('div',{staticClass:"topics-container cell medium-cell-block-y"},_vm._l((this.$config.topics),function(topic){return _c('topic',{key:topic.key,attrs:{"topicKey":topic.key}})}))]):_vm._e()],1)},staticRenderFns: [],_scopeId: 'data-v-c37cf8b6',
components: {
Greeting: Greeting,
Topic: Topic
},
// data() {
// const data = {
// styleObject: {
// 'position': 'relative',
// 'top': '100px',
// 'overflow-y': 'auto',
// 'height': '100px'
// }
// };
// return data;
// },
// mounted() {
// window.addEventListener('resize', this.handleWindowResize);
// this.handleWindowResize();
// },
// beforeDestroy() {
// window.removeEventListener('resize', this.handleWindowResize);
// },
computed: {
geocode: function geocode() {
return this.$store.state.geocode.data;
},
dorParcels: function dorParcels() {
return this.$store.state.parcels.dor.data.length > 0;
},
shouldShowGreeting: function shouldShowGreeting() {
return !(this.geocode || this.dorParcels);
},
// this returns the address shown in the address header
address: function address() {
var geocode = this.geocode;
var dorParcels = this.$store.state.parcels.dor.data;
var activeDorAddress = this.$store.state.parcels.dor.activeAddress;
var address;
if (geocode) {
// TODO make this not ais-specific
// REVIEW what's the difference between these two?
var addressA = geocode.properties.street_address;
var addressB = geocode.street_address;
address = addressA || addressB;
// a DOR address might be found even if there is no geocode
} else if (activeDorAddress) {
address = activeDorAddress;
}
return address;
},
zipCode: function zipCode() {
var geocode = this.geocode;
if (!geocode) { return null; }
var zipCode = geocode.properties.zip_code;
var zip4 = geocode.properties.zip_4;
var parts = [zipCode];
if (zip4) { parts.push(zip4); }
return parts.join('-');
},
},
methods: {
shouldShowTopic: function shouldShowTopic(topic) {
var requiredSources = topic.dataSources || [];
// if there aren't any required topics, show it
if (requiredSources.length === 0) {
return true;
}
var sources = this.$store.state.sources;
return requiredSources.every(function (key) { return sources[key].data; })
},
// handleWindowResize() {
// // console.log('handleWindowResize is running');
// const rootElement = document.getElementById('mb-root');
// const rootStyle = window.getComputedStyle(rootElement);
// const rootHeight = rootStyle.getPropertyValue('height');
// const rootHeightNum = parseInt(rootHeight.replace('px', ''));
// const topicsHeight = rootHeightNum - 100;
// this.styleObject.height = topicsHeight.toString() + 'px';
// }
}
};
var markersMixin = {
watch: {
activeFeature: function activeFeature(nextActiveFeature, prevActiveFeature) {
// console.log('WATCH active feature', prevActiveFeature, '=>', nextActiveFeature);
var updateFeature;
if (nextActiveFeature && nextActiveFeature.tableId && nextActiveFeature.featureId) {
updateFeature = nextActiveFeature;
} else {
updateFeature = prevActiveFeature;
}
var featureId = updateFeature.featureId;
var tableId = updateFeature.tableId;
// get marker
var layerMap = this.$store.state.map.map._layers;
var layers = Object.values(layerMap);
var matchingLayer = layers.filter(function (layer) {
var options = layer.options || {};
var data = options.data;
if (!data) { return; }
var layerFeatureId = data.featureId;
var layerTableId = data.tableId;
return layerFeatureId === featureId && layerTableId === tableId;
})[0];
// if (!matchingLayer) return;
this.updateCircleMarkerFillColor(matchingLayer);
// bring to front
this.bringCircleMarkerToFront(matchingLayer);
},
},
computed: {
locationMarker: function locationMarker() {
var latlngArray = [this.$store.state.map.location.lat, this.$store.state.map.location.lng];
var marker = {
latlng: latlngArray,
radius: 6,
fillColor: '#ff3f3f',
color: '#ff0000',
weight: 1,
opacity: 1,
fillOpacity: 1.0
};
return marker;
},
// returns map markers as simple object with a geometry property, key,
// and optional properties for symbology
markers: function markers() {
var markers = [];
// geocoded address marker
var geocodeGeom = this.geocodeGeom;
if (this.identifyFeature === 'address-marker' && geocodeGeom) {
var latlng = [].concat( geocodeGeom.coordinates ).reverse();
var key = this.geocodeResult.properties.street_address;
var addressMarker = {latlng: latlng, key: key};
markers.push(addressMarker);
}
return markers;
},
circleMarkers: function circleMarkers() {
var this$1 = this;
var filteredData = this.$store.state.tables.filteredData;
var circleMarkers = [];
// get visible tables based on active topic
var tableIds = this.$store.getters.visibleTableIds;
for (var i$1 = 0, list$1 = tableIds; i$1 < list$1.length; i$1 += 1) {
var tableId = list$1[i$1];
var tableConfig = this$1.getConfigForTable(tableId) || {};
var mapOverlay = (tableConfig.options || {}).mapOverlay;
if (!mapOverlay) {
continue;
}
var items = filteredData[tableId];
if (items.length < 1) {
continue;
}
var style = mapOverlay.style;
// go through rows
for (var i = 0, list = items; i < list.length; i += 1) {
var item = list[i];
var latlng = (void 0);
// TODO - get geometry field name from config
if (item.geometry) {
var ref = item.geometry.coordinates;
var x = ref[0];
var y = ref[1];
latlng = [y, x];
} else if (item.lat) {
latlng = [item.lat, item.lng];
// if (item.point_x) {
// latlng = [item.point_y, item.point_x];
// } else if (item.geocode_x) {
// latlng = [item.geocode_y, item.geocode_x];
// }
}
// check for active feature TODO - bind style props to state
var props = Object.assign({}, style);
props.latlng = latlng;
props.featureId = item._featureId;
props.tableId = tableId;
circleMarkers.push(props);
}
}
return circleMarkers;
},
// returns all geojson features to be rendered on the map along with
// necessary props.
geojsonFeatures: function geojsonFeatures() {
var features = [];
var identifyFeature = this.identifyFeature;
var activeParcelLayer = this.activeParcelLayer;
// pwd parcel
if (identifyFeature === 'pwd-parcel' && activeParcelLayer === 'pwd' && this.pwdParcel) {
var geojson = this.pwdParcel;
var color = 'blue';
var key = geojson.properties.PARCELID;
features.push({geojson: geojson, color: color, key: key});
// dor parcel
} else if (identifyFeature === 'dor-parcel' && activeParcelLayer === 'dor') {
var color$1 = 'blue';
var dorParcelFeatures = this.dorParcels.map(function (dorParcel) {
var geojson = dorParcel;
var key = geojson.properties.OBJECTID;
return {geojson: geojson, color: color$1, key: key};
});
features.push.apply(features, dorParcelFeatures);
}
// GeoJSON overlays
// const stateSources = this.$store.state.sources;
// const dataSourcesConfig = this.$config.dataSources;
//
// // step through the (possibly multiple) datasources for the active topic
// for (let dataSource of this.activeTopicConfig.dataSources) {
// // filter datasources with format geojson
// if (dataSourcesConfig[dataSource].format === 'geojson') {
// // step through to add each geojson object to "features"
// for (let geojson of stateSources[dataSource].data) {
// let overlayFeature = this.activeTopicConfig.overlayFeature;
// let key = geojson.id;
// features.push({geojson, overlayFeature, key});
// }
// }
// }
// TODO filter by selected 311, police
return features;
},
leafletMarkers: function leafletMarkers() {
var markers = [];
markers.push.apply(markers, this.markers);
markers.push.apply(markers, this.geojsonFeatures);
return markers;
},
},
methods: {
getTableFromComps: function getTableFromComps(comps, tableId) {
var matchingComps = comps.filter(function (comp) {
return (
comp.type === 'horizontal-table' &&
comp._id == tableId
);
}) || [];
return matchingComps[0];
},
getConfigForTable: function getConfigForTable(tableId) {
var this$1 = this;
var topics = this.$config.topics || [];
for (var i$1 = 0, list$1 = topics; i$1 < list$1.length; i$1 += 1) {
var topic = list$1[i$1];
var comps = topic.components || [];
// try outer comps
var table = this$1.getTableFromComps(comps, tableId);
if (table) { return table; }
// try inner comps
for (var i = 0, list = comps; i < list.length; i += 1) {
var comp = list[i];
var options = comp.options || {};
var innerComps = options.components || [];
if (innerComps.length > 0) {
var innerTable = this$1.getTableFromComps(innerComps, tableId);
// console.log('table on 2nd try', innerTable, innerComps);
if (innerTable) { return innerTable; }
}
}
}
},
bringCircleMarkerToFront: function bringCircleMarkerToFront(circleMarker) {
// put marker on top
var el = circleMarker._path;
// remove from parent
var group = circleMarker._renderer._rootGroup;
group.removeChild(el);
// append to end (which brings it to the front)
group.appendChild(el);
},
handleCircleMarkerMouseover: function handleCircleMarkerMouseover(e) {
console.log('handleCircleMarkerMouseover is starting');
if (!this.isMobileOrTablet) {
console.log('handleCircleMarkerMouseover actions are running');
var target = e.target;
var ref = target.options.data;
var featureId = ref.featureId;
var tableId = ref.tableId;
console.log('target:', target, 'featureId:', featureId, 'tableId:', tableId);
this.$store.commit('setActiveFeature', { featureId: featureId, tableId: tableId });
}
},
handleCircleMarkerClick: function handleCircleMarkerClick(e) {
console.log('handleCircleMarkerClick is starting');
if (this.isMobileOrTablet) {
console.log('handleCircleMarkerClick actions are running');
var target = e.target;
var ref = target.options.data;
var featureId = ref.featureId;
var tableId = ref.tableId;
console.log('target:', target, 'featureId:', featureId, 'tableId:', tableId);
this.$store.commit('setActiveFeature', { featureId: featureId, tableId: tableId });
}
},
handleCircleMarkerMouseout: function handleCircleMarkerMouseout(e) {
console.log('handleCircleMarkerMouseout is starting');
// if (!this.isMobileOrTablet) {
console.log('handleCircleMarkerMouseout actions are running');
var target = e.target;
this.$store.commit('setActiveFeature', null);
// }
},
updateCircleMarkerFillColor: function updateCircleMarkerFillColor(marker) {
// get next fill color
var ref = marker.options.data;
var featureId = ref.featureId;
var tableId = ref.tableId;
var nextFillColor = this.fillColorForCircleMarker(featureId, tableId);
// highlight. we're doing this here (non-reactively) because binding the
// fill color property was not performing well enough.
var nextStyle = Object.assign({}, marker.options);
nextStyle.fillColor = nextFillColor;
marker.setStyle(nextStyle);
},
}
};
var cyclomediaMixin = {
computed: {
cyclomediaActive: function cyclomediaActive() {
return this.$store.state.cyclomedia.active;
},
cyclomediaRecordings: function cyclomediaRecordings() {
return this.$store.state.cyclomedia.recordings;
},
},
methods: {
handleCyclomediaButtonClick: function handleCyclomediaButtonClick() {
this.updateCyclomediaRecordings();
},
handleCyclomediaRecordingClick: function handleCyclomediaRecordingClick(e) {
var latlng = e.latlng;
var viewer = this.$store.state.cyclomedia.viewer;
viewer.openByCoordinate([latlng.lng, latlng.lat]);
},
updateCyclomediaRecordings: function updateCyclomediaRecordings() {
var this$1 = this;
var map = this.$store.state.map.map;
var zoom = map.getZoom();
if (!this.$store.state.cyclomedia.active || zoom <= 18) {
this.$store.commit('setCyclomediaRecordings', []);
return;
}
var bounds = map.getBounds();
this.$cyclomediaRecordingsClient.getRecordings(
bounds,
function (recordings) {
this$1.$store.commit('setCyclomediaRecordings', recordings);
}
);
},
}
};
var pictometryMixin = {
computed: {
pictometryActive: function pictometryActive() {
return this.$store.state.pictometry.active;
}
}
};
// inspired by https://github.com/KoRiGaN/Vue2Leaflet/blob/master/src/utils/eventsBinder.js
function bindEvents(vue, leafletElement, events) {
// get just leaflet events
var leafletEvents = Object.keys(events)
.filter(function (eventName) {
return eventName.startsWith('l-');
})
.map(function (eventName) { return eventName.slice(2); });
var loop = function () {
var leafletEvent = list[i];
var vueEvent = 'l-' + leafletEvent;
leafletElement.on(leafletEvent, function (e) {
vue.$emit(vueEvent, e);
});
};
for (var i = 0, list = leafletEvents; i < list.length; i += 1) loop();
}
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .map-container { height: 100%; } .map { height: 100%; } @media (max-width: 749px) { .map { height: 300px; } } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Map_ = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"map-container"},[_c('div',{ref:"map",staticClass:"map"}),_vm._v(" "),_c('div',[_vm._t("default")],2)])},staticRenderFns: [],
props: [
'center',
'zoom',
'zoomControlPosition',
'minZoom',
'maxZoom' ],
watch: {
// markers(next, prev) {
// // get markers
// // fit bounds
// // const leafletMarkers = this.getMarkers();
// // console.log('watch markers fired', leafletMarkers);
// this.refit();
// }
center: function center(nextCenter) {
var this$1 = this;
// check for not-null coords
if (!nextCenter) { return; }
var lng = nextCenter[0];
var lat = nextCenter[1];
var latLng = new L$1.LatLng(lat, lng);
// we used "setView" here because when you refreshed the app with an address in the url,
// "panTo" was getting stepped on by "setZoom" and it was not happening
this.$nextTick(function () {
this$1.$leafletElement.setView(latLng, this$1.zoom);
});
},
zoom: function zoom(nextZoom) {
if (!nextZoom) { return; }
this.$leafletElement.setZoom(nextZoom);
}
},
mounted: function mounted() {
var this$1 = this;
var map = this.$leafletElement = this.createLeafletElement();
// move zoom control
map.zoomControl.setPosition(this.$props.zoomControlPosition);
// put in state
// REVIEW do we want to do this? is it serializable?
this.$store.commit('setMap', { map: map });
map.setView(this.center,
this.zoom);
this.$nextTick(function () {
map.attributionControl.setPrefix('<a target="_blank" href="//www.phila.gov/it/aboutus/units/Pages/GISServicesGroup.aspx">City of Philadelphia | CityGeo</a>');
});
// signal children to mount
for (var i = 0, list = this$1.$children; i < list.length; i += 1) {
// REVIEW it seems weird to pass children their own props. trying to
// remember why this was necessary... binding issue?
var child = list[i];
child.parentMounted(this$1, child.$props);
}
// bind events
// http://leafletjs.com/reference.html#map-click
// const MAP_EVENTS = [
// 'click',
// 'dblclick',
// 'mousedown',
// 'mouseup',
// 'mouseover',
// 'mouseout',
// 'mousemove',
// 'contextmenu',
// 'focus',
// 'blur',
// 'preclick',
// 'load',
// 'unload',
// 'viewreset',
// 'movestart',
// 'move',
// 'moveend',
// 'dragstart',
// 'drag',
// 'dragend',
// 'zoomstart',
// 'zoomend',
// 'zoomlevelschange',
// 'resize',
// 'autopanstart',
// 'layeradd',
// 'layerremove',
// 'baselayerchange',
// 'overlayadd',
// 'overlayremove',
// 'locationfound',
// 'locationerror',
// 'popupopen',
// 'popupclose'
// ];
// TODO warn if trying to bind an event that doesn't exist
bindEvents(this, this.$leafletElement, this._events);
},
// updated(next, prev) {
// const markers = this.getMarkers();
// if (markers.length === 0) return;
// const latlngs = markers.map(marker => marker.getLatLng());
// console.log('updated', markers);
// const latLngBounds = new LatLngBounds(latlngs);
// console.log('llb', latLngBounds);
// this.$leafletElement.fitBounds(latLngBounds);
// },
methods: {
createLeafletElement: function createLeafletElement() {
var ref = this.$props;
var zoomControlPosition = ref.zoomControlPosition;
var rest = {}; for (var n in ref) if(["zoomControlPosition"].indexOf(n) === -1) rest[n] = ref[n];
var options = rest;
return new L$1.Map(this.$refs.map, options);
},
childDidMount: function childDidMount(child) {
child.addTo(this.$leafletElement);
},
// getMarkers() {
// const children = this.$children;
// const MARKER_CLASSES = [
// '<Geojson>',
// '<VectorMarker>',
// ];
// const markers = children.filter(child => {
// const name = child._name;
// return MARKER_CLASSES.includes(name);
// });
// return markers.map(marker => marker.$leafletElement);
// },
// refit() {
// const markers = this.getMarkers();
// if (markers.length === 0) return;
// const latlngs = markers.map(marker => marker.getLatLng());
// console.log('updated', markers);
// const latLngBounds = new LatLngBounds(latlngs);
// console.log('llb', latLngBounds);
// this.$leafletElement.fitBounds(latLngBounds);
// }
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Control = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_vm._t("default")],2)},staticRenderFns: [],
props: ['position'],
methods: {
createLeafletElement: function createLeafletElement(L) {
// subclass Control to accept an el which gets mounted to the map
var ControlParent = (function (superclass) {
function ControlParent(el, options) {
superclass.call(this, options);
this.el = el;
}
if ( superclass ) ControlParent.__proto__ = superclass;
ControlParent.prototype = Object.create( superclass && superclass.prototype );
ControlParent.prototype.constructor = ControlParent;
ControlParent.prototype.onAdd = function onAdd () {
var el = this.el;
// keep clicks from hitting the map
L.DomEvent.disableClickPropagation(el);
return el;
};
return ControlParent;
}(L.Control));
var el = this.$el;
return new ControlParent(el, {
position: this.position
});
},
parentMounted: function parentMounted(parent, props) {
var leafletElement = this.createLeafletElement(L$1__default);
this.$leafletElement = leafletElement;
var map = parent.$leafletElement;
leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// TODO look into a cleaner way of importing from esri-leaflet
var EsriTiledMapLayer = L$1__default.esri.tiledMapLayer;
var EsriTiledMapLayer$1 = {
props: [
'url',
'minZoom',
'maxZoom',
'zIndex',
'attribution'
],
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
map.attributionControl.removeAttribution('overwrite');
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
var props = Object.assign({}, this.$props);
var mapLayer = new EsriTiledMapLayer(props);
return mapLayer;
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .opacity_slider_control .ui-slider-range { background-image: none; background-color: #646464; height: 200px; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// TODO look into a cleaner way of importing from esri-leaflet
// import Control from '../leaflet/Control';
//
// // REVIEW is there a better way to extend a vue component?
// const {props, methods} = Control;
var opacity_layer;
var OpacitySlider = {
props: [
'layer',
'position',
'initialOpacity'
],
created: function created() {
var opacityValue = this.$props.initialOpacity * 100;
// console.log("opacityValue", opacityValue);
L$1__default.Control.opacitySlider = L$1__default.Control.extend({
options: {
position: 'topright'
},
setOpacityLayer: function (layer) {
opacity_layer = layer;
},
onAdd: function (map) {
// console.log('on add', this, this.$props);
var opacity_slider_div = L$1__default.DomUtil.create('div', 'opacity_slider_control');
$(opacity_slider_div).slider({
orientation: "vertical",
range: "min",
min: 0,
max: 100,
value: opacityValue,
step: 10,
start: function ( event, ui) {
//When moving the slider, disable panning.
map.dragging.disable();
map.once('mousedown', function (e) {
map.dragging.enable();
});
},
slide: function ( event, ui ) {
var slider_value = ui.value / 100;
opacity_layer.setOpacity(slider_value);
}
});
$(opacity_slider_div).click(function(e) {
e.stopPropagation();
});
return opacity_slider_div;
}
});
},
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map.map);
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeControl(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
var OpacitySlider = new L$1__default.Control.opacitySlider;
OpacitySlider.setPosition(this.$props.position);
OpacitySlider.setOpacityLayer(this.$props.layer);
return OpacitySlider;
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
map.addControl(this.$leafletElement);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// TODO things in esri-leaflet should be standalone and not depend on
// mapboard components. pass this in as a prop/plugin rather than importing.
// TODO look into a cleaner way of importing from esri-leaflet
var EsriDynamicMapLayer = L$1__default.esri.dynamicMapLayer;
var EsriDynamicMapLayer$1 = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('opacity-slider',{attrs:{"layer":this.$leafletElement,"position":'topleft',"initialOpacity":_vm.opacity}})},staticRenderFns: [],
components: {
OpacitySlider: OpacitySlider
},
props: {
url: {
},
minZoom: {
},
maxZoom: {
},
zIndex: {
},
opacity: {
default: 1.0
},
layers: {
},
layerDefs: {
},
transparent: {
},
},
created: function created() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
// render(h) {
// return;
// },
computed: {
},
methods: {
createLeafletElement: function createLeafletElement() {
var props = Object.assign({}, this.$props);
return new EsriDynamicMapLayer(props);
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*# sourceMappingURL=FeatureLayer.vue.map */"; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// import OpacitySlider from '../leaflet/OpacitySlider';
// TODO look into a cleaner way of importing from esri-leaflet
var EsriFeatureLayer = L$1__default.esri.featureLayer;
// min and max zooms are not handled by esri leaflet, but are handled by vue
var EsriFeatureLayer$1 = {
props: [
'url',
'minZoom',
'maxZoom',
'zIndex',
'layerName',
'color',
'fillColor',
'fillOpacity',
'weight'
],
created: function created() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
var props = Object.assign({}, this.$props);
return new EsriFeatureLayer(props);
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// pascal case
var GeoJson = L$1.geoJSON;
var Geojson = {
props: [
'geojson',
'color',
'weight' ],
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
// if the geoJSON feature is a point, it needs to be styled through "pointToLayer"
// const type = this.$props.overlay.type;
// const style = this.$props.overlay.style;
return new GeoJson(this.$props.geojson, {
color: this.$props.color,
weight: this.$props.weight,
// pointToLayer: function (feature, latlng) {
// return type(latlng, style)
// }
});
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var CircleMarker$1 = {
props: [
'latlng',
'radius',
'fillColor',
'color',
'weight',
'opacity',
'fillOpacity',
'data'
],
// computed: {
// activeFeature() {
// return this.$store.state.activeFeature;
// }
// },
// watch: {
// activeFeature(nextActiveFeature) {
// console.log('watch', nextActiveFeature);
// this.bringCircleMarkerToFront();
// //console.log(this.circleMarkers);
// }
// },
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
if (map) {
leafletElement.addTo(map);
}
// bind events
// TODO warn if trying to bind an event that doesn't exist
bindEvents(this, this.$leafletElement, this._events);
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
var props = this.$props;
var latlng = props.latlng;
var rest = {}; for (var n in props) if(["latlng"].indexOf(n) === -1) rest[n] = props[n];
var options = rest;
var newCircleMarker = new L$1.CircleMarker(latlng, options);
//this.$store.commit('setCircleMarkers', newCircleMarker);
return newCircleMarker;
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
},
// bringCircleMarkerToFront() {
// // bringCircleMarkerToFront(circleMarker) {
// console.log('bringCircleMarkerToFront');
// // put marker on top
// // const el = circleMarker._path;
// //
// // // remove from parent
// // const group = circleMarker._renderer._rootGroup;
// // group.removeChild(el);
// //
// // // append to end (which brings it to the front)
// // group.appendChild(el);
// },
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var VectorMarker = {
props: [
'latlng',
'markerColor',
'icon'
],
data: function() {
return {
thelatlng: this.$props.latlng
}
},
render: function render(h) {
var a = this.$props.latlng;
return;
},
mounted: function mounted() {
// console.log('vectorMarker mounted fired, latlng is', this.latlng);
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
updated: function updated() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
methods: {
createLeafletElement: function createLeafletElement() {
var icon = L$1__default.VectorMarkers.icon({
icon: this.$props.icon || 'circle',
markerColor: this.$props.markerColor || '#2176d2'
});
return L$1__default.marker(this.latlng, { icon: icon });
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var PngMarker = {
props: [
'icon' ],
render: function render(h) {
// for some reason, the react prop that `this.orientation` depends on has
// to be evaluated once in order to receive updates.
this.orientation;
return;
},
mounted: function mounted() {
// console.log('pngMarker mounted fired, latlng is', this.latlng);
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
updated: function updated() {
// console.log('pngMarker updated fired, latlng is', this.latlng);
this.$leafletElement._map.removeLayer(this.$leafletElement);
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
//console.log('pngMarker destroyed fired, latlng is', this.latlng);
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
computed: {
latlng: function latlng() {
var xyz = this.orientation.xyz;
return [xyz[1], xyz[0]];
},
rotationAngle: function rotationAngle() {
return this.orientation.yaw * (180/3.14159265359);
},
orientation: function orientation() {
// access the orientation prop of the cyclomedia react component
return this.$store.state.cyclomedia.viewer.props.orientation;
}
},
methods: {
createLeafletElement: function createLeafletElement() {
var icon = L$1__default.icon({
iconUrl: this.icon,
iconSize: [26, 16],
iconAnchor: [11, 8],
});
return L$1__default.marker(this.latlng, {
icon: icon,
rotationAngle: this.rotationAngle,
});
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
},
}
};
// Based on:
// https://github.com/iatkin/leaflet-svgicon
// modified to support es6 imports
var SvgIcon = L.DivIcon.extend({
options: {
"circleText": "",
"className": "svg-icon",
"circleAnchor": null, //defaults to [iconSize.x/2, iconSize.x/2]
"circleColor": null, //defaults to color
"circleOpacity": null, // defaults to opacity
"circleFillColor": "rgb(255,255,255)",
"circleFillOpacity": null, //default to opacity
"circleRatio": 0.5,
"circleWeight": null, //defaults to weight
"color": "rgb(0,102,255)",
"fillColor": null, // defaults to color
"fillOpacity": 0.4,
"fontColor": "rgb(0, 0, 0)",
"fontOpacity": "1",
"fontSize": null, // defaults to iconSize.x/4
"iconAnchor": null, //defaults to [iconSize.x/2, iconSize.y] (point tip)
"iconSize": L.point(32,48),
"opacity": 1,
"popupAnchor": null,
"weight": 2
},
initialize: function(options) {
options = L.Util.setOptions(this, options);
if (!options.circleAnchor) {
options.circleAnchor = L.point(Number(options.iconSize.x)/2, Number(options.iconSize.x)/2);
}
if (!options.circleColor) {
options.circleColor = options.color;
}
if (!options.circleFillOpacity) {
options.circleFillOpacity = options.opacity;
}
if (!options.circleOpacity) {
options.circleOpacity = options.opacity;
}
if (!options.circleWeight) {
options.circleWeight = options.weight;
}
if (!options.fillColor) {
options.fillColor = options.color;
}
if (!options.fontSize) {
options.fontSize = Number(options.iconSize.x/4);
}
if (!options.iconAnchor) {
options.iconAnchor = L.point(Number(options.iconSize.x)/2, Number(options.iconSize.y));
}
if (!options.popupAnchor) {
options.popupAnchor = L.point(0, (-0.75)*(options.iconSize.y));
}
var path = this._createPath();
var circle = this._createCircle();
options.html = this._createSVG();
},
_createCircle: function() {
var cx = Number(this.options.circleAnchor.x);
var cy = Number(this.options.circleAnchor.y);
var radius = this.options.iconSize.x/2 * Number(this.options.circleRatio);
var fill = this.options.circleFillColor.replace("rgb(", "rgba(").replace(")", "," + this.options.circleFillOpacity + ")");
var stroke = this.options.circleColor.replace("rgb(", "rgba(").replace(")", "," + this.options.circleOpacity + ")");
var strokeWidth = this.options.circleWeight;
var className = this.options.className + "-circle";
var circle = '<circle class="' + className + '" cx="' + cx + '" cy="' + cy + '" r="' + radius + '" fill="' + fill + '" stroke="' + stroke + '" stroke-width="' + strokeWidth + '"/>';
return circle
},
_createPathDescription: function() {
var height = Number(this.options.iconSize.y);
var width = Number(this.options.iconSize.x);
var weight = Number(this.options.weight);
var margin = weight / 2;
var startPoint = "M " + margin + " " + (width/2) + " ";
var leftLine = "L " + (width/2) + " " + (height - weight) + " ";
var rightLine = "L " + (width - margin) + " " + (width/2) + " ";
var arc = "A " + (width/4) + " " + (width/4) + " 0 0 0 " + margin + " " + (width/2) + " Z";
var d = startPoint + leftLine + rightLine + arc;
return d
},
_createPath: function() {
var pathDescription = this._createPathDescription();
var strokeWidth = this.options.weight;
var stroke = this.options.color.replace("rgb(", "rgba(").replace(")", "," + this.options.opacity + ")");
var fill = this.options.fillColor.replace("rgb(", "rgba(").replace(")", "," + this.options.fillOpacity + ")");
var className = this.options.className + "-path";
var path = '<path class="' + className + '" d="' + pathDescription + '" stroke-width="' + strokeWidth + '" stroke="' + stroke + '" fill="' + fill + '"/>';
return path
},
_createSVG: function() {
var path = this._createPath();
var circle = this._createCircle();
var text = this._createText();
var className = this.options.className + "-svg";
var style = "width:" + this.options.iconSize.x + "; height:" + this.options.iconSize.y + ";";
var svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="' + className + '" style="' + style + '">' + path + circle + text + '</svg>';
return svg
},
_createText: function() {
var fontSize = this.options.fontSize + "px";
var lineHeight = Number(this.options.fontSize);
var x = Number(this.options.iconSize.x) / 2;
var y = x + (lineHeight * 0.35); //35% was found experimentally
var circleText = this.options.circleText;
var textColor = this.options.fontColor.replace("rgb(", "rgba(").replace(")", "," + this.options.fontOpacity + ")");
var text = '<text text-anchor="middle" x="' + x + '" y="' + y + '" style="font-size: ' + fontSize + '" fill="' + textColor + '">' + circleText + '</text>';
return text
}
});
// L.divIcon.svgIcon = function(options) {
// return new L.DivIcon.SVGIcon(options)
// }
// L.Marker.SVGMarker = L.Marker.extend({
// options: {
// "iconFactory": L.divIcon.svgIcon,
// "iconOptions": {}
// },
// initialize: function(latlng, options) {
// options = L.Util.setOptions(this, options)
// options.icon = options.iconFactory(options.iconOptions)
// this._latlng = latlng
// },
// onAdd: function(map) {
// L.Marker.prototype.onAdd.call(this, map)
// },
// setStyle: function(style) {
// if (this._icon) {
// var svg = this._icon.children[0]
// var iconBody = this._icon.children[0].children[0]
// var iconCircle = this._icon.children[0].children[1]
//
// if (style.color && !style.iconOptions) {
// var stroke = style.color.replace("rgb","rgba").replace(")", ","+this.options.icon.options.opacity+")")
// var fill = style.color.replace("rgb","rgba").replace(")", ","+this.options.icon.options.fillOpacity+")")
// iconBody.setAttribute("stroke", stroke)
// iconBody.setAttribute("fill", fill)
// iconCircle.setAttribute("stroke", stroke)
//
// this.options.icon.fillColor = fill
// this.options.icon.color = stroke
// this.options.icon.circleColor = stroke
// }
// if (style.opacity) {
// this.setOpacity(style.opacity)
// }
// if (style.iconOptions) {
// if (style.color) { style.iconOptions.color = style.color }
// iconOptions = L.Util.setOptions(this.options.icon, style.iconOptions)
// this.setIcon(L.divIcon.svgIcon(iconOptions))
// }
// }
// }
// })
//
// L.marker.svgMarker = function(latlng, options) {
// return new L.Marker.SVGMarker(latlng, options)
// }
// L.DivIcon.SVGIcon.noCircleIcon = L.DivIcon.SVGIcon.extend({
// initialize: function(options) {
// options = L.Util.setOptions(this, options)
// options.circleAnchor = L.point(Number(options.iconSize.x)/2, Number(options.iconSize.y)/2)
// options.circleRatio = 0;
// L.DivIcon.SVGIcon.prototype.initialize.call(this, options)
//
// return options
// },
// })
// L.divIcon.svgIcon.noCircleIcon = function(options) {
// return new L.DivIcon.SVGIcon.NoCircleIcon(options)
// }
// L.Marker.SVGMarker.NoCircleMarker = L.Marker.SVGMarker.extend({
// options: {
// "iconFactory": L.divIcon.svgIcon.NoCircleIcon
// }
// })
//
// L.marker.svgMarker.noCircleMarker = function(latlng, options) {
// return new L.Marker.SVGMarker.noCircleMarker(latlng, options)
// }
var TriangleIcon = SvgIcon.extend({
initialize: function(options) {
options = L$1__default.Util.setOptions(this, options);
var circleAnchor = L$1__default.point(Number(options.iconSize.x) / 2,
Number(options.iconSize.y) / 2);
options.circleAnchor = circleAnchor;
options.circleRatio = 0;
options.className = options.className + "-noClick";
SvgIcon.prototype.initialize.call(this, options);
return options;
},
_createPathDescription: function () {
var height = Number(this.options.iconSize.y);
var width = Number(this.options.iconSize.x);
var weight = Number(this.options.weight);
var margin = weight;
var startPoint = "M " + margin + " " + (0) + " ";
var leftLine = "L " + (width / 2) + " " + (height - margin) + " ";
var rightLine = "L " + (width - margin) + " " + (0) + " Z";
var d = startPoint + leftLine + rightLine;
return d;
}
});
// L.divIcon.svgIcon.triangleIcon = function(options) {
// return new L.DivIcon.SVGIcon.TriangleIcon(options)
// }
// L.Marker.SVGMarker.TriangleMarker = L.Marker.SVGMarker.extend({
// options: {
// "iconFactory": L.divIcon.svgIcon.triangleIcon
// }
// })
//
// L.marker.svgMarker.triangleMarker = function(latlng, options) {
// return new L.Marker.SVGMarker.TriangleMarker(latlng, options)
// }
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .svg-icon-noClick-svg { pointer-events: none; } .svg-icon-noClick { pointer-events: none; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// import DivIcon from 'leaflet';
var SvgMarker = {
// props: [
// 'orientation'
// ],
render: function render(h) {
this.orientation;
return;
},
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
// console.log('WHO IT IS', leafletElement);
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
updated: function updated() {
// console.log('svgMarker updated fired, latlng is', this.latlng);
this.$leafletElement._map.removeLayer(this.$leafletElement);
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
// REVIEW kind of hacky/not reactive?
if (map) {
leafletElement.addTo(map);
}
},
destroyed: function destroyed() {
// console.log('svgMarker destroyed fired, latlng is', this.latlng);
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
computed: {
latlng: function latlng() {
var xyz = this.orientation.xyz;
return [xyz[1], xyz[0]];
},
rotationAngle: function rotationAngle() {
return this.orientation.yaw * (180/3.14159265359);
},
coneCoords: function coneCoords() {
var hFov = this.orientation.hFov * (180/3.14159265359);
var scale = 50;//options.scale;
var angle = hFov / 2.0;
var width = Math.sin(angle * Math.PI / 180);
var length = Math.sqrt(1.0 - width * width);
var coneCoords = [width * scale, length * scale];
return coneCoords;
},
orientation: function orientation() {
return this.$store.state.cyclomedia.viewer.props.orientation;
},
},
methods: {
createLeafletElement: function createLeafletElement() {
var coneCoords = this.coneCoords;
var icon = new TriangleIcon({
iconSize: L$1__default.point(this.coneCoords[0], this.coneCoords[1]),
iconAnchor: [this.coneCoords[0] / 2, this.coneCoords[1]],
});
return L$1__default.marker(this.latlng, {
icon: icon,
rotationAngle: this.rotationAngle,
});
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .button-image[data-v-24c2c164] { vertical-align: top; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var methods = Control.methods;
var BasemapToggleControl = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"leaflet-bar easy-button-container leaflet-control"},[_c('button',{on:{"click":_vm.handleImageryToggleButtonClick}},[_c('span',{staticClass:"button-state state-unnamed-state unnamed-state-active"},[_c('img',{staticClass:"button-image",attrs:{"src":_vm.toggleButtonImgSrc}})])])])},staticRenderFns: [],_scopeId: 'data-v-24c2c164',
props: [
'position'
],
computed: {
toggleButtonImgSrc: function toggleButtonImgSrc() {
var shouldShowImagery = this.$store.state.map.shouldShowImagery;
var src;
if (shouldShowImagery) {
src = "../../src/assets/basemap_small.png";
}
else {
src = "../../src/assets/imagery_small.png";
}
return src;
},
},
methods: Object.assign(methods, {
handleImageryToggleButtonClick: function handleImageryToggleButtonClick(e) {
var prevShouldShowImagery = this.$store.state.map.shouldShowImagery;
var nextShouldShowImagery = !prevShouldShowImagery;
this.$store.commit('setShouldShowImagery', nextShouldShowImagery);
},
})
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*# sourceMappingURL=BasemapSelectControl.vue.map */"; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var methods$1 = Control.methods;
var BasemapSelectControl = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.shouldShowImagery),expression:"shouldShowImagery"}]},[_c('select',{attrs:{"id":"year-select"},on:{"change":_vm.handleImageryChange}},_vm._l((_vm.imageryTypes),function(imageryTypeDef,imageryType){return _c('optgroup',{attrs:{"label":imageryTypeDef.label}},_vm._l((_vm.basemapsForImageryType(imageryType)),function(basemap){return _c('option',{attrs:{"data-key":basemap.key}},[_vm._v(" "+_vm._s(basemap.label)+" ")])}))}))])},staticRenderFns: [],_scopeId: 'data-v-48c5e6b4',
props: [
'position' ],
computed: {
shouldShowImagery: function shouldShowImagery() {
return this.$store.state.map.shouldShowImagery;
},
imageryTypes: function imageryTypes() {
return this.$config.map.imageryTypes;
}
},
methods: Object.assign(methods$1, {
handleImageryChange: function handleImageryChange() {
var el = document.getElementById('year-select');
var group = el.options[el.selectedIndex].parentElement.label;
var year = el.options[el.selectedIndex].value;
var nextBasemap = group.toLowerCase() + year;
this.$store.commit('setImagery', nextBasemap);
},
// returns keys of basemaps of a certain type (e.g. historic, imagery)
basemapsForImageryType: function basemapsForImageryType(targetType) {
var basemapConfig = this.$config.map.basemaps;
var basemapKeys = Object.keys(basemapConfig);
var basemaps = [];
for (var i = 0, list = basemapKeys; i < list.length; i += 1) {
var basemapKey = list[i];
var basemapDef = basemapConfig[basemapKey];
var basemapType = basemapDef.type;
if (basemapType === targetType) {
var basemapLabel = basemapDef.label;
basemaps.push({
type: basemapType,
label: basemapLabel
});
}
}
return basemaps;
}
})
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .fa-lg[data-v-15e73008] { vertical-align: -10%; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var methods$2 = Control.methods;
var LocationControl = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"leaflet-bar easy-button-container leaflet-control"},[_c('button',{on:{"click":_vm.handleLocationButtonClick}},[_vm._m(0)])])},staticRenderFns: [function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('span',{staticClass:"button-state state-unnamed-state unnamed-state-active"},[_c('i',{staticClass:"fa fa-dot-circle-o fa-lg",attrs:{"aria-hidden":"true"}})])}],_scopeId: 'data-v-15e73008',
props: [
'position'
],
methods: Object.assign(methods$2, {
handleLocationButtonClick: function handleLocationButtonClick(e) {
var watchPositionOn = this.$store.state.map.watchPositionOn;
// console.log('watchPositionOn', watchPositionOn);
if (!watchPositionOn) {
this.$store.commit('setWatchPositionOn', true);
navigator.geolocation.watchPosition(this.geofindSuccess, this.geofindError, {enableHighAccuracy: true, timeout: 1000, maximumAge: 0, distanceFilter: 5});
} else {
this.moveToPosition();
}
},
geofindSuccess: function geofindSuccess(position) {
// alert('geofindSuccess is running, position:', position);
var payload = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
this.$store.commit('setLocation', payload);
// console.log('latitude', payload.lat, 'longitude', payload.lng);
this.moveToPosition();
},
moveToPosition: function moveToPosition() {
// console.log('moveToPosition is running');
var map = this.$store.state.map.map;
var location = this.$store.state.map.location;
map.setView([location.lat, location.lng], 19);
},
geofindError: function geofindError() {
console.log('GeofindError');
}
})
};
var RecordingsClient = function RecordingsClient(baseUrl, username, password, srid, proxy) {
if ( srid === void 0 ) srid = 3857;
this.baseUrl = baseUrl;
this.username = username;
this.password = password;
this.srid = srid;
this.proxy = proxy;
};
// this takes leaflet map bonds and an EPSG coordinate system id, e.g. 3857
// and returns an array of cyclomedia recording points
RecordingsClient.prototype.getRecordings = function getRecordings (bounds, callback) {
// console.log('get recordings', bounds);
var swCoord = bounds.getSouthWest();
var neCoord = bounds.getNorthEast();
var data = "<wfs:GetFeature service=\"WFS\" version=\"1.1.0\" resultType=\"results\" outputFormat=\"text/xml; subtype=gml/3.1.1\" xmlns:wfs=\"http://www.opengis.net/wfs\">\n\t\t\t\t\t\t\t\t\t\t\t<wfs:Query typeName=\"atlas:Recording\" srsName=\"EPSG:" + (this.srid) + "\" xmlns:atlas=\"http://www.cyclomedia.com/atlas\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\">\n\t\t\t\t\t\t \t\t\t\t\t<ogc:And>\n\t\t\t\t\t\t \t\t\t\t\t<ogc:BBOX>\n\t\t\t\t\t\t\t\t\t\t\t <gml:Envelope srsName=\"EPSG:" + (this.srid) + "\" xmlns:gml=\"http://www.opengis.net/gml\">\n\t\t\t\t\t\t\t\t\t\t\t <gml:lowerCorner>" + (swCoord.lng) + " " + (swCoord.lat) + "</gml:lowerCorner>\n\t\t\t\t\t\t\t\t\t\t\t <gml:upperCorner>" + (neCoord.lng) + " " + (neCoord.lat) + "</gml:upperCorner>\n\t\t\t\t\t\t\t\t\t\t\t </gml:Envelope>\n\t\t\t\t\t\t\t\t\t\t\t </ogc:BBOX>\n\t\t\t\t\t\t\t\t\t\t\t <ogc:PropertyIsNull>\n\t\t\t\t\t\t\t\t\t\t\t <ogc:PropertyName>expiredAt</ogc:PropertyName>\n\t\t\t\t\t\t\t\t\t\t\t </ogc:PropertyIsNull>\n\t\t\t\t\t\t\t\t\t\t\t </ogc:And>\n\t\t\t\t\t\t\t\t\t\t\t </ogc:Filter>\n\t\t\t\t\t\t\t\t\t\t\t </wfs:Query>\n\t\t\t\t\t\t\t\t\t\t\t</wfs:GetFeature>";
var url = (this.proxy || '') + this.baseUrl;
// TEMP
// const url = ((this.proxy || '') + this.baseUrl).replace('//', 'https://');
$$1.ajax({
url: url,
data: data,
type: 'POST',
contentType: 'text/xml',
// dataType: 'text',
headers: {
// 'Content-length': data.length,
'Authorization': 'Basic ' + window.btoa(this.username + ':' + this.password)
},
success: function success(data) {
console.log('got recordings', data);
// const data = response.data
// this is a list of xml elements representing recordings
var recordingElsCollection = data.getElementsByTagNameNS('*', 'Recording');
var recordingEls = [].slice.call(recordingElsCollection);
// check for > 1
if (recordingEls.length < 1) {
console.log('no cyclomedia recordings for bounds');
return;
}
// check if authorized
// const firstRecordingEl = recordingEls[0];
// const isAuthorizedEls = firstRecordingEl.firstChild.getElementsByTagNameNS('*', 'isAuthorized');
// const isAuthorized = isAuthorizedEls.length > 0 && isAuthorizedEls[0].firstChild.data === 'true';
// if (!isAuthorized) {
// throw 'not authorized to get cyclomedia recordings';
// return;
// }
var recordings = recordingEls.map(function (recordingEl) {
var imageId = recordingEl.getElementsByTagNameNS('*', 'imageId')[0].firstChild.data;
var coords = recordingEl.getElementsByTagNameNS('*', 'pos')[0].firstChild.data;
var ref = coords.split(' ').map(parseFloat);
var lng = ref[0];
var lat = ref[1];
return {
imageId: imageId,
lng: lng,
lat: lat
};
});
callback(recordings);
// }, response => {
// console.log('AXIOS ERROR recordings-client.js')
},
error: function error(xhr, ajaxOptions, thrownError) {
console.log(xhr.status);
console.log(thrownError);
}
});
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .inactive[data-v-461b7da4] { background-color: #ffffff; } .inactive[data-v-461b7da4]:hover { background-color: #ffffff; } .active[data-v-461b7da4] { background-color: rgb(243, 198, 19); } .active[data-v-461b7da4]:hover { background-color: rgb(243, 198, 19); } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var CyclomediaButton = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"leaflet-bar easy-button-container leaflet-control"},[_c('button',{class:this.cyclomediaActive,on:{"click":function($event){$event.preventDefault();_vm.handleButtonClick($event);}}},[_c('span',{staticClass:"button-state"},[_c('img',{staticClass:"button-image",attrs:{"src":_vm.imgSrc}})])])])},staticRenderFns: [],_scopeId: 'data-v-461b7da4',
extends: Control,
// TODO figure how to extend props. sometimes it's an obj, sometimes an array.
// props: Object.assign(props, {
// }),
props: [
'link',
'imgSrc'
],
created: function created() {
// create cyclomedia recordings client
this.$cyclomediaRecordingsClient = new RecordingsClient(
this.$config.cyclomedia.recordingsUrl,
this.$config.cyclomedia.username,
this.$config.cyclomedia.password,
4326
);
},
computed: {
cyclomediaActive: function cyclomediaActive() {
return this.$store.state.cyclomedia.active ? 'active' : 'inactive'
}
},
methods: {
handleButtonClick: function handleButtonClick(e) {
var willBeActive = !this.$store.state.cyclomedia.active;
this.$store.commit('setCyclomediaActive', willBeActive);
// if the cyclo viewer is off screen when it loads imagery, it won't
// show anything even once it's on screen. use this to trigger an
// update.
var viewer = this.$store.state.cyclomedia.viewer;
if (willBeActive && viewer) {
this.$nextTick(function () {
viewer.forceUpdate();
});
}
this.$emit('click');
},
// setNewLocation(latlng) {
// const viewer = this.$store.state.cyclomedia.viewer;
// const xy = [latlng.lng, latlng.lat];
// viewer.openByCoordinate(xy);
// },
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .inactive[data-v-651e14cc] { background-color: #ffffff; } .inactive[data-v-651e14cc]:hover { background-color: #ffffff; } .active[data-v-651e14cc] { background-color: rgb(243, 198, 19); } .active[data-v-651e14cc]:hover { background-color: rgb(243, 198, 19); } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var PictometryButton = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"leaflet-bar easy-button-container leaflet-control"},[_c('button',{class:this.pictometryActive,on:{"click":function($event){$event.preventDefault();_vm.handleButtonClick($event);}}},[_c('span',{staticClass:"button-state"},[_c('img',{staticClass:"button-image",attrs:{"src":_vm.imgSrc}})])])])},staticRenderFns: [],_scopeId: 'data-v-651e14cc',
extends: Control,
// TODO figure how to extend props. sometimes it's an obj, sometimes an array.
// props: Object.assign(props, {
// }),
props: [
'link',
'imgSrc'
],
computed: {
pictometryActive: function pictometryActive() {
return this.$store.state.pictometry.active ? 'active' : 'inactive'
}
},
methods: {
handleButtonClick: function handleButtonClick(e) {
this.$store.commit('setPictometryActive', !this.$store.state.pictometry.active);
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Circle$1 = {
props: [
'latlng',
'size',
'color',
'weight'
],
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
var map = this.$store.state.map.map;
if (map) {
leafletElement.addTo(map);
}
// bind events
// const CIRCLE_EVENTS = [
// 'click',
// 'dblclick',
// 'mousedown',
// 'mouseover',
// 'mouseout',
// 'contextmenu'
// ];
// TODO warn if trying to bind an event that doesn't exist
bindEvents(this, this.$leafletElement, this._events);
},
destroyed: function destroyed() {
this.$leafletElement._map.removeLayer(this.$leafletElement);
},
// we don't actually render anything, but need to define either a template
// or a render function
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
return new L$1.Circle(this.latlng, this.size, {
color: this.color,
weight: this.weight
});
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
this.$leafletElement.addTo(map);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var CyclomediaRecordingCircle = {
mixins: [Circle$1],
props: ['imageId']
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*# sourceMappingURL=MeasureControl.vue.map */"; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var MeasureControl = {
props: ['position'],
mounted: function mounted() {
var leafletElement = this.$leafletElement = this.createLeafletElement();
},
destroyed: function destroyed() {
this.$leafletElement._map.removeControl(this.$leafletElement);
},
render: function render(h) {
return;
},
methods: {
createLeafletElement: function createLeafletElement() {
var MeasureTool = new L$1__default.Control.Measure({
position: this.$props.position,
primaryLengthUnit: 'feet',
primaryAreaUnit: 'sqfeet',
});
return MeasureTool;
},
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
map.addControl(this.$leafletElement);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .legend { display: inline-block; padding: 6px 8px; font: 14px/16px Arial, Helvetica, sans-serif; background: white; background: rgba(255,255,255,1); box-shadow: 0 0 15px rgba(0,0,0,0.2); border-radius: 5px; line-height: 18px; color: #555; } .legend-box { display: inline-block; width: 18px; height: 18px; opacity: 1; vertical-align: middle; margin-right: 4px; } .list-text { display: inline-block; vertical-align: middle; } .legend-list { list-style: none; padding-top: 2px; padding-left: 2px; margin-left: 0px; /*override standards*/ margin-bottom: 0; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var methods$3 = Control.methods;
var LegendControl = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{directives:[{name:"show",rawName:"v-show",value:(this.shouldShowLegend),expression:"this.shouldShowLegend"}]},[_c('div',{staticClass:"legend"},[_c('ul',{staticClass:"legend-list"},_vm._l((this.keys),function(key){return _c('li',{staticClass:"legend-listitem",style:("font-size:"+_vm.items[key]["font-size"]+";")},[_c('div',{staticClass:"legend-box",style:("background-color:"+_vm.items[key]["background-color"]+
"; border-color:"+_vm.items[key]["border-color"]+
"; border-style:"+_vm.items[key]["border-style"]+
"; border-width:"+_vm.items[key]["border-weight"]+
"; width:"+_vm.items[key].width+
"; height:"+_vm.items[key].height+";")}),_vm._v(" "),_c('div',{staticClass:"list-text"},[_vm._v(" "+_vm._s(key)+" ")])])}))])])},staticRenderFns: [],
props: [
'position',
'options',
'items'
],
computed: {
keys: function keys() {
return Object.keys(this.$props.items);
},
activeTopic: function activeTopic() {
return this.$store.state.activeTopic;
},
shouldShowImagery: function shouldShowImagery() {
return this.$store.state.map.shouldShowImagery;
},
shouldShowLegend: function shouldShowLegend() {
var result = true;
if (!this.$props.options.topics.includes(this.activeTopic)) {
result = false;
}
if (this.$props.options.showWithBaseMapOnly) {
if (this.shouldShowImagery) {
result = false;
}
}
return result;
}
// style() {
// // const string = "background: " + this.$props.items[key].background + " color: " + this.$props.items[key].color
// const string = this.$props.items[]
// console.log('style string', string);
// return string
// }
},
methods: Object.assign(methods$3)
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .basetooltip { width: 32px; height: 32px; padding: 5px 13px; font: 20px/22px Arial, Helvetica, sans-serif; background: white; background: rgba(255,255,255,1); box-shadow: 0 0 15px rgba(0,0,0,0.2); border-radius: 5px; } .basetooltip2 { float: right; width: 80%; height: 32px; padding: 3px 10px; padding-right: 40px; font: 12px/14px Arial, Helvetica, sans-serif; background: white; background: rgba(255,255,255,1); box-shadow: 0 0 15px rgba(0,0,0,0.2); border-radius: 5px; } .basetooltip a { color: black } .basetooltip2 a { color: black } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var methods$4 = Control.methods;
var BasemapTooltip = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('div',{class:this.basemap === 'none' ? 'basetooltip': 'basetooltip2',on:{"mouseover":_vm.onMouseover,"mouseout":_vm.onMouseout}},[(this.basemap === 'pwd')?_c('div',[_vm._v(" The property boundaries displayed on the map are for reference only and may not be used in place of recorded deeds or land surveys. Boundaries are generalized for ease of visualization. Source: Philadelphia Water ")]):(this.basemap === 'dor')?_c('div',[_vm._v(" The property boundaries displayed on the map are for reference only and may not be used in place of recorded deeds or land surveys. Dimension lengths are calculated using the GIS feature. Source: Department of Records. ")]):_c('div',[_vm._v(" i ")])])])},staticRenderFns: [],
props: [
'position' ],
data: function data() {
return {
'basemap': 'none'
}
},
computed: {
activeBasemap: function activeBasemap() {
return this.$store.state.map.basemap;
},
activeTopic: function activeTopic() {
return this.$store.state.activeTopic;
}
},
methods: Object.assign(methods$4, {
onMouseover: function onMouseover() {
var stateBasemap = this.activeBasemap;
var finalBasemap = stateBasemap;
if (stateBasemap.includes('imagery') || stateBasemap.includes('historic')) {
if (this.activeTopic === 'deeds' || this.activeTopic === 'zoning') {
finalBasemap = 'dor';
} else {
finalBasemap = 'pwd';
}
}
this.basemap = finalBasemap;
},
onMouseout: function onMouseout() {
this.basemap = 'none';
}
})
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .leaflet-almostleft { position: absolute; bottom: 0px; /* possible because the placeholder's parent is the map */ /*transform: translateY(-50%); /* using the CSS3 Transform technique */ /*padding-top: 10px;*/ left: 60px; padding-bottom: 10px; z-index: 500; } .leaflet-almostleft .leaflet-control { margin-bottom: 0px; } .leaflet-almostright { position: absolute; top: 0px; /* possible because the placeholder's parent is the map */ /*transform: translateY(-50%); /* using the CSS3 Transform technique */ /*padding-top: 10px;*/ right: 60px; padding-bottom: 10px; z-index: 500; } .leaflet-almostright .leaflet-control { margin-top: 10px; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var ControlCorner = {
props: [
'vSide',
'hSide'
],
render: function render(h) {
return;
},
methods: {
parentMounted: function parentMounted(parent) {
var map = parent.$leafletElement;
map._controlCorners[this.vSide + this.hSide] = L$1__default.DomUtil.create('div', 'leaflet-'+this.vSide+' leaflet-'+this.hSide, map._controlContainer);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" .mb-panel-map[data-v-1a846501] { /*this allows the loading mask to fill the div*/ position: relative; } /*@media (max-width: 749px) { .mb-panel-map { height: 600px; } }*/ .mb-search-control-container[data-v-1a846501] { height: 48px; border-radius: 2px; box-shadow:0 2px 4px rgba(0,0,0,0.2),0 -1px 0px rgba(0,0,0,0.02); } .mb-search-control-button[data-v-1a846501] { color: #fff; width: 50px; background: #2176d2; line-height: 48px; } .mb-search-control-input[data-v-1a846501] { border: 0; /*height: 48px !important;*/ /*line-height: 48px;*/ padding: 15px; /*padding-left: 15px; padding-right: 15px;*/ font-family: 'Montserrat', 'Tahoma', sans-serif; font-size: 16px; width: 275px; } .mb-map-with-widget[data-v-1a846501] { height: 50%; } .widget-slot[data-v-1a846501] { display: inline-block; float: left; } .mb-map-loading-mask[data-v-1a846501] { /*display: inline;*/ position: absolute; top: 0; height: 100%; width: 100%; background: rgba(0, 0 ,0 , 0.25); z-index: 1000; text-align: center; vertical-align: middle; } .mb-map-loading-mask-inner[data-v-1a846501] { position: absolute; top: 40%; left: 40%; } /*small*/ @media screen and (max-width: 39.9375em) { .mb-search-control-input[data-v-1a846501] { width: 200px; } } /*small retina*/ /*@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi), (max-width: 39.9375em) { .mb-search-control-input { max-width: 250px; } }*/ "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
// mixins
// vue doesn't like it when you import this as Map (reserved-ish word)
var MapPanel = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"medium-12 small-order-1 small-24 medium-order-2 mb-panel mb-panel-map"},[_c('map_',{class:{ 'mb-map-with-widget': this.$store.state.cyclomedia.active || this.$store.state.pictometry.active },attrs:{"center":this.$store.state.map.center,"zoom":this.$store.state.map.zoom,"zoom-control-position":"bottomright","min-zoom":this.$config.map.minZoom,"max-zoom":this.$config.map.maxZoom},on:{"l-click":_vm.handleMapClick,"l-moveend":_vm.handleMapMove}},[_c('div',{directives:[{name:"show",rawName:"v-show",value:(_vm.isGeocoding),expression:"isGeocoding"}],staticClass:"mb-map-loading-mask"},[_c('div',{staticClass:"mb-map-loading-mask-inner"},[_c('i',{staticClass:"fa fa-spinner fa-4x spin"}),_vm._v(" "),_c('h1',[_vm._v("Finding address...")])])]),_vm._v(" "),_vm._l((this.$config.map.basemaps),function(basemap,key){return (_vm.activeBasemap === key)?_c('esri-tiled-map-layer',{key:key,attrs:{"url":basemap.url,"max-zoom":basemap.maxZoom,"attribution":basemap.attribution}}):_vm._e()}),_vm._v(" "),_vm._l((this.$config.map.tiledLayers),function(tiledLayer,key){return (_vm.tiledLayers.includes(key))?_c('esri-tiled-map-layer',{key:key,attrs:{"url":tiledLayer.url,"zIndex":tiledLayer.zIndex,"attribution":tiledLayer.attribution}}):_vm._e()}),_vm._v(" "),_vm._l((this.$config.map.dynamicMapLayers),function(dynamicLayer,key){return (_vm.activeDynamicMaps.includes(key))?_c('esri-dynamic-map-layer',{key:key,attrs:{"url":dynamicLayer.url,"attribution":dynamicLayer.attribution,"transparent":true,"opacity":dynamicLayer.opacity}}):_vm._e()}),_vm._v(" "),_vm._l((this.$config.map.featureLayers),function(featureLayer,key){return (_vm.shouldShowFeatureLayer(key, featureLayer.minZoom))?_c('esri-feature-layer',{key:key,attrs:{"layerName":key,"url":featureLayer.url,"color":featureLayer.color,"fillColor":featureLayer.color,"fillOpacity":featureLayer.fillOpacity,"weight":featureLayer.weight}}):_vm._e()}),_vm._v(" "),_vm._l((this.imageOverlayItems),function(item,key){return (_vm.shouldShowImageOverlay(item.properties.RECMAP))?_c('esri-dynamic-map-layer',{key:key,attrs:{"url":'//gis.phila.gov/arcgis/rest/services/DOR_ParcelExplorer/rtt_basemap/MapServer/',"layers":[29],"layerDefs":'29:NAME=\'g' + item.properties.RECMAP.toLowerCase() + '.tif\'',"transparent":true,"opacity":0.5}}):_vm._e()}),_vm._v(" "),_vm._l((_vm.markers),function(marker,index){return _c('vector-marker',{key:marker.key,attrs:{"latlng":marker.latlng}})}),_vm._v(" "),(this.cyclomediaActive)?_c('png-marker',{attrs:{"icon":'../../src/assets/camera.png'}}):_vm._e(),_vm._v(" "),(this.cyclomediaActive)?_c('svg-marker'):_vm._e(),_vm._v(" "),_vm._l((_vm.geojsonFeatures),function(geojsonFeature){return (_vm.shouldShowGeojson(geojsonFeature.key))?_c('geojson',{key:geojsonFeature.key,attrs:{"geojson":geojsonFeature.geojson,"color":geojsonFeature.color,"weight":2}}):_vm._e()}),_vm._v(" "),(this.$store.state.map.location.lat != null)?_c('circle-marker',{key:Math.random(),attrs:{"latlng":this.locationMarker.latlng,"radius":this.locationMarker.radius,"fillColor":this.locationMarker.fillColor,"color":this.locationMarker.color,"weight":this.locationMarker.weight,"opacity":this.locationMarker.opacity,"fillOpacity":this.locationMarker.fillOpacity}}):_vm._e(),_vm._v(" "),_vm._l((_vm.circleMarkers),function(circleMarker){return _c('circle-marker',{key:Math.random(),attrs:{"latlng":circleMarker.latlng,"radius":circleMarker.radius,"fillColor":circleMarker.fillColor,"color":circleMarker.color,"weight":circleMarker.weight,"opacity":circleMarker.opacity,"fillOpacity":circleMarker.fillOpacity,"data":{
featureId: circleMarker.featureId,
tableId: circleMarker.tableId
}},on:{"l-mouseover":_vm.handleCircleMarkerMouseover,"l-click":_vm.handleCircleMarkerClick,"l-mouseout":_vm.handleCircleMarkerMouseout}})}),_vm._v(" "),_c('control-corner',{attrs:{"vSide":'top',"hSide":'almostright'}}),_vm._v(" "),_vm._m(1),_vm._v(" "),_vm._m(2),_vm._v(" "),_vm._m(4),_vm._v(" "),_vm._m(6),_vm._v(" "),_vm._m(7),_vm._v(" "),_vm._m(8),_vm._v(" "),_vm._m(10),_vm._v(" "),_vm._m(11),_vm._v(" "),_vm._l((_vm.cyclomediaRecordings),function(recording){return (_vm.cyclomediaActive)?_c('cyclomedia-recording-circle',{key:recording.imageId,attrs:{"imageId":recording.imageId,"latlng":[recording.lat, recording.lng],"size":1.2,"color":'#3388ff',"weight":1},on:{"l-click":_vm.handleCyclomediaRecordingClick}}):_vm._e()})],2),_vm._v(" "),_vm._t("cycloWidget"),_vm._v(" "),_vm._t("pictWidget")],2)},staticRenderFns: [function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('basemap-toggle-control',{attrs:{"position":'topright'}})},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(_vm.shouldShowImageryToggle)?_vm._m(0):_vm._e()],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('basemap-select-control',{attrs:{"position":'topalmostright'}})],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('pictometry-button',{attrs:{"position":'topright',"link":'pictometry',"imgSrc":'../../src/assets/pictometry.png'}})},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(this.$config.pictometry.enabled)?_vm._m(3):_vm._e()],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('cyclomedia-button',{attrs:{"position":'topright',"link":'cyclomedia',"imgSrc":'../../src/assets/cyclomedia.png'},on:{"click":_vm.handleCyclomediaButtonClick}})},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(this.$config.cyclomedia.enabled)?_vm._m(5):_vm._e()],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('measure-control',{attrs:{"position":'bottomleft'}})],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',_vm._l((Object.keys(_vm.legendControls)),function(legendControl){return _c('legend-control',{key:legendControl,attrs:{"position":'bottomleft',"options":_vm.legendControls[legendControl].options,"items":_vm.legendControls[legendControl].data}})}))},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('location-control',{attrs:{"position":'bottomright'}})},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[(this.geolocationEnabled)?_vm._m(9):_vm._e()],1)},function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',[_c('control',{attrs:{"position":"topleft"}},[_c('div',{staticClass:"mb-search-control-container"},[_c('form',{on:{"submit":function($event){$event.preventDefault();_vm.handleSearchFormSubmit($event);}}},[_c('input',{staticClass:"mb-search-control-input",attrs:{"placeholder":"Search the map"},domProps:{"value":this.$config.defaultAddress}}),_vm._v(" "),_c('button',{staticClass:"mb-search-control-button"},[_c('i',{staticClass:"fa fa-search fa-lg"})])])])])],1)}],_scopeId: 'data-v-1a846501',
mixins: [
markersMixin,
cyclomediaMixin,
pictometryMixin ],
components: {
Map_: Map_,
Control: Control,
EsriTiledMapLayer: EsriTiledMapLayer$1,
EsriDynamicMapLayer: EsriDynamicMapLayer$1,
EsriFeatureLayer: EsriFeatureLayer$1,
Geojson: Geojson,
CircleMarker: CircleMarker$1,
OpacitySlider: OpacitySlider,
VectorMarker: VectorMarker,
PngMarker: PngMarker,
SvgMarker: SvgMarker,
BasemapToggleControl: BasemapToggleControl,
BasemapSelectControl: BasemapSelectControl,
LocationControl: LocationControl,
PictometryButton: PictometryButton,
CyclomediaButton: CyclomediaButton,
CyclomediaRecordingCircle: CyclomediaRecordingCircle,
MeasureControl: MeasureControl,
LegendControl: LegendControl,
BasemapTooltip: BasemapTooltip,
ControlCorner: ControlCorner,
},
created: function created() {
// if there's a default address, navigate to it
var defaultAddress = this.$config.defaultAddress;
if (defaultAddress) {
this.$controller.goToDefaultAddress(defaultAddress);
}
var cyclomediaConfig = this.$config.cyclomedia || {};
if (cyclomediaConfig.enabled) {
// create cyclomedia recordings client
this.$cyclomediaRecordingsClient = new RecordingsClient(
this.$config.cyclomedia.recordingsUrl,
this.$config.cyclomedia.username,
this.$config.cyclomedia.password,
4326
);
}
},
mounted: function mounted() {
// this.geofind();
this.$controller.appDidLoad();
},
computed: {
isMobileOrTablet: function isMobileOrTablet() {
return this.$store.state.is_mobile_or_tablet;
},
geolocationEnabled: function geolocationEnabled() {
return this.$config.geolocation.enabled;
},
activeDorParcel: function activeDorParcel() {
// return this.$store.state.activeDorParcel;
return this.$store.state.parcels.dor.activeParcel;
},
legendControls: function legendControls() {
return this.$config.legendControls;
},
imageOverlay: function imageOverlay() {
return this.$store.state.map.imageOverlay;
},
imageOverlayItems: function imageOverlayItems() {
// console.log('calculating imageOverlayItem');
if (this.activeTopicConfig.imageOverlayGroup) {
var overlayGroup = this.activeTopicConfig.imageOverlayGroup;
var state = this.$store.state;
var overlay = this.$config.imageOverlayGroups[overlayGroup].items(state);
// console.log('returning imageOverlayItem', overlay);
return overlay;
} else {
return [];
}
},
imageOverlayInfo: function imageOverlayInfo() {
console.log('config:', this.$config);
return this.$config.map.dynamicMapLayers.regmaps;
},
activeBasemap: function activeBasemap() {
var shouldShowImagery = this.$store.state.map.shouldShowImagery;
if (shouldShowImagery) {
return this.$store.state.map.imagery;
}
var defaultBasemap = this.$config.map.defaultBasemap;
var basemap = this.$store.state.map.basemap || defaultBasemap;
return basemap;
},
tiledLayers: function tiledLayers() {
var activeBasemap = this.activeBasemap;
var activeBasemapConfig = this.configForBasemap(activeBasemap);
return activeBasemapConfig.tiledLayers || [];
},
activeDynamicMaps: function activeDynamicMaps() {
if (!this.activeTopicConfig || !this.activeTopicConfig.dynamicMapLayers) {
return [];
} else {
return this.activeTopicConfig.dynamicMapLayers;
}
},
activeFeatureLayers: function activeFeatureLayers() {
if (!this.activeTopicConfig || !this.activeTopicConfig.featureLayers) {
return [];
} else {
return this.activeTopicConfig.featureLayers;
}
},
activeFeature: function activeFeature() {
return this.$store.state.activeFeature;
},
basemaps: function basemaps() {
return Object.values(this.$config.map.basemaps);
},
imageryBasemaps: function imageryBasemaps() {
return this.basemaps.filter(function (basemap) { return basemap.type === 'imagery'; });
},
hasImageryBasemaps: function hasImageryBasemaps() {
return this.imageryBasemaps.length > 0;
},
shouldShowImageryToggle: function shouldShowImageryToggle() {
return this.hasImageryBasemaps && this.$config.map.imagery.enabled;
},
identifyFeature: function identifyFeature() {
var configFeature = this.activeTopicConfig.identifyFeature;
if (configFeature) {
return configFeature;
} else {
return this.$config.map.defaultIdentifyFeature;
}
},
activeTopic: function activeTopic() {
return this.$store.state.activeTopic;
},
activeTopicConfig: function activeTopicConfig() {
var key = this.activeTopic;
var config;
// if no active topic, return null
if (key) {
config = this.$config.topics.filter(function (topic) {
return topic.key === key;
})[0];
}
return config || {};
},
activeParcelLayer: function activeParcelLayer() {
return this.activeTopicConfig.parcels;
},
dorParcels: function dorParcels() {
return this.$store.state.parcels.dor.data;
},
pwdParcel: function pwdParcel() {
return this.$store.state.parcels.pwd;
},
geocodeResult: function geocodeResult() {
return this.$store.state.geocode.data || {};
},
geocodeGeom: function geocodeGeom() {
return this.geocodeResult.geometry;
},
streetAddress: function streetAddress() {
return this.geocodeResult.properties.street_address;
},
picOrCycloActive: function picOrCycloActive() {
if (this.cyclomediaActive || this.pictometryActive) {
return true;
} else {
return false;
}
},
mapBounds: function mapBounds() {
// TODO calculate map bounds based on leaflet markers above
},
isGeocoding: function isGeocoding() {
return this.$store.state.geocode.status === 'waiting';
}
},
watch: {
picOrCycloActive: function picOrCycloActive(value) {
var this$1 = this;
this.$nextTick(function () {
this$1.$store.state.map.map.invalidateSize();
});
}
},
methods: {
configForBasemap: function configForBasemap(basemap) {
return this.$config.map.basemaps[basemap] || {};
},
shouldShowGeojson: function shouldShowGeojson(key) {
if (this.activeTopicConfig.basemap === 'pwd') {
return true;
} else {
return key === this.activeDorParcel;
}
},
shouldShowImageOverlay: function shouldShowImageOverlay(key) {
return key === this.imageOverlay;
},
shouldShowFeatureLayer: function shouldShowFeatureLayer(key, minZoom) {
if (this.activeFeatureLayers.includes(key) && this.$store.state.map.zoom >= minZoom) {
return true;
} else {
return false;
}
},
handleMapClick: function handleMapClick(e) {
this.$controller.handleMapClick(e);
},
handleMapMove: function handleMapMove(e) {
var map = this.$store.state.map.map;
var pictometryConfig = this.$config.pictometry || {};
if (pictometryConfig.enabled) {
// update state for pictometry
var center = map.getCenter();
var lat = center.lat;
var lng = center.lng;
var coords = [lng, lat];
this.$store.commit('setPictometryMapCenter', coords);
var zoom = map.getZoom();
this.$store.commit('setPictometryMapZoom', zoom);
}
var cyclomediaConfig = this.$config.cyclomedia || {};
if (cyclomediaConfig.enabled) {
// update cyclo recordings
this.updateCyclomediaRecordings();
}
},
handleSearchFormSubmit: function handleSearchFormSubmit(e) {
this.$controller.handleSearchFormSubmit(e);
},
fillColorForCircleMarker: function fillColorForCircleMarker(markerId, tableId) {
// get map overlay style and hover style for table
var tableConfig = this.getConfigForTable(tableId);
var mapOverlay = tableConfig.options.mapOverlay;
var style = mapOverlay.style;
var hoverStyle = mapOverlay.hoverStyle;
// compare id to active feature id
var activeFeature = this.activeFeature;
var useHoverStyle = (
markerId === activeFeature.featureId &&
tableId === activeFeature.tableId
);
var curStyle = useHoverStyle ? hoverStyle : style;
return curStyle.fillColor;
},
}, // end of methods
}; //end of export
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" #cyclo-container { padding: 0px; height: 50%; } #inCycloDiv { background-color: white; border: 0px solid; width: 30px; height: 30px; /*display:none;*/ cursor:pointer; z-index: 10; position:relative; float: right; } .popout-icon { margin-top: 8.5px; font-size: 15px; margin-left: 8.5px; } .panoramaViewerWindow { /*display: inline-block;*/ display: block; width: 100%; height:100%; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var CyclomediaWidget = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:this.cycloContainerClass,attrs:{"id":"cyclo-container"}},[_c('div',{attrs:{"id":"inCycloDiv"},on:{"click":this.popoutClicked}},[_c('i',{staticClass:"fa fa-external-link fa popout-icon"})]),_vm._v(" "),_c('div',{ref:"cycloviewer",staticClass:"panoramaViewerWindow",attrs:{"id":"cycloviewer"}})])},staticRenderFns: [],
computed: {
pictometryActive: function pictometryActive() {
return this.$store.state.pictometry.active
},
cycloContainerClass: function cycloContainerClass() {
if (this.pictometryActive) {
return 'large-16 columns mb-panel'
} else {
return 'large-24 columns mb-panel'
}
},
locForCyclo: function locForCyclo() {
// console.log('computing locForCyclo');
var geocodeData = this.$store.state.geocode.data;
var map = this.$store.state.map.map;
if (geocodeData) {
return geocodeData.geometry.coordinates;
}
},
mapCenter: function mapCenter() {
return this.$store.state.map.center;
}
},
watch: {
locForCyclo: function locForCyclo(coords){
// console.log(coords);
this.setNewLocation(coords);
}
},
mounted: function mounted() {
var this$1 = this;
StreetSmartApi.init({
username: this.$config.cyclomedia.username,
password: this.$config.cyclomedia.password,
apiKey: this.$config.cyclomedia.apiKey,
srs: 'EPSG:4326',
locale: 'en-us',
addressSettings: {
locale: 'en-us',
database: 'CMDatabase'
}
}).then(
function () {
var cycloDiv = this$1.$refs.cycloviewer;
var viewer = StreetSmartApi.addPanoramaViewer(cycloDiv, {recordingsVisible: true, timeTravelVisible: true});
this$1.$store.commit('setCyclomediaViewer', viewer);
// get map center and set location
var map = this$1.$store.state.map.map;
var center = map.getCenter();
this$1.setNewLocation([center.lng, center.lat]);
// TODO bind CN events to vue
// viewer.on(StreetSmartApi.Events.panoramaViewer.VIEW_CHANGE, e => {
//
// });
// viewer.on(StreetSmartApi.Events.panoramaViewer.VIEW_LOAD_END, e => {
// const recording = viewer.getRecording();
// const xyz = recording.xyz;
// const xy = xyz.slice(0, 2);
// const xyFloat = xy.map(parseFloat);
// const xyArray = [].slice.call(xyFloat);
// });
},
function (err) {
console.log('Api: init: failed. Error: ', err);
}
);
},
updated: function updated() {
// TODO find a better way to get the image to update and not be stretched
var viewer = this.$store.state.cyclomedia.viewer;
viewer.rotateRight(0.0000001);
},
methods: {
setNewLocation: function setNewLocation(coords) {
// console.log('setNewLocation is running using', coords);
var viewer = this.$store.state.cyclomedia.viewer;
viewer.openByCoordinate(coords);
},
popoutClicked: function popoutClicked() {
var map = this.$store.state.map.map;
var center = map.getCenter();
window.open('//cyclomedia.phila.gov/?' + center.lat + '&' + center.lng, '_blank');
this.$store.commit('setCyclomediaActive', false);
}
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" header.site-header > .row[data-v-b47b60a8]:last-of-type { background: #2176d2; } #in-pict-div[data-v-b47b60a8] { /*float: right;*/ position: absolute; top: 0px; right: 0px; /*z-index: 2000000;*/ background-color: white; border: 0px solid; width: 30px; height: 30px; /*display:none;*/ cursor:pointer; /*position: relative; top: 0px; right: 0px;*/ } .popout-icon[data-v-b47b60a8] { margin-top: 8.5px; font-size: 15px; margin-left: 8.5px; } #pict-container[data-v-b47b60a8] { padding: 0px; height: 50%; position: relative; } /*#iframe-div { }*/ #pictometry-ipa[data-v-b47b60a8] { height: 100%; width: 100%; border: 0px; } #search-container[data-v-b47b60a8] { float: right; } #search-input[data-v-b47b60a8] { float: left; width: 400px; } #search-button[data-v-b47b60a8] { height: 2.78571rem; } #data-panel[data-v-b47b60a8] { background: #fff; padding-left: 12px; padding-right: 12px; height: 100%; } #data-panel > h1[data-v-b47b60a8] { color: #666; } #data-row-list > a[data-v-b47b60a8] { background: #f5f5f5; border: 1px solid #ddd; display: block; font-size: 18px; font-weight: normal; height: 70px; line-height: 45px; /*margin-left: 10px;*/ /*margin-right: 10px;*/ padding: 10px; /*vertical-align: middle;*/ /*text-align: middle;*/ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); margin-bottom: 8px; } #data-row-list > a[data-v-b47b60a8]:hover { background: #fff; color: inherit; } #data-row-list .data-row-link-icon[data-v-b47b60a8] { padding-right: 30px; } .data-row[data-v-b47b60a8] { padding: 10px; margin-bottom: 10px; display: none; } .data-row table th[data-v-b47b60a8], .data-row table td[data-v-b47b60a8] { font-size: 15px; } .data-row table tr th[data-v-b47b60a8] { text-align: left; vertical-align: top; } #map[data-v-b47b60a8] { height: 100%; } ul[data-v-b47b60a8] { list-style-type: none; padding: 0; margin: 0; } img[data-v-b47b60a8] { max-width: inherit; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var PictometryWidget = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{class:this.pictContainerClass,attrs:{"id":"pict-container"}},[_c('div',{attrs:{"id":"in-pict-div"},on:{"click":this.popoutClicked}},[_c('i',{staticClass:"fa fa-external-link fa popout-icon"})]),_vm._v(" "),_c('iframe',{ref:"pictometryIpa",attrs:{"id":"pictometry-ipa","src":"#"}}),_vm._v(" "),_c('div',[_vm._t("default")],2)])},staticRenderFns: [],_scopeId: 'data-v-b47b60a8',
props: [
'apiKey',
'secretKey',
'orientation' ],
created: function created() {
this.$IFRAME_ID = 'pictometry-ipa';
},
mounted: function mounted() {
// fetch pictometry ipa script
var scriptUrl = 'https://pol.pictometry.com/ipa/v1/embed/host.php' + '?apikey=' + this.apiKey;
var self = this;
$$1.getScript(scriptUrl, self.init);
},
computed: {
cyclomediaActive: function cyclomediaActive() {
return this.$store.state.cyclomedia.active;
},
pictContainerClass: function pictContainerClass() {
if (this.cyclomediaActive) {
return 'large-8 columns mb-panel';
} else {
return 'large-24 columns mb-panel';
}
},
mapCenter: function mapCenter() {
// return this.$store.state.geocode.data.geometry.coordinates;
return this.$store.state.pictometry.map.center;
},
mapZoom: function mapZoom() {
// const mapZoom = this.$store.state.map.zoom;
// let zoom;
// if (this.cyclomediaActive) {
// zoom = mapZoom
// } else {
// zoom = mapZoom + 1;
// }
// return zoom;
return this.$store.state.pictometry.map.zoom;
},
},
watch: {
mapCenter: function mapCenter(nextCenter) {
var x = nextCenter[0];
var y = nextCenter[1];
var zoom = this.mapZoom;
if (this.$ipa) {
this.$ipa.setLocation({ x: x, y: y, zoom: zoom });
}
},
mapZoom: function mapZoom(nextZoom) {
// console.log('watch zoomSentToPict', nextZoom);
if (this.$ipa) {
this.$ipa.setLocation({
y: this.mapCenter.lat,
x: this.mapCenter.lng,
zoom: nextZoom
});
}
},
cyclomediaActive: function cyclomediaActive(nextStatus) {
if (nextStatus) {
// console.log('pict: cyclo on');
this.$ipa.showDashboard({
zoom: false,
imageFilter: false,
layers: false,
nextPrevious: false,
tools: false,
annotations: false,
rotation: false,
clearMeasurements: false,
exportPdf: false,
dualPane: false,
imageDate: false,
panTool: false,
exportImage: false,
areaTool: false,
distanceTool: false,
heightTool: false,
locationTool: false,
elevationTool: false,
bearingTool: false,
slopeTool: false,
xyzTool: false,
identifyPoint: false,
identifyBox: false
});
} else {
// console.log('pict: cyclo off');
this.$ipa.showDashboard({
zoom: true,
imageFilter: true,
layers: true,
nextPrevious: true,
tools: true,
annotations: true,
rotation: true,
clearMeasurements: true,
exportPdf: true,
dualPane: true,
imageDate: true,
panTool: true,
exportImage: true,
areaTool: true,
distanceTool: true,
heightTool: true,
locationTool: true,
elevationTool: true,
bearingTool: true,
slopeTool: true,
xyzTool: true,
identifyPoint: true,
identifyBox: true
});
}
}
},
methods: {
popoutClicked: function popoutClicked() {
var map = this.$store.state.map.map;
var center = map.getCenter();
window.open('//pictometry.phila.gov/?' + center.lat + '&' + center.lng, '_blank');
this.$store.commit('setPictometryActive', false);
},
init: function init() {
// construct signed url
var d = new Date();
var t = Math.floor(d.getTime() / 1000);
var unsignedUrl = 'https://pol.pictometry.com/ipa/v1/load.php' + "?apikey=" + this.apiKey + "&ts=" + t;
var hash = md5(unsignedUrl, this.secretKey);
var iframeId = this.$IFRAME_ID;
var signedUrl = unsignedUrl + "&ds=" + hash + "&app_id=" + iframeId;
// set the iframe src to load the IPA
var iframe = this.$refs.pictometryIpa;
// REVIEW can we bind this to a computed instead?
iframe.setAttribute('src', signedUrl);
// create pictometry host
var ipa = this.$ipa = new PictometryHost(iframeId, 'https://pol.pictometry.com/ipa/v1/load.php');
this.$store.commit('setPictometryIpa', ipa);
ipa.ready = this.ipaReady;
},
ipaReady: function ipaReady() {
this.$ipa.setLocation({
y: this.mapCenter.lat,
x: this.mapCenter.lng,
zoom: this.mapZoom
});
var self = this;
this.$ipa.addListener('onendzoom', function(zoom) {
// console.log('widget: ipa detected zoom change to', zoom);
self.$store.commit('setPictometryZoom', zoom.level);
});
},
}, // end of methods
}; // end of export
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Layer = {
render: function render(h) {
return;
},
computed: {
ipa: function ipa() {
return this.$store.state.pictometry.ipa;
},
activeTopic: function activeTopic() {
return this.$store.state.activeTopic;
}
},
mounted: function mounted() {
this.didActivateTopic(this.activeTopic);
},
beforeDestroy: function beforeDestroy() {
this.didDeactivateTopic(this.activeTopic);
},
watch: {
activeTopic: function activeTopic(nextTopic, prevTopic) {
this.didDeactivateTopic(prevTopic);
this.didActivateTopic(nextTopic);
}
},
methods: {
didActivateTopic: function didActivateTopic(topic) {
// console.log('didActivateTopic is firing with topic: ', topic);
switch (topic) {
case 'deeds':
// turn on DOR Parcels
this.ipa.showLayer({
id: 114828,
visible: true,
});
break;
case 'zoning':
// turn on zoning
this.ipa.showLayer({
id: 112230,
visible: true,
});
break;
case 'water':
// turn on water Parcels
this.ipa.showLayer({
id: 108982,
visible: true,
});
break;
default:
// turn off DOR parcels
this.ipa.showLayer({
id: 113478,
visible: false,
});
// turn off zoning
this.ipa.showLayer({
id: 112230,
visible: false,
});
}
},
didDeactivateTopic: function didDeactivateTopic(topic) {
switch (topic) {
case 'deeds':
// turn off DOR parcels
this.ipa.showLayer({
id: 114828,
visible: false,
});
break;
case 'zoning':
// turn on zoning
this.ipa.showLayer({
id: 112230,
visible: false,
});
break;
case 'water':
// turn off water
this.ipa.showLayer({
id: 108982,
visible: false,
});
default:
// turn off DOR parcels
this.ipa.showLayer({
id: 113478,
visible: false,
});
// turn off zoning
this.ipa.showLayer({
id: 112230,
visible: false,
});
}
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=""; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var PngMarker$1 = {
props: [
'icon',
'latlng',
'height',
'width'
],
render: function render(h) {
return;
},
computed: {
ipa: function ipa() {
return this.$store.state.pictometry.ipa;
},
},
mounted: function mounted() {
// console.log('mounting PngMarker', this.icon);
this.placeMarker(this.$props.latlng);
},
beforeDestroy: function beforeDestroy() {
// console.log('before destroying PngMarker', this.icon);
this.ipa.removeShapes(this.$store.state.pictometry.pngMarkerIds);
// console.log('before destroyed PngMarker', this.icon);
},
// destroyed() {
// console.log('destroying PngMarker', this.icon);
// this.ipa.removeShapes(this.$store.state.pictometry.pngMarkerIds);
// console.log('destroyed PngMarker', this.icon);
// },
watch: {
latlng: function latlng(nextLatlng) {
// console.log('PngMarker: latlng changed');
this.ipa.removeShapes(this.$store.state.pictometry.pngMarkerIds);
this.placeMarker(nextLatlng);
}
},
methods: {
constructLocalUrl: function constructLocalUrl(host, path1, path2) {
var url;
if (window.location.protocol === 'https:') {
url = 'https://' + host + path1 + path2;
} else {
url = 'http://' + host + path1 + path2;
}
// console.log('constructing url:', url);
return url
},
placeMarker: function placeMarker(nextLatlng) {
// console.log('starting placeMarker', nextLatlng, this.$props.icon);
var port = window.location.port;
var host;
if (port != '') {
host = window.location.hostname + ':' + port;
} else {
host = window.location.hostname;
}
var pngMarker = {
type : this.ipa.SHAPE_TYPE.MARKER,
center: { y: nextLatlng[0], x: nextLatlng[1]},
markerImageHeight: this.$props.height,
markerImageWidth: this.$props.width,
markerOffsetX: this.$props.offsetX,
markerOffsetY: this.$props.offsetY,
markerImage: this.constructLocalUrl(host, '/src/assets/', this.$props.icon),
onShapeClick: 'true'
};
this.ipa.addShapes([pngMarker], this.didAddShapes);
},
didAddShapes: function didAddShapes(result) {
var this$1 = this;
// const pngMarkerIds = shapes.filter(shape => {
// return shape.success === 'true';
// }).map(shape => shape.shapeId);
// this.$store.commit('setPictometryPngMarkerIds', pngMarkerIds);
for ( var i = 0; i < result.length; i++) {
if ( result[i].success === 'false' ) {
console.log(result[i].error);
} else {
var pngMarkerIds = this$1.$store.state.pictometry.pngMarkerIds;
// console.log('pngMarkerIds', pngMarkerIds);
pngMarkerIds.push(result[i].shapeId);
}
}
},
}
};
(function () { if (typeof document !== 'undefined') { var head = document.head||document.getElementsByTagName('head')[0], style=document.createElement('style'), css=" /*don't highlight any form elements*/ input:focus, select:focus, textarea:focus, button:focus { outline: none; } .mb-panel-topics-with-widget { height: 50%; } /* standards applies padding to buttons, which causes some weirdness with buttons on the map panel. override here. */ button { padding: inherit; } "; style.type='text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); } })();
var Mapboard = {render: function(){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('div',{staticClass:"cell medium-auto grid-x",attrs:{"id":"mb-root"}},[_c('topic-panel'),_vm._v(" "),_c('map-panel',[(this.$config.cyclomedia.enabled)?_c('cyclomedia-widget',{directives:[{name:"show",rawName:"v-show",value:(_vm.cyclomediaActive),expression:"cyclomediaActive"}],attrs:{"slot":"cycloWidget"},slot:"cycloWidget"}):_vm._e(),_vm._v(" "),(this.$config.pictometry.enabled)?_c('pictometry-widget',{directives:[{name:"show",rawName:"v-show",value:(_vm.pictometryActive),expression:"pictometryActive"}],attrs:{"slot":"pictWidget","apiKey":this.ak,"secretKey":this.sk},slot:"pictWidget"},[(this.pictometryShowAddressMarker)?_c('png-marker',{attrs:{"latlng":[this.geocodeData.geometry.coordinates[1], this.geocodeData.geometry.coordinates[0]],"icon":'markers.png',"height":60,"width":40,"offsetX":0,"offsetY":0}}):_vm._e(),_vm._v(" "),(this.pictometryActive)?_c('layer'):_vm._e(),_vm._v(" "),(this.cyclomediaActive && this.pictometryActive)?_c('png-marker',{attrs:{"latlng":[this.$store.state.cyclomedia.viewer.props.orientation.xyz[1], this.$store.state.cyclomedia.viewer.props.orientation.xyz[0]],"icon":'camera2.png',"height":20,"width":30,"offsetX":-2,"offsetY":-2}}):_vm._e(),_vm._v(" "),(this.cyclomediaActive && this.pictometryActive)?_c('view-cone',{attrs:{"orientation":this.$store.state.cyclomedia.viewer.props.orientation}}):_vm._e()],1):_vm._e()],1)],1)},staticRenderFns: [],
components: {
TopicPanel: TopicPanel,
MapPanel: MapPanel,
CyclomediaWidget: CyclomediaWidget,
PictometryWidget: PictometryWidget,
Layer: Layer,
PngMarker: PngMarker$1
},
created: function created() {
var IS_MOBILE_OR_TABLET = false;
this.$store.commit('setIsMobileOrTablet', IS_MOBILE_OR_TABLET);
},
computed: {
cyclomediaActive: function cyclomediaActive() {
return this.$store.state.cyclomedia.active
},
pictometryActive: function pictometryActive() {
return this.$store.state.pictometry.active
},
pictometryZoom: function pictometryZoom() {
return this.$store.state.pictometry.zoom
},
pictometryShowAddressMarker: function pictometryShowAddressMarker() {
if (!this.pictometryActive || !this.geocodeData) {
return false;
} else if (this.pictometryZoom < 20 && this.cyclomediaActive) {
return false;
} else {
return true;
}
},
geocodeData: function geocodeData() {
return this.$store.state.geocode.data
},
ak: function ak() {
var host = window.location.hostname;
if (host === 'atlas.phila.gov') {
return this.$config.pictometry.apiKey;
}
if (host === 'atlas-dev.phila.gov') {
return this.$config.pictometryDev.apiKey;
}
if (host === 'cityatlas.phila.gov') {
return this.$config.pictometryCity.apiKey;
}
if (host === 'cityatlas-dev.phila.gov') {
return this.$config.pictometryCityDev.apiKey;
}
if (host === '10.8.101.67') {
return this.$config.pictometryLocal.apiKey;
}
},
sk: function sk() {
var host = window.location.hostname;
if (host === 'atlas.phila.gov') {
return this.$config.pictometry.secretKey;
}
if (host === 'atlas-dev.phila.gov') {
return this.$config.pictometryDev.secretKey;
}
if (host === 'cityatlas.phila.gov') {
return this.$config.pictometryCity.secretKey;
}
if (host === 'cityatlas-dev.phila.gov') {
return this.$config.pictometryCityDev.secretKey;
}
if (host === '10.8.101.67') {
return this.$config.pictometryLocal.secretKey;
}
}
},
watch: {
pictometryShowAddressMarker: function pictometryShowAddressMarker(nextValue) {
console.log('watch pictometryShowAddressMarker', nextValue);
}
}
};
// http://stackoverflow.com/a/37164538/676001
// helper to verify that an item is an object
function isObject(item) {
return (item && typeof item === 'object' && !Array.isArray(item) && item !== null);
}
// merges n objects, deeply, immutably
function mergeDeep(target, source) {
var obj, obj$1;
var output = Object.assign({}, target);
if (isObject(target) && isObject(source)) {
Object.keys(source).forEach(function (key) {
if (isObject(source[key])) {
if (!(key in target))
{ Object.assign(output, ( obj = {}, obj[key] = source[key], obj)); }
else
{ output[key] = mergeDeep(target[key], source[key]); }
} else {
Object.assign(output, ( obj$1 = {}, obj$1[key] = source[key], obj$1));
}
});
}
return output;
}
/*! https://mths.be/punycode v1.4.1 by @mathias */
/** Highest positive signed 32-bit float value */
var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
/** Bootstring parameters */
var base = 36;
var tMin = 1;
var tMax = 26;
var skew = 38;
var damp = 700;
var initialBias = 72;
var initialN = 128; // 0x80
var delimiter = '-'; // '\x2D'
var regexNonASCII = /[^\x20-\x7E]/; // unprintable ASCII chars + non-ASCII chars
var regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
/** Error messages */
var errors = {
'overflow': 'Overflow: input needs wider integers to process',
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
'invalid-input': 'Invalid input'
};
/** Convenience shortcuts */
var baseMinusTMin = base - tMin;
var floor = Math.floor;
var stringFromCharCode = String.fromCharCode;
/*--------------------------------------------------------------------------*/
/**
* A generic error utility function.
* @private
* @param {String} type The error type.
* @returns {Error} Throws a `RangeError` with the applicable error message.
*/
function error(type) {
throw new RangeError(errors[type]);
}
/**
* A generic `Array#map` utility function.
* @private
* @param {Array} array The array to iterate over.
* @param {Function} callback The function that gets called for every array
* item.
* @returns {Array} A new array of values returned by the callback function.
*/
function map(array, fn) {
var length = array.length;
var result = [];
while (length--) {
result[length] = fn(array[length]);
}
return result;
}
/**
* A simple `Array#map`-like wrapper to work with domain name strings or email
* addresses.
* @private
* @param {String} domain The domain name or email address.
* @param {Function} callback The function that gets called for every
* character.
* @returns {Array} A new string of characters returned by the callback
* function.
*/
function mapDomain(string, fn) {
var parts = string.split('@');
var result = '';
if (parts.length > 1) {
// In email addresses, only the domain name should be punycoded. Leave
// the local part (i.e. everything up to `@`) intact.
result = parts[0] + '@';
string = parts[1];
}
// Avoid `split(regex)` for IE8 compatibility. See #17.
string = string.replace(regexSeparators, '\x2E');
var labels = string.split('.');
var encoded = map(labels, fn).join('.');
return result + encoded;
}
/**
* Creates an array containing the numeric code points of each Unicode
* character in the string. While JavaScript uses UCS-2 internally,
* this function will convert a pair of surrogate halves (each of which
* UCS-2 exposes as separate characters) into a single code point,
* matching UTF-16.
* @see `punycode.ucs2.encode`
* @see <https://mathiasbynens.be/notes/javascript-encoding>
* @memberOf punycode.ucs2
* @name decode
* @param {String} string The Unicode input string (UCS-2).
* @returns {Array} The new array of code points.
*/
function ucs2decode(string) {
var output = [],
counter = 0,
length = string.length,
value,
extra;
while (counter < length) {
value = string.charCodeAt(counter++);
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
// high surrogate, and there is a next character
extra = string.charCodeAt(counter++);
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
} else {
// unmatched surrogate; only append this code unit, in case the next
// code unit is the high surrogate of a surrogate pair
output.push(value);
counter--;
}
} else {
output.push(value);
}
}
return output;
}
/**
* Converts a digit/integer into a basic code point.
* @see `basicToDigit()`
* @private
* @param {Number} digit The numeric value of a basic code point.
* @returns {Number} The basic code point whose value (when used for
* representing integers) is `digit`, which needs to be in the range
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
* used; else, the lowercase form is used. The behavior is undefined
* if `flag` is non-zero and `digit` has no uppercase form.
*/
function digitToBasic(digit, flag) {
// 0..25 map to ASCII a..z or A..Z
// 26..35 map to ASCII 0..9
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
}
/**
* Bias adaptation function as per section 3.4 of RFC 3492.
* https://tools.ietf.org/html/rfc3492#section-3.4
* @private
*/
function adapt(delta, numPoints, firstTime) {
var k = 0;
delta = firstTime ? floor(delta / damp) : delta >> 1;
delta += floor(delta / numPoints);
for ( /* no initialization */ ; delta > baseMinusTMin * tMax >> 1; k += base) {
delta = floor(delta / baseMinusTMin);
}
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
}
/**
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
* symbols.
* @memberOf punycode
* @param {String} input The Punycode string of ASCII-only symbols.
* @returns {String} The resulting string of Unicode symbols.
*/
/**
* Converts a string of Unicode symbols (e.g. a domain name label) to a
* Punycode string of ASCII-only symbols.
* @memberOf punycode
* @param {String} input The string of Unicode symbols.
* @returns {String} The resulting Punycode string of ASCII-only symbols.
*/
function encode(input) {
var n,
delta,
handledCPCount,
basicLength,
bias,
j,
m,
q,
k,
t,
currentValue,
output = [],
/** `inputLength` will hold the number of code points in `input`. */
inputLength,
/** Cached calculation results */
handledCPCountPlusOne,
baseMinusT,
qMinusT;
// Convert the input in UCS-2 to Unicode
input = ucs2decode(input);
// Cache the length
inputLength = input.length;
// Initialize the state
n = initialN;
delta = 0;
bias = initialBias;
// Handle the basic code points
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < 0x80) {
output.push(stringFromCharCode(currentValue));
}
}
handledCPCount = basicLength = output.length;
// `handledCPCount` is the number of code points that have been handled;
// `basicLength` is the number of basic code points.
// Finish the basic string - if it is not empty - with a delimiter
if (basicLength) {
output.push(delimiter);
}
// Main encoding loop:
while (handledCPCount < inputLength) {
// All non-basic code points < n have been handled already. Find the next
// larger one:
for (m = maxInt, j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue >= n && currentValue < m) {
m = currentValue;
}
}
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
// but guard against overflow
handledCPCountPlusOne = handledCPCount + 1;
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
error('overflow');
}
delta += (m - n) * handledCPCountPlusOne;
n = m;
for (j = 0; j < inputLength; ++j) {
currentValue = input[j];
if (currentValue < n && ++delta > maxInt) {
error('overflow');
}
if (currentValue == n) {
// Represent delta as a generalized variable-length integer
for (q = delta, k = base; /* no condition */ ; k += base) {
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
if (q < t) {
break;
}
qMinusT = q - t;
baseMinusT = base - t;
output.push(
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
);
q = floor(qMinusT / baseMinusT);
}
output.push(stringFromCharCode(digitToBasic(q, 0)));
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
delta = 0;
++handledCPCount;
}
}
++delta;
++n;
}
return output.join('');
}
/**
* Converts a Punycode string representing a domain name or an email address
* to Unicode. Only the Punycoded parts of the input will be converted, i.e.
* it doesn't matter if you call it on a string that has already been
* converted to Unicode.
* @memberOf punycode
* @param {String} input The Punycoded domain name or email address to
* convert to Unicode.
* @returns {String} The Unicode representation of the given Punycode
* string.
*/
/**
* Converts a Unicode string representing a domain name or an email address to
* Punycode. Only the non-ASCII parts of the domain name will be converted,
* i.e. it doesn't matter if you call it with a domain that's already in
* ASCII.
* @memberOf punycode
* @param {String} input The domain name or email address to convert, as a
* Unicode string.
* @returns {String} The Punycode representation of the given domain name or
* email address.
*/
function toASCII(input) {
return mapDomain(input, function(string) {
return regexNonASCII.test(string) ?
'xn--' + encode(string) :
string;
});
}
/**
* An object of methods to convert from JavaScript's internal character
* representation (UCS-2) to Unicode code points, and back.
* @see <https://mathiasbynens.be/notes/javascript-encoding>
* @memberOf punycode
* @type Object
*/
// shim for using process in browser
// based off https://github.com/defunctzombie/node-process/blob/master/browser.js
if (typeof global.setTimeout === 'function') {
}
if (typeof global.clearTimeout === 'function') {
}
// empty string to avoid regexp issues
// from https://github.com/kumavis/browser-process-hrtime/blob/master/index.js
var performance = global.performance || {};
var performanceNow =
performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function(){ return (new Date()).getTime() };
// generate timestamp or delta
// see http://nodejs.org/api/process.html#process_process_hrtime
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isNull(arg) {
return arg === null;
}
function isNullOrUndefined(arg) {
return arg == null;
}
function isString(arg) {
return typeof arg === 'string';
}
function isObject$1(arg) {
return typeof arg === 'object' && arg !== null;
}
// log is just a thin wrapper to console.log that prepends a timestamp
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
function hasOwnProperty$1(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
var isArray$1 = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
function stringifyPrimitive(v) {
switch (typeof v) {
case 'string':
return v;
case 'boolean':
return v ? 'true' : 'false';
case 'number':
return isFinite(v) ? v : '';
default:
return '';
}
}
function stringify (obj, sep, eq, name) {
sep = sep || '&';
eq = eq || '=';
if (obj === null) {
obj = undefined;
}
if (typeof obj === 'object') {
return map$1(objectKeys(obj), function(k) {
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
if (isArray$1(obj[k])) {
return map$1(obj[k], function(v) {
return ks + encodeURIComponent(stringifyPrimitive(v));
}).join(sep);
} else {
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
}
}).join(sep);
}
if (!name) { return ''; }
return encodeURIComponent(stringifyPrimitive(name)) + eq +
encodeURIComponent(stringifyPrimitive(obj));
}
function map$1 (xs, f) {
if (xs.map) { return xs.map(f); }
var res = [];
for (var i = 0; i < xs.length; i++) {
res.push(f(xs[i], i));
}
return res;
}
var objectKeys = Object.keys || function (obj) {
var res = [];
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) { res.push(key); }
}
return res;
};
function parse$1(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
var regexp = /\+/g;
qs = qs.split(sep);
var maxKeys = 1000;
if (options && typeof options.maxKeys === 'number') {
maxKeys = options.maxKeys;
}
var len = qs.length;
// maxKeys <= 0 means that we should not limit keys count
if (maxKeys > 0 && len > maxKeys) {
len = maxKeys;
}
for (var i = 0; i < len; ++i) {
var x = qs[i].replace(regexp, '%20'),
idx = x.indexOf(eq),
kstr, vstr, k, v;
if (idx >= 0) {
kstr = x.substr(0, idx);
vstr = x.substr(idx + 1);
} else {
kstr = x;
vstr = '';
}
k = decodeURIComponent(kstr);
v = decodeURIComponent(vstr);
if (!hasOwnProperty$1(obj, k)) {
obj[k] = v;
} else if (isArray$1(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
return obj;
}
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
function Url() {
this.protocol = null;
this.slashes = null;
this.auth = null;
this.host = null;
this.port = null;
this.hostname = null;
this.hash = null;
this.search = null;
this.query = null;
this.pathname = null;
this.path = null;
this.href = null;
}
// Reference: RFC 3986, RFC 1808, RFC 2396
// define these here so at least they only have to be
// compiled once on the first module load.
var protocolPattern = /^([a-z0-9.+-]+:)/i;
var portPattern = /:[0-9]*$/;
var simplePathPattern = /^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/;
var delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'];
var unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims);
var autoEscape = ['\''].concat(unwise);
var nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape);
var hostEndingChars = ['/', '?', '#'];
var hostnameMaxLen = 255;
var hostnamePartPattern = /^[+a-z0-9A-Z_-]{0,63}$/;
var hostnamePartStart = /^([+a-z0-9A-Z_-]{0,63})(.*)$/;
var unsafeProtocol = {
'javascript': true,
'javascript:': true
};
var hostlessProtocol = {
'javascript': true,
'javascript:': true
};
var slashedProtocol = {
'http': true,
'https': true,
'ftp': true,
'gopher': true,
'file': true,
'http:': true,
'https:': true,
'ftp:': true,
'gopher:': true,
'file:': true
};
function urlParse(url, parseQueryString, slashesDenoteHost) {
if (url && isObject$1(url) && url instanceof Url) { return url; }
var u = new Url;
u.parse(url, parseQueryString, slashesDenoteHost);
return u;
}
Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
return parse$$1(this, url, parseQueryString, slashesDenoteHost);
};
function parse$$1(self, url, parseQueryString, slashesDenoteHost) {
if (!isString(url)) {
throw new TypeError('Parameter \'url\' must be a string, not ' + typeof url);
}
// Copy chrome, IE, opera backslash-handling behavior.
// Back slashes before the query string get converted to forward slashes
// See: https://code.google.com/p/chromium/issues/detail?id=25916
var queryIndex = url.indexOf('?'),
splitter =
(queryIndex !== -1 && queryIndex < url.indexOf('#')) ? '?' : '#',
uSplit = url.split(splitter),
slashRegex = /\\/g;
uSplit[0] = uSplit[0].replace(slashRegex, '/');
url = uSplit.join(splitter);
var rest = url;
// trim before proceeding.
// This is to support parse stuff like " http://foo.com \n"
rest = rest.trim();
if (!slashesDenoteHost && url.split('#').length === 1) {
// Try fast path regexp
var simplePath = simplePathPattern.exec(rest);
if (simplePath) {
self.path = rest;
self.href = rest;
self.pathname = simplePath[1];
if (simplePath[2]) {
self.search = simplePath[2];
if (parseQueryString) {
self.query = parse$1(self.search.substr(1));
} else {
self.query = self.search.substr(1);
}
} else if (parseQueryString) {
self.search = '';
self.query = {};
}
return self;
}
}
var proto = protocolPattern.exec(rest);
if (proto) {
proto = proto[0];
var lowerProto = proto.toLowerCase();
self.protocol = lowerProto;
rest = rest.substr(proto.length);
}
// figure out if it's got a host
// user@server is *always* interpreted as a hostname, and url
// resolution will treat //foo/bar as host=foo,path=bar because that's
// how the browser resolves relative URLs.
if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
var slashes = rest.substr(0, 2) === '//';
if (slashes && !(proto && hostlessProtocol[proto])) {
rest = rest.substr(2);
self.slashes = true;
}
}
var i, hec, l, p;
if (!hostlessProtocol[proto] &&
(slashes || (proto && !slashedProtocol[proto]))) {
// there's a hostname.
// the first instance of /, ?, ;, or # ends the host.
//
// If there is an @ in the hostname, then non-host chars *are* allowed
// to the left of the last @ sign, unless some host-ending character
// comes *before* the @-sign.
// URLs are obnoxious.
//
// ex:
// http://a@b@c/ => user:a@b host:c
// http://a@b?@c => user:a host:c path:/?@c
// v0.12 TODO(isaacs): This is not quite how Chrome does things.
// Review our test case against browsers more comprehensively.
// find the first instance of any hostEndingChars
var hostEnd = -1;
for (i = 0; i < hostEndingChars.length; i++) {
hec = rest.indexOf(hostEndingChars[i]);
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
{ hostEnd = hec; }
}
// at this point, either we have an explicit point where the
// auth portion cannot go past, or the last @ char is the decider.
var auth, atSign;
if (hostEnd === -1) {
// atSign can be anywhere.
atSign = rest.lastIndexOf('@');
} else {
// atSign must be in auth portion.
// http://a@b/c@d => host:b auth:a path:/c@d
atSign = rest.lastIndexOf('@', hostEnd);
}
// Now we have a portion which is definitely the auth.
// Pull that off.
if (atSign !== -1) {
auth = rest.slice(0, atSign);
rest = rest.slice(atSign + 1);
self.auth = decodeURIComponent(auth);
}
// the host is the remaining to the left of the first non-host char
hostEnd = -1;
for (i = 0; i < nonHostChars.length; i++) {
hec = rest.indexOf(nonHostChars[i]);
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
{ hostEnd = hec; }
}
// if we still have not hit it, then the entire thing is a host.
if (hostEnd === -1)
{ hostEnd = rest.length; }
self.host = rest.slice(0, hostEnd);
rest = rest.slice(hostEnd);
// pull out port.
parseHost(self);
// we've indicated that there is a hostname,
// so even if it's empty, it has to be present.
self.hostname = self.hostname || '';
// if hostname begins with [ and ends with ]
// assume that it's an IPv6 address.
var ipv6Hostname = self.hostname[0] === '[' &&
self.hostname[self.hostname.length - 1] === ']';
// validate a little.
if (!ipv6Hostname) {
var hostparts = self.hostname.split(/\./);
for (i = 0, l = hostparts.length; i < l; i++) {
var part = hostparts[i];
if (!part) { continue; }
if (!part.match(hostnamePartPattern)) {
var newpart = '';
for (var j = 0, k = part.length; j < k; j++) {
if (part.charCodeAt(j) > 127) {
// we replace non-ASCII char with a temporary placeholder
// we need this to make sure size of hostname is not
// broken by replacing non-ASCII by nothing
newpart += 'x';
} else {
newpart += part[j];
}
}
// we test again with ASCII char only
if (!newpart.match(hostnamePartPattern)) {
var validParts = hostparts.slice(0, i);
var notHost = hostparts.slice(i + 1);
var bit = part.match(hostnamePartStart);
if (bit) {
validParts.push(bit[1]);
notHost.unshift(bit[2]);
}
if (notHost.length) {
rest = '/' + notHost.join('.') + rest;
}
self.hostname = validParts.join('.');
break;
}
}
}
}
if (self.hostname.length > hostnameMaxLen) {
self.hostname = '';
} else {
// hostnames are always lower case.
self.hostname = self.hostname.toLowerCase();
}
if (!ipv6Hostname) {
// IDNA Support: Returns a punycoded representation of "domain".
// It only converts parts of the domain name that
// have non-ASCII characters, i.e. it doesn't matter if
// you call it with a domain that already is ASCII-only.
self.hostname = toASCII(self.hostname);
}
p = self.port ? ':' + self.port : '';
var h = self.hostname || '';
self.host = h + p;
self.href += self.host;
// strip [ and ] from the hostname
// the host field still retains them, though
if (ipv6Hostname) {
self.hostname = self.hostname.substr(1, self.hostname.length - 2);
if (rest[0] !== '/') {
rest = '/' + rest;
}
}
}
// now rest is set to the post-host stuff.
// chop off any delim chars.
if (!unsafeProtocol[lowerProto]) {
// First, make 100% sure that any "autoEscape" chars get
// escaped, even if encodeURIComponent doesn't think they
// need to be.
for (i = 0, l = autoEscape.length; i < l; i++) {
var ae = autoEscape[i];
if (rest.indexOf(ae) === -1)
{ continue; }
var esc = encodeURIComponent(ae);
if (esc === ae) {
esc = escape(ae);
}
rest = rest.split(ae).join(esc);
}
}
// chop off from the tail first.
var hash = rest.indexOf('#');
if (hash !== -1) {
// got a fragment string.
self.hash = rest.substr(hash);
rest = rest.slice(0, hash);
}
var qm = rest.indexOf('?');
if (qm !== -1) {
self.search = rest.substr(qm);
self.query = rest.substr(qm + 1);
if (parseQueryString) {
self.query = parse$1(self.query);
}
rest = rest.slice(0, qm);
} else if (parseQueryString) {
// no query string, but parseQueryString still requested
self.search = '';
self.query = {};
}
if (rest) { self.pathname = rest; }
if (slashedProtocol[lowerProto] &&
self.hostname && !self.pathname) {
self.pathname = '/';
}
//to support http.request
if (self.pathname || self.search) {
p = self.pathname || '';
var s = self.search || '';
self.path = p + s;
}
// finally, reconstruct the href based on what has been validated.
self.href = format(self);
return self;
}
function format(self) {
var auth = self.auth || '';
if (auth) {
auth = encodeURIComponent(auth);
auth = auth.replace(/%3A/i, ':');
auth += '@';
}
var protocol = self.protocol || '',
pathname = self.pathname || '',
hash = self.hash || '',
host = false,
query = '';
if (self.host) {
host = auth + self.host;
} else if (self.hostname) {
host = auth + (self.hostname.indexOf(':') === -1 ?
self.hostname :
'[' + this.hostname + ']');
if (self.port) {
host += ':' + self.port;
}
}
if (self.query &&
isObject$1(self.query) &&
Object.keys(self.query).length) {
query = stringify(self.query);
}
var search = self.search || (query && ('?' + query)) || '';
if (protocol && protocol.substr(-1) !== ':') { protocol += ':'; }
// only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
// unless they had them to begin with.
if (self.slashes ||
(!protocol || slashedProtocol[protocol]) && host !== false) {
host = '//' + (host || '');
if (pathname && pathname.charAt(0) !== '/') { pathname = '/' + pathname; }
} else if (!host) {
host = '';
}
if (hash && hash.charAt(0) !== '#') { hash = '#' + hash; }
if (search && search.charAt(0) !== '?') { search = '?' + search; }
pathname = pathname.replace(/[?#]/g, function(match) {
return encodeURIComponent(match);
});
search = search.replace('#', '%23');
return protocol + host + pathname + search + hash;
}
Url.prototype.format = function() {
return format(this);
};
Url.prototype.resolve = function(relative) {
return this.resolveObject(urlParse(relative, false, true)).format();
};
Url.prototype.resolveObject = function(relative) {
var this$1 = this;
if (isString(relative)) {
var rel = new Url();
rel.parse(relative, false, true);
relative = rel;
}
var result = new Url();
var tkeys = Object.keys(this);
for (var tk = 0; tk < tkeys.length; tk++) {
var tkey = tkeys[tk];
result[tkey] = this$1[tkey];
}
// hash is always overridden, no matter what.
// even href="" will remove it.
result.hash = relative.hash;
// if the relative url is empty, then there's nothing left to do here.
if (relative.href === '') {
result.href = result.format();
return result;
}
// hrefs like //foo/bar always cut to the protocol.
if (relative.slashes && !relative.protocol) {
// take everything except the protocol from relative
var rkeys = Object.keys(relative);
for (var rk = 0; rk < rkeys.length; rk++) {
var rkey = rkeys[rk];
if (rkey !== 'protocol')
{ result[rkey] = relative[rkey]; }
}
//urlParse appends trailing / to urls like http://www.example.com
if (slashedProtocol[result.protocol] &&
result.hostname && !result.pathname) {
result.path = result.pathname = '/';
}
result.href = result.format();
return result;
}
var relPath;
if (relative.protocol && relative.protocol !== result.protocol) {
// if it's a known url protocol, then changing
// the protocol does weird things
// first, if it's not file:, then we MUST have a host,
// and if there was a path
// to begin with, then we MUST have a path.
// if it is file:, then the host is dropped,
// because that's known to be hostless.
// anything else is assumed to be absolute.
if (!slashedProtocol[relative.protocol]) {
var keys = Object.keys(relative);
for (var v = 0; v < keys.length; v++) {
var k = keys[v];
result[k] = relative[k];
}
result.href = result.format();
return result;
}
result.protocol = relative.protocol;
if (!relative.host && !hostlessProtocol[relative.protocol]) {
relPath = (relative.pathname || '').split('/');
while (relPath.length && !(relative.host = relPath.shift())){ }
if (!relative.host) { relative.host = ''; }
if (!relative.hostname) { relative.hostname = ''; }
if (relPath[0] !== '') { relPath.unshift(''); }
if (relPath.length < 2) { relPath.unshift(''); }
result.pathname = relPath.join('/');
} else {
result.pathname = relative.pathname;
}
result.search = relative.search;
result.query = relative.query;
result.host = relative.host || '';
result.auth = relative.auth;
result.hostname = relative.hostname || relative.host;
result.port = relative.port;
// to support http.request
if (result.pathname || result.search) {
var p = result.pathname || '';
var s = result.search || '';
result.path = p + s;
}
result.slashes = result.slashes || relative.slashes;
result.href = result.format();
return result;
}
var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
isRelAbs = (
relative.host ||
relative.pathname && relative.pathname.charAt(0) === '/'
),
mustEndAbs = (isRelAbs || isSourceAbs ||
(result.host && relative.pathname)),
removeAllDots = mustEndAbs,
srcPath = result.pathname && result.pathname.split('/') || [],
psychotic = result.protocol && !slashedProtocol[result.protocol];
relPath = relative.pathname && relative.pathname.split('/') || [];
// if the url is a non-slashed url, then relative
// links like ../.. should be able
// to crawl up to the hostname, as well. This is strange.
// result.protocol has already been set by now.
// Later on, put the first path part into the host field.
if (psychotic) {
result.hostname = '';
result.port = null;
if (result.host) {
if (srcPath[0] === '') { srcPath[0] = result.host; }
else { srcPath.unshift(result.host); }
}
result.host = '';
if (relative.protocol) {
relative.hostname = null;
relative.port = null;
if (relative.host) {
if (relPath[0] === '') { relPath[0] = relative.host; }
else { relPath.unshift(relative.host); }
}
relative.host = null;
}
mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
}
var authInHost;
if (isRelAbs) {
// it's absolute.
result.host = (relative.host || relative.host === '') ?
relative.host : result.host;
result.hostname = (relative.hostname || relative.hostname === '') ?
relative.hostname : result.hostname;
result.search = relative.search;
result.query = relative.query;
srcPath = relPath;
// fall through to the dot-handling below.
} else if (relPath.length) {
// it's relative
// throw away the existing file, and take the new path instead.
if (!srcPath) { srcPath = []; }
srcPath.pop();
srcPath = srcPath.concat(relPath);
result.search = relative.search;
result.query = relative.query;
} else if (!isNullOrUndefined(relative.search)) {
// just pull out the search.
// like href='?foo'.
// Put this after the other two cases because it simplifies the booleans
if (psychotic) {
result.hostname = result.host = srcPath.shift();
//occationaly the auth can get stuck only in host
//this especially happens in cases like
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
authInHost = result.host && result.host.indexOf('@') > 0 ?
result.host.split('@') : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
result.search = relative.search;
result.query = relative.query;
//to support http.request
if (!isNull(result.pathname) || !isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}
result.href = result.format();
return result;
}
if (!srcPath.length) {
// no path at all. easy.
// we've already handled the other stuff above.
result.pathname = null;
//to support http.request
if (result.search) {
result.path = '/' + result.search;
} else {
result.path = null;
}
result.href = result.format();
return result;
}
// if a url ENDs in . or .., then it must get a trailing slash.
// however, if it ends in anything else non-slashy,
// then it must NOT get a trailing slash.
var last = srcPath.slice(-1)[0];
var hasTrailingSlash = (
(result.host || relative.host || srcPath.length > 1) &&
(last === '.' || last === '..') || last === '');
// strip single dots, resolve double dots to parent dir
// if the path tries to go above the root, `up` ends up > 0
var up = 0;
for (var i = srcPath.length; i >= 0; i--) {
last = srcPath[i];
if (last === '.') {
srcPath.splice(i, 1);
} else if (last === '..') {
srcPath.splice(i, 1);
up++;
} else if (up) {
srcPath.splice(i, 1);
up--;
}
}
// if the path is allowed to go above the root, restore leading ..s
if (!mustEndAbs && !removeAllDots) {
for (; up--; up) {
srcPath.unshift('..');
}
}
if (mustEndAbs && srcPath[0] !== '' &&
(!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
srcPath.unshift('');
}
if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
srcPath.push('');
}
var isAbsolute = srcPath[0] === '' ||
(srcPath[0] && srcPath[0].charAt(0) === '/');
// put the host back
if (psychotic) {
result.hostname = result.host = isAbsolute ? '' :
srcPath.length ? srcPath.shift() : '';
//occationaly the auth can get stuck only in host
//this especially happens in cases like
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
authInHost = result.host && result.host.indexOf('@') > 0 ?
result.host.split('@') : false;
if (authInHost) {
result.auth = authInHost.shift();
result.host = result.hostname = authInHost.shift();
}
}
mustEndAbs = mustEndAbs || (result.host && srcPath.length);
if (mustEndAbs && !isAbsolute) {
srcPath.unshift('');
}
if (!srcPath.length) {
result.pathname = null;
result.path = null;
} else {
result.pathname = srcPath.join('/');
}
//to support request.http
if (!isNull(result.pathname) || !isNull(result.search)) {
result.path = (result.pathname ? result.pathname : '') +
(result.search ? result.search : '');
}
result.auth = relative.auth || result.auth;
result.slashes = result.slashes || relative.slashes;
result.href = result.format();
return result;
};
Url.prototype.parseHost = function() {
return parseHost(this);
};
function parseHost(self) {
var host = self.host;
var port = portPattern.exec(host);
if (port) {
port = port[0];
if (port !== ':') {
self.port = port.substr(1);
}
host = host.substr(0, host.length - port.length);
}
if (host) { self.hostname = host; }
}
var Router = function Router(opts) {
var config = this.config = opts.config;
this.store = opts.store;
this.controller = opts.controller;
this.eventBus = opts.eventBus;
this.dataManager = opts.dataManager;
this.history = window.history;
// check if the router should be silent (i.e. not update the url or listen
// for hash changes)
var silent = this.silent = !config.router || !config.router.enabled;
// only listen for route changes if routing is enabled
if (!silent) {
window.onhashchange = this.hashChanged.bind(this);
}
};
Router.prototype.activeTopicConfig = function activeTopicConfig () {
var key = this.store.state.activeTopic;
var config;
// if no active topic, return null
if (key) {
config = this.config.topics.filter(function (topic) {
return topic.key === key;
})[0];
}
return config || {};
};
Router.prototype.activeParcelLayer = function activeParcelLayer () {
return this.activeTopicConfig().parcels || this.config.map.defaultBasemap;
};
Router.prototype.makeHash = function makeHash (address, topic) {
console.log('make hash', address, topic);
// must have an address
if (!address || address.length === 0) {
return null;
}
var hash = "#/" + (encodeURIComponent(address));
if (topic) {
hash += "/" + topic;
}
return hash;
};
Router.prototype.getAddressFromState = function getAddressFromState () {
// TODO add an address getter fn to config so this isn't ais-specific
var geocodeData = this.store.state.geocode.data || {};
var props = geocodeData.properties || {};
if (geocodeData.street_address) {
return geocodeData.street_address;
} else if (props.street_address) {
return props.street_address;
}
};
Router.prototype.hashChanged = function hashChanged () {
var location = window.location;
var hash = location.hash;
// console.log('hash changed =>', hash);
// parse url
var comps = urlParse(location.href);
var query = comps.query;
// handle ?search entry point
if (query && query.search) {
// TODO
}
// parse path
var pathComps = hash.split('/').splice(1);
var addressComp = pathComps[0];
// if there's no address, don't do anything
if (!addressComp) {
// console.log('no address, returning');
return;
}
var nextAddress = decodeURIComponent(addressComp);
var nextTopic;
if (pathComps.length > 1) {
nextTopic = decodeURIComponent(pathComps[1]);
}
this.store.commit('setLastSearchMethod', 'geocode');
this.routeToAddress(nextAddress);
this.routeToTopic(nextTopic);
};
Router.prototype.routeToAddress = function routeToAddress (nextAddress) {
console.log('Router.routeToAddress', nextAddress);
if (nextAddress) {
// check against current address
var prevAddress = this.getAddressFromState();
// if the hash address is different, geocode
if (!prevAddress || nextAddress !== prevAddress) {
this.dataManager.geocode(nextAddress);
// .then(this.didGeocode.bind(this));
}
}
// the following code doesn't seem to be needed anymore. it's probably
// happening in didGeocode.
// if not silent, update hash. this is needed for updating the hash after
// topic clicks.
// if (!this.silent) {
// const prevOrNextAddress = nextAddress || this.getAddressFromState();
// const nextHash = this.makeHash(prevOrNextAddress, nextTopic);
//
// if (nextHash) {
// // TODO replace state
// const prevState = this.history.state;
// // this.history.replaceState(prevState, null, nextHash);
//
// // window.location.hash = nextHash;
// }
// }
};
Router.prototype.configForBasemap = function configForBasemap (key) {
return this.config.map.basemaps[key];
};
// this gets called when you click a topic header.
Router.prototype.routeToTopic = function routeToTopic (nextTopic, target) {
// check against active topic
var prevTopic = this.store.state.activeTopic;
if (!prevTopic || prevTopic !== nextTopic) {
this.store.commit('setActiveTopic', nextTopic);
this.store.commit('setActiveParcelLayer', this.activeParcelLayer());
var prevBasemap = this.store.state.map.basemap || null;
// if (!this.store.state.map.shouldShowImagery) {
var nextTopicConfig = this.config.topics.filter(function (topic) {
return topic.key === nextTopic;
})[0] || {};
var nextBasemap = nextTopicConfig.parcels;
if (prevBasemap !== nextBasemap) {
this.store.commit('setBasemap', nextTopicConfig.parcels);
}
// console.log('in routeToTopic, nextTopic', nextTopic, 'target', target);
// if (target) {
// target.scrollIntoView();
// }
// }
}
if (!this.silent) {
var address = this.getAddressFromState();
var nextHash = this.makeHash(address, nextTopic);
var lastHistoryState = this.history.state;
this.history.replaceState(lastHistoryState, null, nextHash);
}
};
Router.prototype.didGeocode = function didGeocode () {
// console.log('Router.didGeocode');
// update url
// REVIEW this is ais-specific
var geocodeData = this.store.state.geocode.data;
// make hash if there is geocode data
console.log('Router.didGeocode running - geocodeData:', geocodeData);
if (geocodeData) {
// const address = geocodeData.properties.street_address;
var address;
if (geocodeData.street_address) {
address = geocodeData.street_address;
} else if (geocodeData.properties.street_address) {
address = geocodeData.properties.street_address;
}
// } else if (this.store.state.activeDorMapreg) {
// address = this.store.state.activeDorMapreg;
var topic = this.store.state.activeTopic;
// REVIEW this is only pushing state when routing is turned on. but maybe we
// want this to happen all the time, right?
if (!this.silent) {
// push state
var nextHistoryState = {
geocode: geocodeData
};
var nextHash = this.makeHash(address, topic);
// console.log('nextHistoryState', nextHistoryState, 'nextHash', nextHash);
this.history.pushState(nextHistoryState, null, nextHash);
}
} else {
// wipe out hash if a geocode fails
if (!this.silent) {
// push state
// const nextHistoryState = {
// geocode: null
// };
// this.history.pushState(nextHistoryState, null, '#');
this.history.pushState(null, null, '#');
}
}
};
var BaseClient = function BaseClient(opts) {
this.config = opts.config;
this.store = opts.store;
this.dataManager = opts.dataManager;
};
BaseClient.prototype.evaluateParams = function evaluateParams (feature, dataSource) {
var params = {};
var paramEntries = Object.entries(dataSource.options.params);
var state = this.store.state;
for (var i = 0, list = paramEntries; i < list.length; i += 1) {
var ref = list[i];
var key = ref[0];
var valOrGetter = ref[1];
var val = (void 0);
if (typeof valOrGetter === 'function') {
val = valOrGetter(feature, state);
} else {
val = valOrGetter;
}
params[key] = val;
}
return params;
};
BaseClient.prototype.assignFeatureIds = function assignFeatureIds (features, dataSourceKey, topicId) {
var featuresWithIds = [];
// REVIEW this was not working with Array.map for some reason
// it was returning an object when fetchJson was used
// that is now converted to an array in fetchJson
for (var i = 0; i < features.length; i++) {
var suffix = (topicId ? topicId + '-' : '') + i;
var id = "feat-" + dataSourceKey + "-" + suffix;
var feature = features[i];
// console.log(dataSourceKey, feature);
try {
feature._featureId = id;
}
catch (e) {
console.warn(e);
}
featuresWithIds.push(feature);
}
// console.log(dataSourceKey, features, featuresWithIds);
return featuresWithIds;
};
BaseClient.prototype.didFetch = function didFetch (key, status, data, targetId) {
// console.log('DID FETCH DATA:', key, targetId || '', data);
var dataOrNull = status === 'error' ? null : data;
var stateData = dataOrNull;
// if this is an array, assign feature ids
if (Array.isArray(stateData)) {
stateData = this.assignFeatureIds(stateData, key, targetId);
}
// does this data source have targets?
// const targets = this.config.dataSources[key].targets;
// put data in state
var setSourceDataOpts = {
key: key,
data: stateData,
};
var setSourceStatusOpts = {
key: key,
status: status
};
if (targetId) {
setSourceDataOpts.targetId = targetId;
setSourceStatusOpts.targetId = targetId;
}
// commit
this.store.commit('setSourceData', setSourceDataOpts);
this.store.commit('setSourceStatus', setSourceStatusOpts);
// try fetching more data
console.log('171111 base-client js is calling fetchData()');
this.fetchData();
};
// the high-level purpose of this is: take an address, geocode it, and put
// the result in state.
var GeocodeClient = (function (BaseClient$$1) {
function GeocodeClient () {
BaseClient$$1.apply(this, arguments);
}
if ( BaseClient$$1 ) GeocodeClient.__proto__ = BaseClient$$1;
GeocodeClient.prototype = Object.create( BaseClient$$1 && BaseClient$$1.prototype );
GeocodeClient.prototype.constructor = GeocodeClient;
GeocodeClient.prototype.fetch = function fetch (input) {
console.log('geocode fetch is running, input:', input);
var store = this.store;
var geocodeConfig = this.config.geocoder;
var url = geocodeConfig.url(input);
var params = geocodeConfig.params;
// update state
this.store.commit('setGeocodeStatus', 'waiting');
// console.log('GEOCODE CLIENT setting last search method to geocode');
// this.store.commit('setLastSearchMethod', 'geocode');
var success = this.success.bind(this);
var error = this.error.bind(this);
// return a promise that can accept further chaining
return axios$1.get(url, { params: params })
.then(success)
.catch(error);
};
GeocodeClient.prototype.success = function success (response) {
console.log('geocode success', response.config.url);
var store = this.store;
var data = response.data;
var url = response.config.url;
// console.log(url)
// TODO handle multiple results
if (!data.features || data.features.length < 1) {
console.log('geocode got no features', data);
return;
}
// TODO do some checking here
var feature = data.features[0];
var relatedFeatures = [];
for (var i = 0, list = data.features.slice(1); i < list.length; i += 1){
var relatedFeature = list[i];
if (!!feature.properties.address_high) {
if (relatedFeature.properties.address_high) {
relatedFeatures.push(relatedFeature);
}
} else {
relatedFeatures.push(relatedFeature);
}
}
store.commit('setGeocodeData', feature);
store.commit('setGeocodeRelated', relatedFeatures);
store.commit('setGeocodeStatus', 'success');
return feature;
};
GeocodeClient.prototype.error = function error (error$1) {
console.log('geocode error', error$1);
var store = this.store;
store.commit('setGeocodeStatus', 'error');
store.commit('setGeocodeData', null);
store.commit('setGeocodeRelated', null);
};
return GeocodeClient;
}(BaseClient));
var HttpClient = (function (BaseClient$$1) {
function HttpClient () {
BaseClient$$1.apply(this, arguments);
}
if ( BaseClient$$1 ) HttpClient.__proto__ = BaseClient$$1;
HttpClient.prototype = Object.create( BaseClient$$1 && BaseClient$$1.prototype );
HttpClient.prototype.constructor = HttpClient;
HttpClient.prototype.evaluateParams = function evaluateParams (feature, dataSource) {
var params = {};
var paramEntries = Object.entries(dataSource.options.params);
var state = this.store.state;
for (var i = 0, list = paramEntries; i < list.length; i += 1) {
var ref = list[i];
var key = ref[0];
var valOrGetter = ref[1];
var val = (void 0);
if (typeof valOrGetter === 'function') {
val = valOrGetter(feature, state);
} else {
val = valOrGetter;
}
params[key] = val;
}
return params;
};
HttpClient.prototype.fetch = function fetch (feature, dataSource, dataSourceKey, targetIdFn) {
var this$1 = this;
var params = this.evaluateParams(feature, dataSource);
// console.log('http-client fetch, feature:', feature, 'dataSource:', dataSource, 'dataSourceKey:', dataSourceKey, 'targetIdFn:', targetIdFn, 'params:', params);
var url = dataSource.url;
var options = dataSource.options;
var urlAddition = params.urlAddition;
if (urlAddition) {
url += encodeURIComponent(urlAddition);
// url += encodeURIComponent(urlAddition.properties.street_address);
}
// console.log('url', url);
// console.log('http-client fetch, feature:', feature, 'dataSource:', dataSource, 'dataSourceKey:', dataSourceKey, 'targetIdFn:', targetIdFn, 'params:', params);
var successFn = options.success;
//if (params.urlAddition)
// if the data is not dependent on other data
axios$1.get(url, { params: params }).then(function (response) {
// call success fn
var data = response.data;
if (successFn) {
data = successFn(data);
}
// get target id, if there should be one
var targetId;
if (targetIdFn) {
targetId = targetIdFn(feature);
}
this$1.dataManager.didFetchData(dataSourceKey, 'success', data, targetId);
}, function (response) {
console.log('fetch json error', response);
this$1.dataManager.didFetchData(dataSourceKey, 'error');
});
};
HttpClient.prototype.fetchMore = function fetchMore (feature, dataSource, dataSourceKey, highestPageRetrieved) {
var this$1 = this;
var params = this.evaluateParams(feature, dataSource);
params.page = highestPageRetrieved + 1;
var url = dataSource.url;
var options = dataSource.options;
var urlAddition = params.urlAddition;
if (urlAddition) {
// url += encodeURIComponent(urlAddition.properties.street_address);
url += encodeURIComponent(urlAddition);
}
var successFn = options.success;
// if the data is not dependent on other data
axios$1.get(url, { params: params }).then(function (response) {
// call success fn
var data = response.data;
if (successFn) {
data = successFn(data);
}
// console.log('data', data);
this$1.dataManager.didFetchMoreData(dataSourceKey, 'success', data);
}, function (response) {
console.log('fetch json error', response);
this$1.dataManager.didFetchMoreData(dataSourceKey, 'error');
});
};
HttpClient.prototype.fetchNearby = function fetchNearby (feature, dataSource, dataSourceKey, targetIdFn) {
var this$1 = this;
var params = this.evaluateParams(feature, dataSource);
var url = dataSource.url;
var options = dataSource.options;
// const srid = options.srid || 4326;
var table = options.table;
var dateMinNum = options.dateMinNum || null;
var dateMinType = options.dateMinType || null;
var dateField = options.dateField || null;
var successFn = options.success;
var distQuery = "ST_Distance(the_geom::geography, ST_SetSRID(ST_Point("
+ feature.geometry.coordinates[0]
+ "," + feature.geometry.coordinates[1]
+ "),4326)::geography)";
var latQuery = "ST_Y(the_geom)";
var lngQuery = "ST_X(the_geom)";
// let select = '*'
// if (calculateDistance) {
var select = "*, " + distQuery + 'as distance,' + latQuery + 'as lat, ' + lngQuery + 'as lng';
// }
params['q'] = "select" + select + " from " + table + " where " + distQuery + " < 250";
if (dateMinNum) {
params['q'] = params['q'] + " and " + dateField + " > '" + moment().subtract(dateMinNum, dateMinType).format('YYYY-MM-DD') + "'";
}
// if the data is not dependent on other data
axios$1.get(url, { params: params }).then(function (response) {
// call success fn
var data = response.data.rows;
// console.log('table and data', table, data);
if (successFn) {
data = successFn(data);
}
// get target id, if there should be one
var targetId;
if (targetIdFn) {
targetId = targetIdFn(feature);
}
this$1.dataManager.didFetchData(dataSourceKey, 'success', data, targetId);
}, function (response) {
console.log('fetch json error', response);
this$1.dataManager.didFetchData(dataSourceKey, 'error');
});
};
return HttpClient;
}(BaseClient));
var EsriClient = (function (BaseClient$$1) {
function EsriClient () {
BaseClient$$1.apply(this, arguments);
}
if ( BaseClient$$1 ) EsriClient.__proto__ = BaseClient$$1;
EsriClient.prototype = Object.create( BaseClient$$1 && BaseClient$$1.prototype );
EsriClient.prototype.constructor = EsriClient;
EsriClient.prototype.fetch = function fetch (feature, dataSource, dataSourceKey) {
var options = dataSource.options;
var url = dataSource.url;
var relationship = options.relationship;
// check if a target geometry fn was specified. otherwise, use geocode feat
var targetGeomFn = options.targetGeometry;
var geom;
if (targetGeomFn) {
var state = this.store.state;
// pass leaflet to the targetgeom function so it can construct a custom
// geometry (such as the lat lng bounds of a set of parcels) if it needs
// to. use case: fetching regmaps.
geom = targetGeomFn(state, L$1__default);
} else {
geom = feature.geometry;
}
// handle null geom
if (!geom) {
this.dataManager.didFetchData(dataSourceKey, 'error');
return;
}
this.fetchBySpatialQuery(dataSourceKey, url, relationship, geom);
};
EsriClient.prototype.fetchNearby = function fetchNearby (feature, dataSource, dataSourceKey) {
var this$1 = this;
// console.log('fetch esri nearby', feature);
// const url = dataSource.url;
var options = dataSource.options;
var dataSourceUrl = dataSource.url;
var geometryServerUrl = options.geometryServerUrl;
var calculateDistance = options.calculateDistance;
// params.geometries = `[${feature.geometry.coordinates.join(', ')}]`
// TODO get some of these values from map, etc.
var coords = feature.geometry.coordinates;
var params = {
// geometries: feature => '[' + feature.geometry.coordinates[0] + ', ' + feature.geometry.coordinates[1] + ']',
geometries: ("[" + (coords.join(', ')) + "]"),
inSR: 4326,
outSR: 4326,
bufferSR: 4326,
distances: 0.0028,
unionResults: true,
geodesic: false,
f: 'json',
};
// console.debug('esri nearby params', params);
// get buffer polygon
var bufferUrl = geometryServerUrl.replace(/\/$/, '') + '/buffer';
axios$1.get(bufferUrl, { params: params }).then(function (response) {
var data = response.data;
// console.log('did get esri nearby buffer', data);
var geoms = data.geometries || [];
var geom = geoms[0] || {};
var rings = geom.rings || [];
var xyCoords = rings[0];
// check for xy coords
if (!xyCoords) {
// we can't do anything without coords, so bail out
this$1.dataManager.didFetchData(dataSourceKey, 'error');
return;
}
var latLngCoords = xyCoords.map(function (xyCoord) { return [].concat( xyCoord ).reverse(); });
// get nearby features using buffer
var buffer = L.polygon(latLngCoords);
var map = this$1.dataManager.store.state.map.map;
// DEBUG
// buffer.addTo(map);
this$1.fetchBySpatialQuery(dataSourceKey,
dataSourceUrl,
'within',
buffer,
calculateDistance ? coords : null
);
}, function (response) {
console.log('did fetch esri nearby error', response);
this$1.dataManager.didFetchData(dataSourceKey, 'error');
});
};
EsriClient.prototype.fetchBySpatialQuery = function fetchBySpatialQuery (dataSourceKey, url, relationship, targetGeom, calculateDistancePt) {
var this$1 = this;
// console.log('fetch esri spatial query', dataSourceKey, url, relationship, targetGeom);
var query = L.esri.query({ url: url })[relationship](targetGeom);
query.run(function (error, featureCollection, response) {
// console.log('did get esri spatial query', response, error);
var features = (featureCollection || {}).features;
var status = error ? 'error' : 'success';
// calculate distance
if (calculateDistancePt) {
var from = turf.point(calculateDistancePt);
features = features.map(function (feature) {
// console.log('feat', feature);
var featureCoords = feature.geometry.coordinates;
var to = turf.point(featureCoords);
var dist = turf.distance(from, to, 'miles');
// TODO make distance units an option. for now, just hard code to ft.
var distFeet = parseInt(dist * 5280);
feature._distance = distFeet;
return feature;
});
}
this$1.dataManager.didFetchData(dataSourceKey, status, features);
});
};
return EsriClient;
}(BaseClient));
/*
The DataManager is responsible for fetching external data (mainly API responses)
and storing them in state.
The router should own an instance of DataManager and make calls to it based on
navigation events.
*/
var DataManager = function DataManager(opts) {
var store = this.store = opts.store;
var config = this.config = opts.config;
this.eventBus = opts.eventBus;
this.controller = opts.controller;
// create clients
this.clients = {};
// REVIEW do these need the store any more? or can they just pass the
// response back to this?
var clientOpts = { config: config, store: store, dataManager: this };
this.clients.geocode = new GeocodeClient(clientOpts);
this.clients.http = new HttpClient(clientOpts);
this.clients.esri = new EsriClient(clientOpts);
};
/* STATE HELPERS */
// REVIEW maybe the getXXXParcelsById methods should just take an argument
// activeParcelLayer? that's the only reason these are in here.
// activeTopicConfig() {
// const key = this.store.state.activeTopic;
// let config;
//
// // if no active topic, return null
// if (key) {
// config = this.config.topics.filter((topic) => {
// return topic.key === key;
// })[0];
// }
//
// return config || {};
// }
//
// activeParcelLayer() {
// return this.activeTopicConfig().parcels || this.config.map.defaultBasemap;
// }
/* ROUTING */
// makeHash(address, topic) {
// let hash = `/${address}`;
// if (topic) {
// hash += `/${topic}`;
// }
// return hash;
// }
// arguably this would be better off in Router, but that would create a
// circular ref router => datamanager => router. trying this for now.
// routeToAddress(input) {
// const activeTopic = this.store.state.activeTopic;
// const nextHash = this.makeHash(input, activeTopic);
//
// console.log('route to address', nextHash);
//
// window.location.hash = nextHash;
// }
//
// routeToTopic(topic) {
// // TODO add an address getter fn to config so this isn't ais-specific
// const address = this.store.state.geocode.data.properties.street_address;
// const nextHash = this.makeHash(address, topic);
//
// console.log('route to topic:', topic, `(${nextHash})`);
//
// window.location.hash = nextHash;
// }
/* DATA FETCHING METHODS */
DataManager.prototype.fetchMoreData = function fetchMoreData (dataSourceKey, highestPageRetrieved) {
var feature = this.store.state.geocode.data;
var dataSource = this.config.dataSources[dataSourceKey];
var state = this.store.state;
var type = dataSource.type;
// update secondary status to `waiting`
var setSecondarySourceStatusOpts = {
key: dataSourceKey,
secondaryStatus: 'waiting'
};
this.store.commit('setSecondarySourceStatus', setSecondarySourceStatusOpts);
console.log('INCREMENT - datamanager get 100 More was clicked, type', type, 'dataSource', dataSource, 'highestPageRetrieved', highestPageRetrieved);
switch(type) {
case 'http-get':
console.log('INCREMENT - http-get', dataSourceKey);
this.clients.http.fetchMore(feature,
dataSource,
dataSourceKey,
highestPageRetrieved);
break;
}
};
DataManager.prototype.didFetchMoreData = function didFetchMoreData (key, secondaryStatus, data) {
console.log('INCREMENT - DID FETCH More DATA:', key, secondaryStatus, data);
var dataOrNull = status === 'error' ? null : data;
var stateData = dataOrNull;
// if this is an array, assign feature ids
if (Array.isArray(stateData)) {
stateData = this.assignFeatureIds(stateData, key);
}
// console.log('stateData', stateData);
var nextPage = this.store.state.sources[key].data.page + 1;
// put data in state
var setSourceDataOpts = {
key: key,
data: stateData,
page: nextPage
};
var setSecondarySourceStatusOpts = {
key: key,
secondaryStatus: secondaryStatus
};
console.log('nextPage', nextPage, 'setSourceDataOpts', setSourceDataOpts);
// commit
this.store.commit('setSourceDataMore', setSourceDataOpts);
this.store.commit('setSecondarySourceStatus', setSecondarySourceStatusOpts);
};
DataManager.prototype.fetchData = function fetchData () {
var this$1 = this;
// console.log('\nFETCH DATA');
// console.log('-----------');
var geocodeObj = this.store.state.geocode.data;
// we always need a good geocode before we can get data, so return
// if we don't have one yet.
if (!geocodeObj) {
// console.log('fetch data but no geocode yet, returning');
return;
}
var dataSources = this.config.dataSources || {};
// get "ready" data sources (ones whose deps have been met)
for (var i$1 = 0, list$1 = Object.entries(dataSources); i$1 < list$1.length; i$1 += 1) {
var ref = list$1[i$1];
var dataSourceKey = ref[0];
var dataSource = ref[1];
var state = this$1.store.state;
var type = dataSource.type;
var targetsDef = dataSource.targets;
// console.log('key:', dataSourceKey, type);
// if the data sources specifies a features getter, use that to source
// features for evaluating params/forming requests. otherwise,
// default to the geocode result.
var targets = (void 0);
var targetIdFn = (void 0);
var targetsFn = (void 0);
if (targetsDef) {
targetsFn = targetsDef.get;
targetIdFn = targetsDef.getTargetId;
if (typeof targetsFn !== 'function') {
throw new Error(("Invalid targets getter for data source '" + dataSourceKey + "'"));
}
targets = targetsFn(state);
// check if target objs exist in state.
var targetIds = targets.map(targetIdFn);
var stateTargets = state.sources[dataSourceKey].targets;
var stateTargetIds = Object.keys(stateTargets);
// the inclusion check wasn't working because ids were strings in
// one set and ints in another, so do this.
var stateTargetIdsStr = stateTargetIds.map(String);
var shouldCreateTargets = !targetIds.every(function (targetId) {
var targetIdStr = String(targetId);
return stateTargetIdsStr.includes(targetIdStr);
});
// if not, create them.
if (shouldCreateTargets) {
// console.log('should create targets', targetIds, stateTargetIds);
this$1.store.commit('createEmptySourceTargets', {
key: dataSourceKey,
targetIds: targetIds
});
}
if (!Array.isArray(targets)) {
throw new Error('Data source targets getter should return an array');
}
} else {
targets = [geocodeObj];
}
for (var i = 0, list = targets; i < list.length; i += 1) {
// get id of target
var target = list[i];
var targetId = (void 0);
if (targetIdFn) {
targetId = targetIdFn(target);
}
// targetId && console.log('target:', targetId);
// check if it's ready
var isReady = this$1.checkDataSourceReady(dataSourceKey, dataSource, targetId);
if (!isReady) {
// console.log('not ready');
continue;
}
// update status to `waiting`
var setSourceStatusOpts = {
key: dataSourceKey,
status: 'waiting'
};
if (targetId) {
setSourceStatusOpts.targetId = targetId;
}
this$1.store.commit('setSourceStatus', setSourceStatusOpts);
// TODO do this for all targets
switch(type) {
case 'http-get':
// console.log('http-get', dataSourceKey, targetIdFn);
this$1.clients.http.fetch(target,
dataSource,
dataSourceKey,
targetIdFn);
break;
case 'http-get-nearby':
// console.log('http-get-nearby', dataSourceKey, targetIdFn)
this$1.clients.http.fetchNearby(target,
dataSource,
dataSourceKey,
targetIdFn);
break;
case 'esri':
// console.log('esri', dataSourceKey)
// TODO add targets id fn
this$1.clients.esri.fetch(target, dataSource, dataSourceKey);
break;
break;
case 'esri-nearby':
// console.log('esri-nearby', dataSourceKey)
// TODO add targets id fn
this$1.clients.esri.fetchNearby(target, dataSource, dataSourceKey);
break;
default:
throw ("Unknown data source type: " + type);
break;
}// end of switch
}// end of for targets loop
// console.log('end of targets loop for', dataSourceKey);
} // end of for dataSource loop
// console.log('end of outer loop');
};
DataManager.prototype.didFetchData = function didFetchData (key, status, data, targetId) {
// console.log('DID FETCH DATA:', key, targetId || '', data);
var dataOrNull = status === 'error' ? null : data;
var stateData = dataOrNull;
// if this is an array, assign feature ids
if (Array.isArray(stateData)) {
stateData = this.assignFeatureIds(stateData, key, targetId);
}
// does this data source have targets?
// const targets = this.config.dataSources[key].targets;
// put data in state
var setSourceDataOpts = {
key: key,
data: stateData,
};
var setSourceStatusOpts = {
key: key,
status: status
};
if (targetId) {
setSourceDataOpts.targetId = targetId;
setSourceStatusOpts.targetId = targetId;
}
// commit
this.store.commit('setSourceData', setSourceDataOpts);
this.store.commit('setSourceStatus', setSourceStatusOpts);
// try fetching more data
// console.log('171111 data-manager.js line 319 - didFetchData - is calling fetchData on targetId', targetId, 'key', key);
this.fetchData();
};
DataManager.prototype.resetData = function resetData () {
var this$1 = this;
var dataSources = this.config.dataSources || {};
for (var i = 0, list = Object.keys(dataSources); i < list.length; i += 1) {
var dataSourceKey = list[i];
var dataSource = dataSources[dataSourceKey];
var targetsDef = dataSource.targets;
// null out existing data in state
if (targetsDef) {
this$1.store.commit('clearSourceTargets', {
key: dataSourceKey
});
} else {
this$1.store.commit('setSourceData', {
key: dataSourceKey,
data: null
});
this$1.store.commit('setSourceStatus', {
key: dataSourceKey,
status: null
});
}
}
};
DataManager.prototype.checkDataSourcesFetched = function checkDataSourcesFetched (paths) {
if ( paths === void 0 ) paths = [];
// console.log('check data sources fetched', paths);
var state = this.store.state;
return paths.every(function (path) {
// deps can be deep keys, e.g. `dor.parcels`. split on periods to get
// a sequence of keys.
var pathKeys = path.split('.');
// TODO/TEMP restructure state so parcels and geocode live in
// state.sources? the following targets the dorDocuments data source.
var isDorParcels = (pathKeys.length === 1
&& pathKeys[0] === 'dorParcels');
if (isDorParcels) {
return state.dorParcels.status === 'success';
}
// traverse state to get the parent of the data object we need to
// check.
var stateObj = pathKeys.reduce(function (acc, pathKey) {
return acc[pathKey];
}, state);
return stateObj.status === 'success';
});
};
DataManager.prototype.checkDataSourceReady = function checkDataSourceReady (key, options, targetId) {
// console.log(`check data source ready: ${key} ${targetId || ''}`, options);
var deps = options.deps;
// console.log('deps', deps);
var depsMet = this.checkDataSourcesFetched(deps);
// console.log('depsMet', depsMet);
var isReady = false;
// if data deps have been met
if (depsMet) {
// get the target obj
var targetObj = this.store.state.sources[key];
if (targetId) {
targetObj = targetObj.targets[targetId];
}
// if the target obj has a status of null, this data source is ready.
isReady = !targetObj.status;
}
// console.log('checkDataSourceReady isReady:', isReady);
return isReady;
};
DataManager.prototype.assignFeatureIds = function assignFeatureIds (features, dataSourceKey, topicId) {
var featuresWithIds = [];
// REVIEW this was not working with Array.map for some reason
// it was returning an object when fetchJson was used
// that is now converted to an array in fetchJson
for (var i = 0; i < features.length; i++) {
var suffix = (topicId ? topicId + '-' : '') + i;
var id = "feat-" + dataSourceKey + "-" + suffix;
var feature = features[i];
// console.log(dataSourceKey, feature);
try {
feature._featureId = id;
}
catch (e) {
console.warn(e);
}
featuresWithIds.push(feature);
}
// console.log(dataSourceKey, features, featuresWithIds);
return featuresWithIds;
};
DataManager.prototype.evaluateParams = function evaluateParams (feature, dataSource) {
var params = {};
var paramEntries = Object.entries(dataSource.options.params);
var state = this.store.state;
for (var i = 0, list = paramEntries; i < list.length; i += 1) {
var ref = list[i];
var key = ref[0];
var valOrGetter = ref[1];
var val = (void 0);
if (typeof valOrGetter === 'function') {
val = valOrGetter(feature, state);
} else {
val = valOrGetter;
}
params[key] = val;
}
return params;
};
/* GEOCODING */
DataManager.prototype.geocode = function geocode (address) {
var didGeocode = this.didGeocode.bind(this);
// this.clients.geocode.fetch(address, didGeocode);
return this.clients.geocode.fetch(address).then(didGeocode);
};
DataManager.prototype.didGeocode = function didGeocode (feature) {
var this$1 = this;
console.log('DataManager.didGeocode:', feature);
this.controller.router.didGeocode();
// emit event to event bus
this.eventBus.$emit('geocodeResult', feature);
var activeParcelLayer = this.store.state.activeParcelLayer;
var lastSearchMethod = this.store.state.lastSearchMethod;
var configForActiveParcelLayer = this.config.parcels[activeParcelLayer];
// // const multipleAllowed = configForParcelLayer.multipleAllowed;
// const geocodeField = configForParcelLayer.geocodeField;
var parcelLayers = Object.keys(this.config.parcels || {});
var otherParcelLayers = Object.keys(this.config.parcels || {});
otherParcelLayers.splice(otherParcelLayers.indexOf(activeParcelLayer), 1);
console.log('didGeocode - activeParcelLayer:', activeParcelLayer, 'parcelLayers:', parcelLayers, 'otherParcelLayers:', otherParcelLayers);
// if it is a dor parcel query, and the geocode fails, coordinates can still be used
// to get dor parcels which are not in ais
// set coords to the ais coords OR the click if there is no ais result
var coords, lat, lng, latlng;
// if geocode fails
if (!feature) {
console.log('didGeocode - no geom', feature);
if (lastSearchMethod === 'reverseGeocode') {
var clickCoords = this.store.state.clickCoords;
coords = [clickCoords.lng, clickCoords.lat];
var assign;
(assign = coords, lng = assign[0], lat = assign[1]);
latlng = L$1__default.latLng(lat, lng);
}
// if geocode succeeds
} else {
console.log('didGeocode - GEOM', feature);
coords = feature.geometry.coordinates;
var assign$1;
(assign$1 = coords, lng = assign$1[0], lat = assign$1[1]);
latlng = L$1__default.latLng(lat, lng);
}
// if (coords) {
// const [lng, lat] = coords;
// const latlng = L.latLng(lat, lng);
// }
// all of this happens whether geocode failed or succeeded
// search box or onload - get parcels by id
// (unless it fails and you are allowed to get them by LatLng on failure)
if (lastSearchMethod === 'geocode') {
if (feature) {
console.log('didGeocode lastSearchMethod:', lastSearchMethod, '- attempting to get all parcel layers:', parcelLayers, ' by ID');
// loop through the parcels, and get them by their ids
for (var i = 0, list = parcelLayers; i < list.length; i += 1) {
var parcelLayer = list[i];
var configForParcelLayer = this$1.config.parcels[parcelLayer];
var parcelIdInGeocoder = configForParcelLayer.parcelIdInGeocoder;
var parcelId = feature.properties[parcelIdInGeocoder];
if (parcelId && parcelId.length > 0) {
this$1.getParcelsById(parcelId, parcelLayer);
} else {
if (configForParcelLayer.getByLatLngIfIdFails) {
console.log(parcelLayer, 'Id failed - had to get by LatLng');
this$1.getParcelsByLatLng(latlng, parcelLayer);
}
}
}
}
// map-click - get pwd and dor parcels (whichever has not already been found) by latlng
// this is needed because it will not automatically get the dor parcels in case it does not find a pwd parcel
// and vice versa
} else if (lastSearchMethod === 'reverseGeocode') {
if (feature) {
console.log('didGeocode lastSearchMethod:', lastSearchMethod, 'feature', feature, '- getting other parcel layers by id or latlng');
for (var i$1 = 0, list$1 = otherParcelLayers; i$1 < list$1.length; i$1 += 1) {
var otherParcelLayer = list$1[i$1];
var configForOtherParcelLayer = this$1.config.parcels[otherParcelLayer];
var parcelIdInGeocoder$1 = configForOtherParcelLayer.parcelIdInGeocoder;
var parcelId$1 = feature.properties[parcelIdInGeocoder$1];
if (parcelId$1 && parcelId$1.length > 0) {
this$1.getParcelsById(parcelId$1, otherParcelLayer);
} else {
if (configForOtherParcelLayer.getByLatLngIfIdFails) {
console.log(otherParcelLayer, 'Id failed - had to get by LatLng');
this$1.getParcelsByLatLng(latlng, otherParcelLayer);
}
}
}
} else {
console.log('didGeocode lastSearchMethod:', lastSearchMethod, 'NO feature', feature);
var geocodeFailAttemptParcel = configForActiveParcelLayer.geocodeFailAttemptParcel;
if (geocodeFailAttemptParcel) {
console.log('ran ais on a dor parcel and got no response - should try pwd parcel?', geocodeFailAttemptParcel);
var otherParcel = this.store.state.parcels[geocodeFailAttemptParcel];
console.log('otherParcel:', otherParcel);
if (otherParcel) {
var configForOtherParcelLayer$1 = this.config.parcels[geocodeFailAttemptParcel];
var geocodeField = configForOtherParcelLayer$1.geocodeField;
console.log('running ais again on the pwd parcel', otherParcel.properties[geocodeField]);
this.store.commit('setLastSearchMethod', 'reverseGeocode-secondAttempt');
this.geocode(otherParcel.properties[geocodeField]);
}
}
}
}
// only recenter the map on geocode
if (lastSearchMethod === 'geocode') {
this.store.commit('setMapCenter', coords);
this.store.commit('setMapZoom', 19);
}
// reset data only when not a rev geocode second attempt
if (lastSearchMethod !== 'reverseGeocode-secondAttempt') {
this.resetData();
}
// if it is not an intersection, fetch new data
if (feature) {
if (feature.street_address) {
return;
} else if (feature.properties.street_address) {
console.log('171111 data-manager.js line 571 - didGeocode - is calling fetchData on feature w address', feature.properties.street_address);
this.fetchData();
}
} else {
console.log('171111 data-manager.js line 575 - didGeocode - is calling fetchData, no feature');
this.fetchData();
}
}; // end didGeocode
DataManager.prototype.getParcelsById = function getParcelsById (id, parcelLayer) {
// console.log('getParcelsById', parcelLayer);
var url = this.config.map.featureLayers[parcelLayer+'Parcels'].url;
var configForParcelLayer = this.config.parcels[parcelLayer];
var geocodeField = configForParcelLayer.geocodeField;
var parcelQuery = L$1__default.esri.query({ url: url });
parcelQuery.where(geocodeField + " = '" + id + "'");
parcelQuery.run((function(error, featureCollection, response) {
// console.log('parcelQuery ran, activeParcelLayer:', activeParcelLayer);
this.didGetParcels(error, featureCollection, response, parcelLayer);
}).bind(this)
);
};
DataManager.prototype.getParcelsByLatLng = function getParcelsByLatLng (latlng, parcelLayer, fetch) {
console.log('171111 getParcelsByLatLng', parcelLayer, 'fetch', fetch);
var url = this.config.map.featureLayers[parcelLayer+'Parcels'].url;
var parcelQuery = L$1__default.esri.query({ url: url });
parcelQuery.contains(latlng);
var test = 5;
parcelQuery.run((function(error, featureCollection, response) {
console.log('171111 test', test, 'fetch', fetch);
this.didGetParcels(error, featureCollection, response, parcelLayer, fetch);
}).bind(this)
);
};
DataManager.prototype.didGetParcels = function didGetParcels (error, featureCollection, response, parcelLayer, fetch) {
var this$1 = this;
console.log('171111 didGetParcels is running parcelLayer', parcelLayer, 'fetch', fetch);
var configForParcelLayer = this.config.parcels[parcelLayer];
var multipleAllowed = configForParcelLayer.multipleAllowed;
var geocodeField = configForParcelLayer.geocodeField;
var otherParcelLayers = Object.keys(this.config.parcels || {});
otherParcelLayers.splice(otherParcelLayers.indexOf(parcelLayer), 1);
var lastSearchMethod = this.store.state.lastSearchMethod;
var activeParcelLayer = this.store.state.activeParcelLayer;
// console.log('didGetParcels - parcelLayer:', parcelLayer, 'otherParcelLayers:', otherParcelLayers, 'configForParcelLayer:', configForParcelLayer);
if (error) {
console.warn('didGetParcels error', parcelLayer, error);
// update state
if (configForParcelLayer.clearStateOnError) {
// this.store.commit('setParcelData', { parcelLayer, [] });
// this.store.commit('setParcelStatus', { parcelLayer }, 'error' });
}
return;
}
if (!featureCollection) {
console.warn('didGetParcel', parcelLayer, 'got no featureCollection');
return;
}
var features = featureCollection.features;
if (features.length === 0) {
console.warn('didGetParcels:', parcelLayer,' got a parcel but no features');
return;
}
var featuresSorted = this.sortDorParcelFeatures(features);
var feature;
if (!multipleAllowed) {
feature = features[0];
if (features.length > 1) {
console.debug('got more than one', parcelLayer, 'parcel:', features);
}
// dor
} else {
feature = featuresSorted[0];
}
// at this point there is definitely a feature or features - put it in state
this.setParcelsInState(parcelLayer, multipleAllowed, feature, featuresSorted);
// geocode
// console.log('didGetParcels activeParcelLayer:', activeParcelLayer, 'parcelLayer:', parcelLayer);
var shouldGeocode = (
activeParcelLayer === parcelLayer &&
lastSearchMethod === 'reverseGeocode'
);
// console.log('didGetParcels - shouldGeocode is', shouldGeocode);
if (shouldGeocode) {
// since we definitely have a new parcel, and will attempt to geocode it:
// 1. wipe out state data on other parcels
// 2. attempt to replace
// if (lastSearchMethod === 'reverseGeocode') { // || !configForParcelLayer.wipeOutOtherParcelsOnReverseGeocodeOnly) {
var clickCoords = this.store.state.clickCoords;
var coords = [clickCoords.lng, clickCoords.lat];
var lng = coords[0];
var lat = coords[1];
var latlng = L$1__default.latLng(lat, lng);
// console.log('didGetParcels is wiping out the', otherParcelLayers, 'parcels in state');
for (var i = 0, list = otherParcelLayers; i < list.length; i += 1) {
var otherParcelLayer = list[i];
var configForOtherParcelLayer = this$1.config.parcels[otherParcelLayer];
var otherMultipleAllowed = configForOtherParcelLayer.multipleAllowed;
this$1.setParcelsInState(otherParcelLayer, otherMultipleAllowed, null, []);
console.log('171111 - line 680 running getParcelsByLatLng');
this$1.getParcelsByLatLng(latlng, otherParcelLayer, 'noFetch');
}
// console.log('didGetParcels - shouldGeocode is running');
var props = feature.properties || {};
var id = props[geocodeField];
if (id) { this.controller.router.routeToAddress(id); }
} else {
console.log('171111 data-manager.js line 688 - didGetParcels - if shouldGeocode is NOT running');
// if (lastSearchMethod != 'reverseGeocode-secondAttempt') {
// if (fetch !== 'noFetch') {
if (fetch !== 'noFetch' && lastSearchMethod != 'reverseGeocode-secondAttempt') {
console.log('171111 data-manager.js line 688 - didGetParcels - is calling fetchData() on feature w address', feature.properties.street_address);
this.fetchData();
}
}
};
DataManager.prototype.setParcelsInState = function setParcelsInState (parcelLayer, multipleAllowed, feature, featuresSorted) {
var payload;
// pwd
if (!multipleAllowed) {
payload = {
parcelLayer: parcelLayer,
multipleAllowed: multipleAllowed,
data: feature
};
// dor
} else {
payload = {
parcelLayer: parcelLayer,
multipleAllowed: multipleAllowed,
data: featuresSorted,
status: 'success',
activeParcel: feature ? feature.id : null,
activeAddress: feature ? concatDorAddress(feature) : null,
activeMapreg: feature ? feature.properties.MAPREG : null
};
}
// update state
this.store.commit('setParcelData', payload);
};
DataManager.prototype.sortDorParcelFeatures = function sortDorParcelFeatures (features) {
// map parcel status to a numeric priority
// (basically so remainders come before inactives)
var STATUS_PRIORITY = {
1: 1,
2: 3,
3: 2
};
// first sort by mapreg (descending)
features.sort(function (a, b) {
var mapregA = a.properties.MAPREG;
var mapregB = b.properties.MAPREG;
if (mapregA < mapregB) { return 1; }
if (mapregA > mapregB) { return -1; }
return 0;
});
// then sort by status
features.sort(function (a, b) {
var statusA = STATUS_PRIORITY[a.properties.STATUS];
var statusB = STATUS_PRIORITY[b.properties.STATUS];
if (statusA < statusB) { return -1; }
if (statusA > statusB) { return 1; }
return 0;
});
return features;
};
/*
The Controller handles events from the UI that have some effect on routing or
data fetching. It is a "thin" class that mostly proxies events to the router and
data manager, and facilitates communication between them.
*/
var Controller = function Controller(opts) {
var store = this.store = opts.store;
var config = this.config = opts.config;
var eventBus = this.eventBus = opts.eventBus;
this.history = window.history;
// the router and data manager need a ref to the controller
opts.controller = this;
// create data manager
var dataManager = this.dataManager = new DataManager(opts);
// create router
opts.dataManager = dataManager;
this.router = new Router(opts);
};
/*
EVENT HANDLERS
*/
Controller.prototype.appDidLoad = function appDidLoad () {
// route once on load
this.router.hashChanged();
};
Controller.prototype.getMoreRecords = function getMoreRecords (dataSource, highestPageRetrieved) {
this.dataManager.fetchMoreData(dataSource, highestPageRetrieved);
};
Controller.prototype.handleSearchFormSubmit = function handleSearchFormSubmit (e) {
var this$1 = this;
console.log('handle search form submit', e, this);
var input = e.target[0].value;
this.store.commit('setLastSearchMethod', 'geocode');
this.store.commit('setClickCoords', null);
this.store.commit('setGeocodeStatus', null);
this.store.commit('setGeocodeInput', input);
// clear out state
var parcelLayers = Object.keys(this.config.parcels || {});
for (var i = 0, list = parcelLayers; i < list.length; i += 1) {
var parcelLayer = list[i];
var configForParcelLayer = this$1.config.parcels[parcelLayer];
var multipleAllowed = configForParcelLayer.multipleAllowed;
var payload = (void 0);
// pwd
if (!multipleAllowed) {
payload = {
parcelLayer: parcelLayer,
multipleAllowed: multipleAllowed,
data: null
};
// dor
} else {
payload = {
parcelLayer: parcelLayer,
multipleAllowed: multipleAllowed,
data: [],
status: null,
activeParcel: null,
activeAddress: null,
activeMapreg: null
};
}
// update state
this$1.store.commit('setParcelData', payload);
}
// tell router
this.router.routeToAddress(input);
};
Controller.prototype.handleMapClick = function handleMapClick (e) {
console.log('handle map click', e, this);
// TODO figure out why form submits via enter key are generating a map
// click event and remove this
if (e.originalEvent.keyCode === 13) {
return;
}
this.store.commit('setLastSearchMethod', 'reverseGeocode');
this.store.commit('setClickCoords', null);
// get parcels that intersect map click xy
var latLng = e.latlng;
this.store.commit('setClickCoords', latLng);
this.store.commit('setGeocodeInput', null);
// if click is on a topic with pwd parcels, you do not want to find dor parcels unless the
// click was actually on a pwd parcel that could be geocoded, because just running
// getDorParcelsByLatLng changes the Deeds topic in the UI, and the click could have been
// on the road
// there is a callback after geocode to get dor parcels
var activeParcelLayer = this.store.state.activeParcelLayer;
// console.log('activeParcelLayer', activeParcelLayer);
this.dataManager.getParcelsByLatLng(latLng, activeParcelLayer);
};
// util for making sure topic headers are visible after clicking on one
// adapted from: https://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport/7557433#7557433
// REVIEW this is returning true even when the topic header isn't visible,
// probably because of a timing issue. it's good enough without this check for
// now. commenting out.
// isElementInViewport(el) {
// const rect = el.getBoundingClientRect();
//
// // check visibility of each side of bounding rect
// const topVisible = rect.top >= 0;
// const leftVisible = rect.left >= 0;
// const bottomVisible = rect.bottom <= (
// window.innerHeight || document.documentElement.clientHeight
// );
// const rightVisible = rect.right <= (
// window.innerWidth || document.documentElement.clientWidth
// );
//
// return (topVisible && leftVisible && bottomVisible && rightVisible);
// }
Controller.prototype.handleTopicHeaderClick = function handleTopicHeaderClick (topic) {
// console.log('Controller.handleTopicHeaderClick', topic);
this.router.routeToTopic(topic);//.then(function(targetExists) {
/*
scroll to top of topic header
*/
// get element
var els = document.querySelectorAll(("[data-topic-key='" + topic + "']"));
var el = els.length === 1 && els[0];
// handle null el - this shouldn't happen, but just in case
if (!el) { return; }
Vue.nextTick(function () {
// REVIEW this check is returning true even when the header el isn't
// really visible, probbaly because of a timing issue. it works well
// enough without it. commenting out for now.
// const visible = this.isElementInViewport(el);
// if (!visible) {
el.scrollIntoView();
// }
});
};
Controller.prototype.goToDefaultAddress = function goToDefaultAddress (address) {
this.router.routeToAddress(address);
};
function controllerMixin(Vue$$1, opts) {
var controller = new Controller(opts);
Vue$$1.mixin({
created: function created() {
this.$controller = controller;
}
});
}
// helper function to auto-assign ids to horizontal tables
function assignTableIds(comps) {
for (var i = 0, list = comps; i < list.length; i += 1) {
var comp = list[i];
var options = comp.options || {};
var innerComps = options.components;
// if this is a "group" component, recurse
if (innerComps) {
assignTableIds(innerComps);
return;
}
// skip comps that aren't horizontal tables
if (comp.type !== 'horizontal-table') {
continue;
}
var id = generateUniqueId();
comp._id = id;
// the id also needs to get passed to the horizontal table component, so
// use the options object.
comp.options.tableId = id;
}
}
function assignTableGroupIds(comps) {
for (var i = 0, list = comps; i < list.length; i += 1) {
var comp = list[i];
var options = comp.options || {};
var innerComps = options.components;
// if this is a "group" component, recurse
if (!innerComps) {
continue;
}
// skip comps that aren't horizontal table groups
if (comp.type !== 'table-group') {
continue;
}
var id = generateUniqueId();
comp._id = id;
// the id also needs to get passed to the horizontal table component, so
// use the options object.
comp.options.tableGroupId = id;
}
}
function main (clientConfig) {
var baseConfigUrl = clientConfig.baseConfig;
// create a global event bus used to proxy events to the mapboard host
var eventBus = new Vue();
Vue.prototype.$eventBus = eventBus;
// get base config
return axios.get(baseConfigUrl).then(function (response) {
var data = response.data;
// parse raw js. yes, it's ok to use eval :)
// http://stackoverflow.com/a/87260/676001
var baseConfig = eval(data);
// deep merge base config and client config
//const config = mergeDeep(clientConfig, baseConfig);
var config = mergeDeep(baseConfig, clientConfig);
// assign table ids
for (var i = 0, list = config.topics; i < list.length; i += 1) {
var topic = list[i];
assignTableIds(topic.components);
assignTableGroupIds(topic.components);
}
// make config accessible from each component via this.$config
Vue.use(configMixin, config);
// create store
var store = createStore(config);
// create and globally mix in data manager
// const dataManager = new DataManager({ store, config, eventBus });
// REVIEW there might be a cleaner way of doing this:
// https://vuejs.org/v2/guide/plugins.html
// Vue.use((Vue, dataManager) => {
// Vue.mixin({
// created() {
// this.$dataManager = dataManager;
// }
// });
// }, dataManager);
// create router
// Vue.use(routerMixin, { config, store, eventBus, dataManager });
// mix in controller
Vue.use(controllerMixin, { config: config, store: store, eventBus: eventBus });
// mount main vue
var vm = new Vue({
el: config.el || '#mapboard',
render: function (h) { return h(Mapboard); },
store: store
});
// bind mapboard events to host app
var events = config.events || {};
for (var i$1 = 0, list$1 = Object.keys(events); i$1 < list$1.length; i$1 += 1) {
var eventName = list$1[i$1];
var callback = events[eventName];
vm.$eventBus.$on(eventName, callback);
}
// event api for host apps
// this doesn't work now that we're getting the base config
// asynchronously. see above for workaround.
// REVIEW it would be nice to return the jquery ajax deferred and have the
// client app call .then() on it.
// return {
// on(eventName, callback) {
// vm.$eventBus.$on(eventName, callback);
// return this;
// },
// off(eventName, callback) {
// vm.$eventBus.$off(eventName, callback);
// return this;
// }
// };
}).catch(function (err) {
console.error('Error loading base config:', err);
});
}
exports['default'] = main;
exports.Mapboard = Mapboard;
Object.defineProperty(exports, '__esModule', { value: true });
})));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment