Are you part of our mailing list? SIGN UP HERE!","clickthroughUrl":{"url":"/contact","newWindow":false}},"popupOverlaySettings":{"style":2,"showOnScroll":true,"scrollPercentage":25,"showOnTimer":true,"timerDelay":5000,"showUntilSignup":true,"displayFrequency":1,"enableMobile":true,"enabledPages":[],"showOnAllPages":true,"version":3},"commentLikesAllowed":true,"commentAnonAllowed":true,"commentThreaded":true,"commentApprovalRequired":false,"commentAvatarsOn":true,"commentSortType":2,"commentFlagThreshold":0,"commentFlagsAllowed":true,"commentEnableByDefault":false,"commentDisableAfterDaysDefault":0,"disqusShortname":"","commentsEnabled":true,"contactPhoneNumber":"","businessHours":{"monday":{"text":"","ranges":[{}]},"tuesday":{"text":"","ranges":[{}]},"wednesday":{"text":"","ranges":[{}]},"thursday":{"text":"","ranges":[{}]},"friday":{"text":"","ranges":[{}]},"saturday":{"text":"","ranges":[{}]},"sunday":{"text":"","ranges":[{}]}},"storeSettings":{"returnPolicy":null,"termsOfService":null,"privacyPolicy":null,"expressCheckout":false,"continueShoppingLinkUrl":"/","useLightCart":false,"showNoteField":false,"shippingCountryDefaultValue":"US","billToShippingDefaultValue":false,"showShippingPhoneNumber":true,"isShippingPhoneRequired":false,"showBillingPhoneNumber":true,"isBillingPhoneRequired":false,"currenciesSupported":["USD","AUD","CAD","CHF","CZK","DKK","EUR","GBP","HKD","ILS","MXN","MYR","NOK","NZD","PHP","PLN","RUB","SEK","SGD","THB"],"defaultCurrency":"USD","selectedCurrency":"USD","measurementStandard":1,"showCustomCheckoutForm":false,"checkoutPageMarketingOptInEnabled":false,"enableMailingListOptInByDefault":false,"sameAsRetailLocation":false,"merchandisingSettings":{"scarcityEnabledOnProductItems":false,"scarcityEnabledOnProductBlocks":false,"scarcityMessageType":"DEFAULT_SCARCITY_MESSAGE","scarcityThreshold":10,"multipleQuantityAllowedForServices":true,"restockNotificationsEnabled":false,"restockNotificationsMailingListSignUpEnabled":false,"relatedProductsEnabled":false,"relatedProductsOrdering":"random","soldOutVariantsDropdownDisabled":false,"productComposerOptedIn":true,"productComposerABTestOptedOut":false,"productReviewsEnabled":false,"displayImportedProductReviewsEnabled":false,"hasOptedToCollectNativeReviews":false},"minimumOrderSubtotalEnabled":false,"minimumOrderSubtotal":{"currency":"USD","value":"0.00"},"isLive":true,"multipleQuantityAllowedForServices":true},"useEscapeKeyToLogin":true,"ssBadgeType":1,"ssBadgePosition":4,"ssBadgeVisibility":1,"ssBadgeDevices":1,"pinterestOverlayOptions":{"mode":"disabled"},"ampEnabled":false,"userAccountsSettings":{"loginAllowed":false,"signupAllowed":false}},"cookieSettings":{"isCookieBannerEnabled":false,"isRestrictiveCookiePolicyEnabled":false,"cookieBannerText":"","cookieBannerTheme":"","cookieBannerVariant":"","cookieBannerPosition":"","cookieBannerCtaVariant":"","cookieBannerCtaText":"","cookieBannerAcceptType":"OPT_IN","cookieBannerOptOutCtaText":"","cookieBannerHasOptOut":false,"cookieBannerHasManageCookies":true,"cookieBannerManageCookiesLabel":"","cookieBannerSavedPreferencesText":"","cookieBannerSavedPreferencesLayout":"PILL"},"websiteCloneable":false,"collection":{"title":"Database","id":"630b2e88cc5a253646020589","fullUrl":"/","type":10,"permissionType":1},"subscribed":false,"appDomain":"squarespace.com","templateTweakable":true,"tweakJSON":{"autohide-footer":"true","product-gallery-auto-crop":"false","product-image-auto-crop":"false","project-hover-panning":"false","project-hover-zoom":"false","project-squares":"false","projectCoverWidth":"420px","tweak-v1-related-products-title-spacing":"50px"},"templateId":"4fba57fde4b0f79d428daa8b","templateVersion":"7","pageFeatures":[1,2,4],"gmRenderKey":"QUl6YVN5Q0JUUk9xNkx1dkZfSUUxcjQ2LVQ0QWVUU1YtMGQ3bXk4","templateScriptsRootUrl":"https://static1.squarespace.com/static/ta/4fba5732e4b0935259821a4a/1838/scripts/","impersonatedSession":false,"tzData":{"zones":[[0,"EU","GMT/BST",null]],"rules":{"EU":[[1981,"max",null,"Mar","lastSun","1:00u","1:00","S"],[1996,"max",null,"Oct","lastSun","1:00u","0",null]]}},"showAnnouncementBar":true,"recaptchaEnterpriseContext":{"recaptchaEnterpriseSiteKey":"6LdDFQwjAAAAAPigEvvPgEVbb7QBm-TkVJdDTlAv"},"i18nContext":{"timeZoneData":{"id":"Europe/London","name":"Greenwich Mean Time"}},"env":"PRODUCTION"};
Welcome to the Women Photograph database! Please use the menu below to search for photographers by name or location, or filter according to region, expertise, skills & certifications, or demographic data. If you are a photo editor, curator, or art director looking for access to our private database, which has even more info available, please fill out this form and we’ll get back to you as soon as we can.
CLEAR ALL CATEGORIES
▼Region
Clear
▼Expertise
Clear
▼Skills & Certifications
Clear
▼Gender / Sex Identity
Clear
▼Race / Ethnicity
Clear
There are
a lot of
photographers in this database.
`,
);
// Add the name of the photographer to the card.
const p1 = card
.select('.db-card__info')
.append('div')
.attr('class', 'db-info db-info__p1 db-info__line')
.html(`${first_name(datum)} ${last_name(datum)}`);
// If we have pronoun data, add it.
if (pronouns(datum).length > 0) {
p1.append('span')
.attr('class', 'db-info__pronouns')
.text(` (${pronouns(datum)})`);
}
// Work on adding the location of the photographer.
const p2 = card.select('.db-card__info').append('div').attr('class', 'db-info db-info__p2');
// Group location data.
let location1 = [city_1(datum).trim(), area_1(datum).trim(), country_1(datum).trim()];
let location2 = [city_2(datum).trim(), area_2(datum).trim(), country_2(datum).trim()];
// Substitute Area names if we have locations in Canada or USA.
if ([location1[2], location2[2]].includes('Canada')) {
if (location1[2] == 'Canada') {
location1[1] = canada_areas[location1[1]];
}
if (location2[2] == 'Canada') {
location2[1] = canada_areas[location2[1]];
}
}
if ([location1[2], location2[2]].includes('USA')) {
if (location1[2] == 'USA') {
location1[1] = america_states[location1[1]];
}
if (location2[2] == 'USA') {
location2[1] = america_states[location2[1]];
}
}
if ([location1[2], location2[2]].includes('Australia')) {
if (location1[2] == 'Australia') {
location1[1] = australia_areas[location1[1]];
}
if (location2[2] == 'Australia') {
location2[1] = australia_areas[location2[1]];
}
}
// Concatenate the location data.
const primary_loc = location1
.filter(d => d != '')
.join(', ')
.trim();
const secondary_loc = location2
.filter(d => d != '')
.join(', ')
.trim();
// Add location data to the card.
[primary_loc, secondary_loc].forEach(location => {
if (location.length > 0) {
p2.append('div').attr('class', 'db-info__location db-info__line').text(location);
}
});
// Add website & instagram if available.
const p3 = card.select('.db-card__info').append('div').attr('class', 'db-info db-info__p3');
if (_web.length > 0) {
p3.append('a')
.attr('class', 'db-info__website db-info__line')
.attr('href', working_url)
.attr('target', '_blank')
.text(display_url);
}
const instagram_handle = instagram(datum).toLowerCase().replace(/\/$/, '').replace(/@/g, '');
if (instagram_handle.length > 1) {
p3.append('a')
.attr('class', 'db-info__instagram db-info__line')
.attr('href', `https://www.instagram.com/${instagram_handle}`)
.attr('target', '_blank')
.text(`@${instagram_handle}`);
}
// return card;
}
function controlCenter(val, action_source) {
// Pre-process the input value based on the action_source.
if (action_source == 'filter') {
// We're going to be filtering. Update the chain, and clear buttons. Also toggle the filtering flag based on the db_filter_chain.
const id = val;
updateFilterChain(id);
} else if (action_source == 'search') {
// A search button was triggered. Let's update the search term.
db_search_term = val;
} else if (action_source == 'clear') {
// clear the appropriate filters.
const r = val.split('-')[1];
clearSection(r);
}
// Look through and update the UI.
toggleClearButtons();
// Work with the data.
db_active_photogs = data;
if (db_filter_chain.length > 0) {
filterPhotographers();
}
if (db_search_term.length >= 0) {
searchPhotographers();
}
// Update the gallery & text after running one or two of the above blocks.
updateText(db_active_photogs);
updateGallery(db_active_photogs);
}
function updateFilterChain(id) {
const filter_option = d3.select(`#${id}`);
const inner_btn = filter_option.select('.db-option__inner');
// Check if ID is already in the chain. If yes, remove it and make the option inactive. If not, add it and make the option active.
if (db_filter_chain.includes(id)) {
// ID is in the chain. Remove it.
db_filter_chain = db_filter_chain.filter(d => d != id);
inner_btn.classed('db-option__inner--active', false);
} else {
// ID is not in the chain. Add it.
db_filter_chain.push(id);
inner_btn.classed('db-option__inner--active', true);
}
}
function toggleClearButtons() {
// Toggle the clear buttons for categories and overall search based on the chain. Use the db_filter_chain to determine which the clear button should be visible.
d3.selectAll('.db-group__clear').classed('db-invisible', true);
if (db_filter_chain.length > 0) {
let active_categories = [];
db_filter_chain.forEach(elt => {
const c = elt.split('-')[0];
// add category c if it's not in the active_categories array
if (!active_categories.includes(c)) {
active_categories.push(c);
}
});
// Show the clear button for each item in active_categories.
active_categories.forEach(c => {
d3.select(`#clear-${c}`).classed('db-invisible', false);
});
// If we have at least 2 categories, show the clear button for the overall database.
if (active_categories.length >= 2) {
d3.select('#clear-db').classed('db-invisible', false);
}
}
}
function filterPhotographers() {
// Go through db_filter_chain and filter the data based on the chain. If we hit 0 at any point, break out.
let temp = db_active_photogs;
for (i = 0; i < db_filter_chain.length; i++) {
// Decompose the filter chain item. It's in the form of category-value.
const [category, value] = db_filter_chain[i].split('-');
const category_index = +category[category.length - 1];
let key = db_dictionary[category].options[value];
let acc = filter_accessors[category_index - 1];
// We shortened some keys visually. Let's expand them here when looking at the data.
if (key == 'HEFAT') {
key = 'HEFAT (Hostile Environment & First Aid Training)';
}
if (key == 'SCUBA Certification') {
key = 'Scuba Diving Certification';
}
if (category_index == 3 && key == 'Owns PPE') {
// For "Owns PPE" we have a separate column in the data set that we'll use.
temp = temp.filter(d => owns_ppe(d) == 'Yes');
} else if (category_index == 5 && key == 'Other') {
// For "Other" we will get rid of anything that isn't "Other" from the data.
let race_ethnicity_options = db_dictionary['filter5'].options;
let exclude = race_ethnicity_options.filter(d => d != 'Other');
let temp2 = temp;
exclude.forEach(elt => {
temp2 = temp2.filter(d => acc(d) != elt);
});
temp = temp2;
} else {
// This is the default, general case of filtering.
temp = temp.filter(d => {
const j = acc(d)
.split(', ')
.filter(k => k.toLowerCase() == key.toLowerCase());
return j.length > 0;
});
}
// Check that we still have data to go through. If not, break out.
if (temp.length == 0) {
console.log('dead end reached with', db_filter_chain[i]);
break;
}
}
db_active_photogs = temp;
}
function searchPhotographers() {
let temp = db_active_photogs;
let raw_matches = [];
const search_accessors = [
first_name,
last_name,
full_name,
first_name_2,
last_name_2,
full_name_2,
city_1,
city_2,
area_1,
area_2,
country_1,
country_2,
website,
instagram,
];
console.log(
db_search_term
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, ''),
);
search_accessors.forEach(acc => {
raw_matches = raw_matches.concat(
temp.filter(d =>
acc(d)
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
.includes(
db_search_term
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, ''),
),
),
);
});
const matches = [...new Set(raw_matches)];
db_active_photogs = matches;
}
function updateText(data_source) {
// Take the data_source and based on it's length, update the text on top of the gallery.
const n_photogs = data_source.length;
const container = d3.select('#db-summary__text');
let text = `There are ${n_photogs} photographers that match your criteria.`;
if (n_photogs == 1) {
text = `There is 1 photographer that matches your criteria.`;
}
if (n_photogs == data.length) {
text = `There are ${n_photogs} photographers in the database.`;
}
if (n_photogs == 0) {
text = `There are no photographers that match your criteria. Try a different search.`;
}
container.html(text);
}
function updateGallery(data_source) {
// Remove all current cards.
const current_cards = d3.selectAll('.db-card');
current_cards.remove();
// Shuffle the data_source.
const photog_list = d3.map(data_source, d => d.photog_id);
shuffleArray(photog_list);
// Add cards for each ID.
photog_list.forEach((id, i) => {
generatePhotogCard(id);
});
imagesLoaded(db_gallery_grid, function (instance) {
dbMasonry = new Masonry('.db-galleryGrid', {
itemSelector: '.db-card',
columnWidth: '.db-card',
percentPosition: true,
initLayout: false,
});
dbMasonry.layout();
});
}
function clearSection(section) {
if (section == 'search') {
// Clear the search term.
db_search_term = '';
d3.select('#db-search__input').property('value', '');
} else if (section == 'db') {
// clear all the filters & search term.
db_filter_chain = [];
db_search_term = '';
d3.select('#db-search__input').property('value', '');
d3.selectAll('.db-option__inner').classed('db-option__inner--active', false);
} else {
// Clear the corresponding filter category.
db_filter_chain = db_filter_chain.filter(d => !d.includes(section));
d3.select(`#lmd-${section}`).selectAll('.db-option__inner').classed('db-option__inner--active', false);
}
}
}
main();