This article was published in partnership with The Marshall Project, a nonprofit news organization covering the U.S. criminal justice system. Sign up for their newsletters here.
Additional reporting by Geoff Hing.
/////////////////////////////////SCROLLING TEXT BLOCKS/////////////////////////////////// let wWidth, wHeight; const blocks = []; let mapindex = 0; const mapContainer = document.querySelector('.g-santa-anna-maps-container');
const getHeight = (el) => { return el.getBoundingClientRect().height; } const getPositionTop = (el) => { const rect = el.getBoundingClientRect(), scrollTop = window.pageYOffset || document.documentElement.scrollTop; return rect.top + scrollTop; } const constrain = (n, low, high) => { return Math.max(Math.min(n, high), low); }
//////////////////////////////////BLOCKS///////////////////////////////////
const initBlocks = () => { [...document.querySelectorAll('.g-block')].forEach((el, index) => { var obj = {}; obj.index = index; obj.el = el; obj.isGraphic = el.classList.contains('g-santa-anna-block'); obj.isOpener = el.classList.contains('g-opener'); if(obj.isGraphic){ obj.mapindex = mapindex; mapindex++; } blocks.push(obj); }); onResize(); addResizeListener(); addScrollListener();
} //////////////////////////////////RESIZE/SCROLL/////////////////////////////////// const onResize = () => {
wWidth = Math.max(document.documentElement.clientWidth, window.innerWidth); wHeight = window.innerHeight;
blocks.forEach((block, index) => { block.top = getPositionTop(block.el); block.height = getHeight(block.el); block.bottom = block.top + block.height; }); onScroll(); } const onScroll = () => {
const scroll = window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0); blocks.forEach((block, index) => { const offsetY = (block.isOpener) ? 0 : wHeight/3;
if(block.bottom - offsetY >= scroll && block.top <= scroll + offsetY){ if(!block.el.classList.contains('g-active')){ block.el.classList.add('g-active'); if(block.isGraphic) mapContainer.dataset.currentindex = block.mapindex; } if(block.isOpener){ let offset = scroll - block.top; offset = constrain(offset, 0, block.height); let percentScrolled = offset/block.height; percentScrolled = constrain(percentScrolled, 0, 1); console.log(percentScrolled) block.el.style.setProperty('--p', percentScrolled); } }else{ if(block.el.classList.contains('g-active')){ block.el.classList.remove('g-active'); } } }); } const addScrollListener = () => {
let ticking = false;
window.addEventListener('scroll', scrollListener);
function scrollListener(evt) {
if (!ticking) {
window.requestAnimationFrame((evt) => { ticking = false;
onScroll(); }); } ticking = true; } }
const addResizeListener = () => {
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => { onResize(); }, 1000); }); } const setupObserver = (elements, callback) => { const options = { rootMargin: '-50% 0% -50% 0%', threshold: [0] };
const observer = new IntersectionObserver(callback, options);
Array.prototype.forEach.call(elements, (el) => { observer.observe(el); }); }
const createScrollEls = () => { const elements = document.querySelectorAll('.g-block'); if (elements.length === 0) return false;
setupObserver(elements, scrollerObserverCallbackFunction); }
const scrollerObserverCallbackFunction = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const { target } = entry; onResize(); } }); }
initBlocks(); createScrollEls();
/////////////////////////////////SCROLLING TEXT BLOCKS/////////////////////////////////// let wWidth1, wHeight1; const blocks1 = []; let mapindex1 = 0; const mapContainer1 = document.querySelector('.g-santa-anna1-maps-container');
const getHeight1 = (el) => { return el.getBoundingClientRect().height; } const getPositionTop1 = (el) => { const rect = el.getBoundingClientRect(), scrollTop = window.pageYOffset || document.documentElement.scrollTop; return rect.top + scrollTop; } const constrain1 = (n, low, high) => { return Math.max(Math.min(n, high), low); }
//////////////////////////////////BLOCKS///////////////////////////////////
const initBlocks1 = () => { [...document.querySelectorAll('.g-block1')].forEach((el, index) => { var obj = {}; obj.index = index; obj.el = el; obj.isGraphic = el.classList.contains('g-santa-anna1-block'); obj.isOpener = el.classList.contains('g-opener'); if(obj.isGraphic){ obj.mapindex1 = mapindex1; mapindex1++; } blocks1.push(obj); }); onResize1(); addResizeListener1(); addScrollListener1();
} //////////////////////////////////RESIZE/SCROLL/////////////////////////////////// const onResize1 = () => {
wWidth1 = Math.max(document.documentElement.clientWidth, window.innerWidth); wHeight1 = window.innerHeight;
blocks1.forEach((block, index) => { block.top = getPositionTop1(block.el); block.height = getHeight1(block.el); block.bottom = block.top + block.height; }); onScroll1(); } const onScroll1 = () => {
const scroll = window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0); blocks1.forEach((block, index) => { const offsetY = (block.isOpener) ? 0 : wHeight1/3;
if(block.bottom - offsetY >= scroll && block.top <= scroll + offsetY){ if(!block.el.classList.contains('g-active')){ block.el.classList.add('g-active'); if(block.isGraphic) mapContainer1.dataset.currentindex = block.mapindex1; } if(block.isOpener){ let offset = scroll - block.top; offset = constrain1(offset, 0, block.height); let percentScrolled = offset/block.height; percentScrolled = constrain1(percentScrolled, 0, 1); block.el.style.setProperty('--p', percentScrolled); } }else{ if(block.el.classList.contains('g-active')){ block.el.classList.remove('g-active'); } } }); } const addScrollListener1 = () => {
let ticking1 = false;
window.addEventListener('scroll', scrollListener1);
function scrollListener1(evt) {
if (!ticking1) {
window.requestAnimationFrame((evt) => { ticking1 = false;
onScroll1(); }); } ticking1 = true; } }
const addResizeListener1 = () => {
let resizeTimer1;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer1);
resizeTimer1 = setTimeout(() => { onResize1(); }, 1000); }); } const setupObserver1 = (elements, callback) => { const options = { rootMargin: '-50% 0% -50% 0%', threshold: [0] };
const observer = new IntersectionObserver(callback, options);
Array.prototype.forEach.call(elements, (el) => { observer.observe(el); }); }
const createScrollEls1 = () => { const elements = document.querySelectorAll('.g-block1'); if (elements.length === 0) return false;
setupObserver1(elements, scrollerObserverCallbackFunction1); }
const scrollerObserverCallbackFunction1 = (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const { target } = entry; onResize1(); } }); }
initBlocks1(); createScrollEls1();
/////////////////////////////////SCROLLING TEXT BLOCKS/////////////////////////////////// let wWidth2, wHeight2; const blocks2 = []; let mapindex2 = 0; const mapContainer2 = document.querySelector('.g-santa-anna2-maps-container');
const getHeight2 = (el) => { return el.getBoundingClientRect().height; } const getPositionTop2 = (el) => { const rect = el.getBoundingClientRect(), scrollTop = window.pageYOffset || document.documentElement.scrollTop; return rect.top + scrollTop; } const constrain2 = (n, low, high) => { return Math.max(Math.min(n, high), low); }
//////////////////////////////////BLOCKS///////////////////////////////////
const initBlocks2 = () => { [...document.querySelectorAll('.g-block2')].forEach((el, index) => { var obj = {}; obj.index = index; obj.el = el; obj.isGraphic = el.classList.contains('g-santa-anna2-block'); obj.isOpener = el.classList.contains('g-opener'); if(obj.isGraphic){ obj.mapindex2 = mapindex2; mapindex2++; } blocks2.push(obj); }); onResize2(); addResizeListener2(); addScrollListener2();
} //////////////////////////////////RESIZE/SCROLL/////////////////////////////////// const onResize2 = () => {
wWidth2 = Math.max(document.documentElement.clientWidth, window.innerWidth); wHeight2 = window.innerHeight;
blocks2.forEach((block, index) => { block.top = getPositionTop2(block.el); block.height = getHeight2(block.el); block.bottom = block.top + block.height; }); onScroll2(); } const onScroll2 = () => {
const scroll = window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0); blocks2.forEach((block, index) => { const offsetY = (block.isOpener) ? 0 : wHeight2/3;
if(block.bottom - offsetY >= scroll && block.top <= scroll + offsetY){ if(!block.el.classList.contains('g-active')){ block.el.classList.add('g-active'); if(block.isGraphic) mapContainer2.dataset.currentindex = block.mapindex2; } if(block.isOpener){ let offset = scroll - block.top; offset = constrain2(offset, 0, block.height); let percentScrolled = offset/block.height; percentScrolled = constrain2(percentScrolled, 0, 1); console.log(percentScrolled) block.el.style.setProperty('--p', percentScrolled); } }else{ if(block.el.classList.contains('g-active')){ block.el.classList.remove('g-active'); } } }); } const addScrollListener2 = () => {
let ticking = false;
window.addEventListener('scroll', scrollListener);
function scrollListener(evt) {
if (!ticking) {
window.requestAnimationFrame((evt) => { ticking = false;
onScroll2(); }); } ticking = true; } }
const addResizeListener2 = () => {
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => { onResize2(); }, 1000); }); } const setupObserver2 = (elements, callback) => { const options = { rootMargin: '-50% 0% -50% 0%', threshold: [0] };
const observer2 = new IntersectionObserver(callback, options);
Array.prototype.forEach.call(elements, (el) => { observer2.observe(el); }); }
const createScrollEls2 = () => { const elements = document.querySelectorAll('.g-block2'); if (elements.length === 0) return false;
setupObserver2(elements, scrollerObserverCallbackFunction2); }
const scrollerObserverCallbackFunction2 = (entries, observer2) => { entries.forEach(entry => { if (entry.isIntersecting) { const { target } = entry; onResize2(); } }); }
initBlocks2(); createScrollEls2();
Illustrations and reporting by Susie Cagle. Cagle is a 2023 Alicia Patterson Foundation journalism fellow.
Citations
Ajamu spoke with TMP on the condition that his nickname, “Ajamu,” be used to identify him because he feared retribution for speaking out.
The landslide was stabilized by private contractors in the summer of 2022, but unprecedented flash flooding across eastern Kentucky on the morning of July 28 triggered the property’s second slide. While flooding is Kentucky’s most frequent and costly natural disaster, landslides — typically triggered by rainfall — follow close behind.
Precipitation and snowpack data from the California Department of Water Resources.
National analysis based on data from the Federal Emergency Management Agency and U.S. Census Bureau.
Floods and Droughts in the Tulare Lake Basin, by John T. Austin; Department of Water Resources.
School enrollment data, Hanford Sentinel, October 17, 1984; unemployment and lost city revenue, April 26, 1986.
Residents and officials at local meetings were quoted in the Corcoran Journal and the Fresno Bee, from 1984 to 1986.
“CEQA Exemption-Corcoran” notes dated July 5, 1985, authored by attorney Dick Skjeie, held at state archives. “We are not seeking to avoid having environmental impact studies. But we are seeking to try to speed up this process,” said Gov. George Deukmejian on July 17, 1985, The Los Angeles Times.
“A Pandora’s Box” and “would establish a dangerous precedent,” Kings County Grand Jury, June 13, 1985; “Given CDC’s sorry record in facility planning, is it wise policy to suspend all independent reviews of their planning?” Assembly Committee meeting notes on Senate Bill 146, August 26, 1985; “Potentially significant impacts,” “flooding,” “subsidence,” 1986 report by consultant firm Jones and Stokes assessing Corrections’ internal environmental review of the Corcoran project.
Vote count, McClatchy News Service, September 13, 1985.
Population counts, 1980 and 2020, U.S. Census Bureau.
“In 1985, the CDC bought the least desirable of the three parcels from the J. G. Boswell Company,” Golden Gulag by Ruth Wilson Gilmore. Boswell land ownership data, ParcelQuest.
Mark Grewal, former Boswell Company VP, calculated the flooded acreage using local flood district maps and observations, estimating the lake grew 10,000 acres each week in the initial flood phase.
Repeated attempts to reach Boswell officials for comment went unanswered.
2015 and 2017 levee work, Hanford Sentinel, August 30, 2017; “Ground Subsidence Study Report, Corcoran Subsidence Bowl,” Amec Foster Wheeler Environment & Infrastructure, 2017; 1969 and 1983 flood satellite images provided by Rob Hansen; 2023 flood map, California Department of Water Resources.
Greg, an incarcerated person at SATF, asked that his last name be withheld because he feared retribution for speaking to a reporter.
José Madrigal spoke with TMP over the course of several months in the late spring and summer.
Daily temperatures, National Weather Service station in Hanford, California.
Fire risk depicted is sourced from CalFire 2023 maps; floodplains sourced from FEMA; prison locations, with “X” marking facilities being closed or in process of being closed, California Department of Corrections and Rehabilitation.
“Overlapping Crises: Climate Disaster Susceptibility and Incarceration” study published in 2022, based on data from FEMA and The Marshall Project.
Climate scientist Daniel Swain “office hours” on YouTube, July 10, 2023.
This story was originally published by Grist with the headline In California, climate chaos looms over prisons — and thousands of prisoners — in a lake bed on Oct 24, 2023.