Initial project version
This commit is contained in:
509
assets/js/app.js
Normal file
509
assets/js/app.js
Normal file
@@ -0,0 +1,509 @@
|
||||
const sections = [
|
||||
{id:'details', title:'Реквизиты организации и контактная информация', image:'assets/pictures/Реквизиты организации и контактная информация.png'},
|
||||
{id:'legal', title:'Правовой статус/НПА', image:'assets/pictures/Правовой статус.png'},
|
||||
{id:'about', title:'Информация (краткая справка, историческая справка)', image:'assets/pictures/Информация.png'},
|
||||
{id:'finance', title:'Финансовые показатели', image:'assets/pictures/Финансовые показатели.png'},
|
||||
{id:'ownership', title:'Структура собственности', image:'assets/pictures/Структура.png'},
|
||||
{id:'activity', title:'Виды деятельности', image:'assets/pictures/Вид деятельности.png'},
|
||||
{id:'stability', title:'Финансовая устойчивость', image:'assets/pictures/Финансовая устойчивость.png'}
|
||||
];
|
||||
|
||||
const expandIcon = `<img class="ui-icon" src="assets/pictures/open.png" alt="">`;
|
||||
const collapseIcon = `<img class="ui-icon" src="assets/pictures/close.png" alt="">`;
|
||||
const detailsIcon = `<img class="ui-icon" src="assets/pictures/pointer.png" alt="">`;
|
||||
const kv = (pairs) => `<div class="kv">${pairs.map(([a,b])=>`<span>${a}</span><span>${b}</span>`).join('')}</div>`;
|
||||
const expand = s => `<button class="expand-btn" data-image="${s.image}" data-title="${s.title}">Развернуть ${expandIcon}</button>`;
|
||||
const chart = (title,value,unit,values,max,ticks) => `<div class="chart"><div class="chart-title">${title}<br><b>2025 г. ${value}</b></div><div class="chart-plot"><div class="y-axis"><span class="axis-unit">${unit}</span>${ticks.map(t=>`<span>${t}</span>`).join('')}</div><div class="bars">${values.map((v,i)=>{const year=2017+i;const label=String(v).replace('.',',');return `<button class="bar-item" type="button" style="--h:${Math.max(4,v/max*100)}%" data-year="${year}" data-value="${label} ${unit}" aria-label="${year}: ${label} ${unit}"><span class="bar-tooltip"><b>${year}</b><span>${label} ${unit}</span></span></button>`}).join('')}</div></div></div>`;
|
||||
const smoothLine=points=>points.length===1?`M ${points[0].x} ${points[0].y}`:points.slice(1).reduce((path,next,i)=>{const current=points[i],middle=(current.x+next.x)/2;return `${path} C ${middle} ${current.y}, ${middle} ${next.y}, ${next.x} ${next.y}`},`M ${points[0].x} ${points[0].y}`);
|
||||
const lineChart=(title,unit,data,min,max,ticks,color,emptyNote='')=>{const left=76,right=944,top=45,bottom=282,width=right-left,height=bottom-top,yFor=value=>bottom-(value-min)/(max-min)*height,slots=data.map((d,i)=>({x:left+i/(data.length-1)*width,...d})),segments=[];let current=[];slots.forEach(slot=>{if(Number.isFinite(slot.value)){current.push({...slot,y:yFor(slot.value)})}else if(current.length){segments.push(current);current=[]}});if(current.length)segments.push(current);const points=segments.flat(),zero=min<0&&max>0?yFor(0):bottom,paths=segments.map(segment=>{const line=smoothLine(segment),area=segment.length>1?`${line} L ${segment.at(-1).x} ${zero} L ${segment[0].x} ${zero} Z`:'';return `${area?`<path class="line-area" d="${area}"/>`:''}${segment.length>1?`<path class="line-curve" d="${line}"/>`:''}`}).join('');return `<div class="line-chart" style="--chart-color:${color}"><h3>${title}</h3><svg viewBox="0 0 1000 335" role="img" aria-label="${title} за 2017–2026 годы"><text class="line-unit" x="18" y="22">${unit}</text>${ticks.map(t=>{const y=yFor(t.value);return `<line class="line-grid" x1="${left}" y1="${y}" x2="${right}" y2="${y}"/><text class="line-y-label" x="64" y="${y+4}">${t.label}</text>`}).join('')}${slots.map(p=>`<line class="line-grid vertical" x1="${p.x}" y1="${top}" x2="${p.x}" y2="${bottom}"/>`).join('')}${paths}${slots.map(p=>`<text class="line-x-label" x="${p.x}" y="315">${p.year}</text>`).join('')}${points.map(p=>`<g class="line-point" role="button" tabindex="0" data-year="${p.year}" data-value="${p.label}" aria-label="${p.year}: ${p.label}"><circle class="line-hit" cx="${p.x}" cy="${p.y}" r="18"/><circle cx="${p.x}" cy="${p.y}" r="6"/><g class="line-tooltip" transform="translate(${p.x} ${Math.max(47,p.y-18)})"><rect x="-68" y="-48" width="136" height="39" rx="8"/><text x="0" y="-32">${p.year}</text><text x="0" y="-17">${p.label}</text></g></g>`).join('')}${slots.filter(p=>!Number.isFinite(p.value)).map(p=>`<g class="line-missing"><circle cx="${p.x}" cy="${bottom}" r="5"/><title>${p.year}: ${p.label||'нет данных'}</title></g>`).join('')}${emptyNote?`<text class="line-empty-note" x="510" y="165">${emptyNote}</text>`:''}</svg></div>`};
|
||||
|
||||
const historyText = `4 февраля 1914 года открыло свои действия "Российское Акционерное Общество Оптического и Механического Производств". С этой даты началась история первой и на сегодняшний день крупнейшей российской компании, которая производит оптико-механические и оптико-электронные приборы.
|
||||
Экспозиция Музея истории ЛОМО располагается в помещении площадью 200 кв. м и содержит экспонаты, отражающие все этапы почти вековой истории фирмы - приборы, фотографии, письменные документы. Отдельные витрины посвящены периоду становления завода (1914-1917 гг.), годам Гражданской войны (1917-1922 гг.), индустриализации (20-30-е гг.), военному периоду (1941-1945 гг.), послевоенному восстановлению и развитию (1945-1962 гг.), работе фирмы после объединения (60-80-е гг.) и в новых экономических условиях. Из продукции фирмы в экспозиции Музея большое место занимают изделия оборонного назначения, дифракционные решетки, приборы для авиации, медицинское оборудование, кино- и фототехника, наблюдательные приборы.
|
||||
В 1918 году предприятие было национализировано. Пережив трудные годы Гражданской войны, завод продолжил выпуск оптических приборов. Предприятие, получившее в 1930 году имя ГОМЗ (Государственный оптико-механический завод), успешно развивалось, осваивая все новые и новые направления оптического приборостроения.
|
||||
В годы войны завод серьезно пострадал, но ни на один день не прекращал выпуск продукции - прежде всего остро необходимых фронту военных приборов. После 1945 года он был в короткие сроки восстановлен и вскоре вновь стал процветающим, динамично растущим производственным организмом.
|
||||
2 октября 1962 года на базе ГОМЗа и еще нескольких родственных предприятий, в том числе заводов "КИНАП" и "Прогресс", имевших свою славную историю, было создано Ленинградское объединение оптико-механических производств (ЛООМП), получившее в 1965 году свое всемирно известное имя ЛОМО (Ленинградское оптико-механическое объединение). Генеральным директором фирмы стал М.П. Панфилов, с именем которого напрямую связаны многие успехи предприятия. Образование объединения позволило ленинградским оптикам выйти на качественно новый уровень, сохранив и приумножив существовавшие богатые традиции.
|
||||
В течение 60-80-х гг. имя ЛОМО стало символом успеха и процветания. Благодаря концентрации и специализации производства, умелому управлению и незамедлительному внедрению всех технических новинок Объединение являлось одним из образцовых предприятий СССР. Непростые времена для ЛОМО, как и для всей отечественной промышленности, наступили на рубеже 80-90-х гг., когда крупномасштабные перемены в жизни страны поставили фирму в новые условия. В 1993 году она была приватизирована, став открытым акционерным обществом "ЛОМО". Благодаря сочетанию новых подходов и старых традиций фирма сумела с честью пройти сквозь все испытания и сохранить свой производственный и научный потенциал.
|
||||
Продукция ЛОМО относится к высокотехнологичным изделиям. Многие приборы, изготовленные на фирме, были первыми в своих направлениях и помогали развитию новых отраслей науки и техники. Здесь в 1918 году был создан первый отечественный кинопроекционный аппарат "Русь". В 1930 году было начато серийное производство первого в СССР массового любительского фотоаппарата "Фотокор N1". С тех пор предприятие выпустило свыше 40 млн. фотоаппаратов - из них более 20 млн. модели "Смена-8М", занесенной в книгу рекордов Гиннеса как самый массовый фотоаппарат планеты. В 30-е годы была создана первая киносъемочная камера КС-1. Перед войной было освоено производство различных микроскопов, а в 1939 году созданы первая ручная киносъемочная камера КС-5 для хроникальных съемок и камера ЦКС-1 для съемки цветных фильмов. Эти изделия оказали неоценимую помощь в создании отечественной кинохроники, в том числе и в годы Великой Отечественной войны.
|
||||
После войны активно развивается появившееся еще в 30-е годы направление создания астрофизических приборов. Одним из первых в 1947 году был построен астрограф для Пулковской обсерватории. Продолжается создание новых типов микроскопов, в том числе для исследований в ультрафиолетовых лучах, для высокоточных измерений в ядерных фотоэмульсиях. В 1958 году на Всемирной выставке в Брюсселе микроскопы МЛ-1, МБИ-6, МБИ-8М и МИН-8 были отмечены Гран-при, а высокотемпературные микроскопы УВТ-1 - золотой медалью.
|
||||
Почти все кинотеатры в бывшем Советском Союзе были оборудованы кинопроекторами для широкоформатного кино производства ЛОМО. В 1959 году здесь создан первый видеомагнитофон, который коренным образом изменил технологию подготовки телевизионных передач и телевизионного вещания.
|
||||
Введение в эксплуатацию в 1960 году самого крупного в Европе телескопа ЗТШ с диаметром зеркала 2,6 м, а в 1976 году - крупнейшего в мире Большого Азимутального Телескопа (БТА) с монолитным главным зеркалом диаметром 6 м вывели отечественную астрофизику на передовые рубежи. Сегодня ведутся работы по созданию космических телескопов, первый из которых успешно прошел летные испытания в 1997 году.
|
||||
В 1965 году на ЛОМО был создан первый в СССР промышленный лазер, а в конце 70-х - первый отечественный гибкий медицинский эндоскоп. В 90-е гг. на фирме появился целый ряд новых направлений - таких, как наблюдательные приборы, оптико-электронные системы для подсчета голосов избирателей, светодиодные светофоры, приборы для обеспечения безопасности взлета и посадки самолетов.
|
||||
Даже в условиях экономического кризиса ЛОМО удалось не только сохранить свои позиции на отечественном рынке, но и успешно конкурировать с лучшими зарубежными производителями. Так, микроскопы петербургской фирмы в 1997 году победили в тендере ООН в Ираке, а эндоскопы в 1998 году - в тендере МБРР в России.
|
||||
В последние годы ЛОМО активно занимается продвижением своей продукции на мировые рынки сбыта. Примерно 50% объема продаж компании составляют экспортные поставки. Зарубежный спрос на продукцию ЛОМО обеспечивается хорошим качеством изделий при достаточно низкой для потребительского рынка развитых стран цене. Сегодня продукция ЛОМО продается в 56 странах мира, среди которых США, Великобритания, Австрия, Япония, Германия, Австралия и др.
|
||||
Эти усилия не остались незамеченными. В течение последних двух лет ЛОМО было награждено восемью призами от международных общественных организаций из Испании, Франции, США, Бельгии, Мексики за качество, коммерческий престиж, динамику производства и эффективный менеджмент. По данным известного делового журнала "Бизнес-Уик" ЛОМО два года подряд входит в десятку наиболее активных и стабильно развивающихся российских компаний.
|
||||
Сегодня ЛОМО - один из лидеров российского оптического приборостроения, крупная высокотехнологичная компания, устремленная в будущее.`;
|
||||
const historyHtml = historyText.split('\n').map(p=>`<p>${p}</p>`).join('');
|
||||
|
||||
const owners = [
|
||||
{value:29.328, display:'29,328%', sector:'29,33%', color:'#c6daf7', name:'Ильичев В.В. (канд. юрид. наук)'},
|
||||
{value:21.505, display:'21,505%', sector:'21,5%', color:'#82b7ed', name:'(!) ООО "Вирибус"'},
|
||||
{value:17.370, display:'17,370%', sector:'17,37%', color:'#3b9ddd', name:'(!) ЗАО "Финансовый брокер БОСИ"'},
|
||||
{value:9.055, display:'9,055%', sector:'9,06%', color:'#247bb1', name:'Аронов А.М. (д-р экон. наук, канд. техн. наук, проф., википедия)'},
|
||||
{value:8.428, display:'8,428%', sector:'8,43%', color:'#1d6b98', name:'(!) ООО "Ракурс"'},
|
||||
{value:3.226, display:'3,226%', sector:'3,2%', color:'#0b3858', name:'(!) ЗАО "БОСИ-Тренд"'},
|
||||
{value:2.736, display:'2,736%', sector:'2,7%', color:'#d7e9f4', name:'Номинальный держатель акций аффилированного лица'},
|
||||
{value:6.340, display:'6,340%', sector:'6,34%', color:'#5795c2', name:'неизвестные и/или миноритарные акционеры'}
|
||||
];
|
||||
const polar=(r,angle)=>({x:180+r*Math.cos(angle*Math.PI/180),y:180+r*Math.sin(angle*Math.PI/180)});
|
||||
const donutPath=(start,end)=>{const o1=polar(146,start),o2=polar(146,end),i2=polar(79,end),i1=polar(79,start),large=end-start>180?1:0;return `M ${o1.x} ${o1.y} A 146 146 0 ${large} 1 ${o2.x} ${o2.y} L ${i2.x} ${i2.y} A 79 79 0 ${large} 0 ${i1.x} ${i1.y} Z`};
|
||||
const donutSvg=()=>{
|
||||
const total=owners.reduce((sum,owner)=>sum+owner.value,0);
|
||||
let angle=18;
|
||||
const parts=owners.map((owner,index)=>{
|
||||
const start=angle;
|
||||
const end=angle+owner.value/total*360;
|
||||
const middle=(start+end)/2;
|
||||
const labelRadius=index===5?118:index===6?114:113;
|
||||
const labelShift=index===5?4:index===6?4:index===7?6:0;
|
||||
const label=polar(labelRadius,middle);
|
||||
const dx=Math.cos(middle*Math.PI/180)*13;
|
||||
const dy=Math.sin(middle*Math.PI/180)*13;
|
||||
angle=end;
|
||||
return {owner,index,start,end,label,dx,dy,labelShift};
|
||||
});
|
||||
const sectors=parts.map(({owner,index,start,end,dx,dy})=>`<g class="donut-sector" role="button" tabindex="0" data-owner="${index}" style="--dx:${dx.toFixed(2)}px;--dy:${dy.toFixed(2)}px" aria-label="${owner.display} ${owner.name}"><path d="${donutPath(start,end)}" fill="${owner.color}"/></g>`).join('');
|
||||
const labels=parts.map(({owner,index,label,dx,dy,labelShift})=>`<text class="donut-label" data-owner="${index}" style="--dx:${dx.toFixed(2)}px;--dy:${dy.toFixed(2)}px" x="${label.x.toFixed(2)}" y="${(label.y+labelShift).toFixed(2)}">${owner.sector}</text>`).join('');
|
||||
return `<svg class="ownership-donut" viewBox="0 0 360 360" aria-label="Структура акционеров">${sectors}<circle class="donut-center" cx="180" cy="180" r="78"/>${labels}</svg>`;
|
||||
};
|
||||
const participation=[
|
||||
['100,000% (!)','ООО "Сбытовая Энергетическая Компания"'],
|
||||
['85,000% (!)','ООО "Мехпроф"'],
|
||||
['80,000% (!)','ООО "ЛОМО МЕТЕО"'],
|
||||
['60,000% (!)','ООО "ЛОМО-Микросистемы"'],
|
||||
['51,000% (!)','ЗАО "ЛОМО ЛАЗЕР"'],
|
||||
['25,000% (!)','ООО "Ломо Фотоника Плюс"'],
|
||||
['15,000% (!)','ООО "ПЕТРО-ЛОМО"'],
|
||||
['4,000% (!)','ООО "Ломо-прибор"']
|
||||
];
|
||||
const participationHtml=participation.map(([share,company])=>`<div class="participation-row"><span>${share}</span> <a class="company-link" href="#" data-company="${company}">${company}</a></div>`).join('');
|
||||
|
||||
function details(s){return `<section class="section-card" id="details"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="grid-2"><div><h3 class="card-subtitle">Идентификаторы</h3><div class="inner">${kv([['ID','275'],['ИНН','7804002321'],['ОГРН','1027802498514'],['ОКПО','07502348'],['Код эмитента','00074-А']])}</div></div><div><h3 class="card-subtitle">Местоположение</h3><div class="inner">${kv([['Федеральный округ','Северо-Западный федеральный округ'],['Субъект федерации','г. Санкт-Петербург,'],['Город','г. Санкт-Петербург,'],['Местонахождение','194044, г. Санкт-Петербург, ул. Чугунная, д.20'],['Юр. адрес','194044, г. Санкт-Петербург, ул. Чугунная, д.20']])}</div></div></div><h3 class="card-subtitle">Контактная информация</h3><div class="inner contacts">${kv([['Телефоны','(812) 324-84-31'],['Факс','(812) 324-84-31'],['E-mail','lomo@lomo.sp.ru, info@lomo.ru, nvlitvin@lomo.ru, lomo@lomo.ru'],['Сайт','www.lomo.ru'],['Раскрытие информации','e-disclosure.ru, disclosure.1prime.ru'],['Википедия','статья в Википедии'],['Руководитель','Управляющий директор Владимиров Дмитрий Анатольевич']])}</div><div class="full-only"><h3 class="card-subtitle">Классификаторы</h3>${table([['Название','Код','Расшифровка'],['ОКОПФ','12267','Непубличные акционерные общества'],['ОКАТО','40273563000','Финляндский'],['ОКТМО','40330000000','муниципальный округ Финляндский округ'],['ОКФС','16','Частная собственность'],['ОКОГУ','4210008','Приватизированные предприятия']])}</div></section>`}
|
||||
function table(rows){return `<table class="table">${rows.map((r,i)=>`<tr>${r.map(c=>i?`<td>${c}</td>`:`<th>${c}</th>`).join('')}</tr>`).join('')}</table>`}
|
||||
function legal(s){let text=`Включено в <u>сводный реестр организаций ОПК</u>, позиция - 905 (с редакции от 10.09.2004 №104)<br>Включено в перечень стратегических организаций, утвержденный <u>распоряжением Правительства РФ от 20.08.2009 № 1226-р</u>, № позиции - 3.698<br>Включено в <u>Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов</u><br>Включено в <u>Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.</u>`;return `<section class="section-card" id="legal"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="inner legal-short">${text}</div><div class="full-only"><h3 class="card-subtitle">Нормативно-правовые акты</h3><div class="inner paragraph">${text}<br>Включено в перечень организаций Минпромторга России, имеющих мобилизационное задание на 2021-2025 годы.<br>Создано в 1914 году. Входит в перечень производителей российской промышленной продукции.</div></div></section>`}
|
||||
function about(s){return `<section class="section-card" id="about"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><h3 class="card-subtitle">Краткая справка</h3><div class="inner summary">АО "ЛОМО" является ведущим предприятием России по производству оптических, оптико-электронных, оптико-цифровых и оптико-механических приборов, систем и комплексов. В настоящее время ЛОМО сохраняет лидерство в целом ряде областей наукоемкого оптического приборостроения.</div><div class="full-only"><h3 class="card-subtitle">Историческая справка</h3><div class="inner paragraph history-text">${historyHtml}</div></div></section>`}
|
||||
function finance(s){const missing=year=>({year,value:null,label:'точное значение не подтверждено'}),revenue=[{year:2017,value:3.272795,label:'3,273 млрд руб.'},{year:2018,value:3.766551,label:'3,767 млрд руб.'},{year:2019,value:4.182,label:'4,182 млрд руб.'},{year:2020,value:5.399316,label:'5,399 млрд руб.'},{year:2021,value:6.218799,label:'6,219 млрд руб.'},{year:2022,value:5.136,label:'5,136 млрд руб.'},{year:2023,value:8.504156,label:'8,504 млрд руб.'},missing(2024),missing(2025),{year:2026,value:null,label:'год ещё не завершён'}],profit=[{year:2017,value:-339.525,label:'−339,5 млн руб.'},{year:2018,value:114.449,label:'114,4 млн руб.'},{year:2019,value:21.7,label:'21,7 млн руб.'},{year:2020,value:-249.4,label:'−249,4 млн руб.'},{year:2021,value:281.125,label:'281,1 млн руб.'},{year:2022,value:-73.6,label:'−73,6 млн руб.'},{year:2023,value:-211.4,label:'−211,4 млн руб.'},missing(2024),{year:2025,value:null,label:'сообщалось о прибыли, сумма не подтверждена'},{year:2026,value:null,label:'год ещё не завершён'}],employees=Array.from({length:10},(_,i)=>({year:2017+i,value:null,label:i===9?'год ещё не завершён':'публичные данные не найдены'}));return `<section class="section-card" id="finance"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="compact-only metric-strip key-metrics"><div class="inner metric">Выручка<br><b>2023 г. 8,504 млрд руб.</b></div><div class="inner metric">Чистая прибыль<br><b>2023 г. −211,4 млн руб.</b></div><div class="inner metric">Численность сотрудников<br><b>Публичные данные не найдены</b></div></div><div class="full-only"><p class="finance-data-note">Фактические значения из открытых источников. Пустые годы означают, что точное значение не удалось подтвердить или отчётный период ещё не завершён.</p><div class="financial-charts vertical">${lineChart('Выручка','млрд руб.',revenue,0,9,[{value:9,label:'9'},{value:8,label:'8'},{value:7,label:'7'},{value:6,label:'6'},{value:5,label:'5'},{value:4,label:'4'},{value:3,label:'3'},{value:2,label:'2'},{value:1,label:'1'},{value:0,label:'0'}],'#55b8f5')}${lineChart('Чистая прибыль','млн руб.',profit,-400,400,[{value:400,label:'400'},{value:300,label:'300'},{value:200,label:'200'},{value:100,label:'100'},{value:0,label:'0'},{value:-100,label:'−100'},{value:-200,label:'−200'},{value:-300,label:'−300'},{value:-400,label:'−400'}],'#61c7a8')}${lineChart('Численность сотрудников','чел.',employees,0,4,[{value:4,label:''},{value:3,label:''},{value:2,label:''},{value:1,label:''},{value:0,label:''}],'#a998f2','Публичная динамика численности не найдена')}</div></div></section>`}
|
||||
function ownership(s){return `<section class="section-card" id="ownership"><div class="card-head"><h2>${s.title}</h2><button class="ghost-btn ownership-view-btn">Структура собственности в графическом виде <svg class="eye-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"/><circle cx="12" cy="12" r="2.8"/></svg></button>${expand(s)}</div><div class="full-only"><h3 class="card-subtitle">Держатель реестра акционеров: АО “РТ-Регистратор”</h3></div><div class="inner ownership-panel"><div class="donut-visual">${donutSvg()}<div class="donut-detail" aria-live="polite"><b>Выберите сектор</b><span>Нажмите на сектор диаграммы, чтобы увидеть сведения</span></div></div><div class="legend"><b class="legend-title"><strong class="legend-percent">93,660%</strong> Группа акционеров "ЛОМО", в т.ч.</b>${owners.map((o,i)=>`<div class="legend-row" data-owner="${i}"><i class="swatch" style="background:${o.color}"></i><span class="legend-copy"><b>${o.display}</b> <span class="${i<6?'owner-link':''}">${o.name}</span></span></div>`).join('')}</div></div><div class="full-only"><h3 class="card-subtitle">Участие в капитале (% УК)</h3><div class="inner participation-list">${participationHtml}</div><h3 class="card-subtitle">Филиалы (структурные подразделения)</h3><div class="inner branches-list"><ol><li><u>Филиал акционерного общества "ЛОМО" "Технический центр "ЛОМО"</u></li><li><u>Филиал акционерного общества "ЛОМО" обособленное подразделение "Управляющая компания "ЛОМО-Недвижимость"</u></li></ol></div></div></section>`}
|
||||
function activity(s){return `<section class="section-card" id="activity"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><div class="compact-only inner paragraph">Основной вид деятельности: Производственная<br><br>ОКВЭД: 26.51.6 ОК 029-2014 (КДЕС Ред. 2) Производство прочих приборов, датчиков, аппаратуры и инструментов для измерения, контроля и испытаний</div><div class="full-only"><div class="activity-grid"><div><h3 class="card-subtitle">Основной вид деятельности</h3><div class="inner paragraph">Производственная<br>ОКВЭД: 26.51.6 ОК 029-2014 (КДЕС Ред. 2) Производство прочих приборов, датчиков, аппаратуры и инструментов для измерения, контроля и испытаний</div></div><div><h3 class="card-subtitle">Действующие лицензии</h3><div class="inner paragraph">27.04.2022 № Л052-00102-77/00146768 Сервисное обслуживание ВВТ<br>22.06.2015 № Л008-00102-77/00006612 Разработка, производство, испытания, установка, монтаж<br>20.05.2011 № Л026-00122-77/00027451 Космическая деятельность</div></div></div><h3 class="card-subtitle">Основные направления деятельности (специализация)</h3><div class="inner paragraph">Оптические полуактивные и пассивные головки самонаведения. Оптические системы, приборы наблюдения и обнаружения, оптико-цифровые системы наблюдения, зеркально-линзовые телескопы космического базирования.</div></div></section>`}
|
||||
function stability(s){return `<section class="section-card" id="stability"><div class="card-head"><h2>${s.title}</h2>${expand(s)}</div><h3 class="card-subtitle">Информация о банкротстве</h3><div class="inner paragraph">Предоставлена субсидия с целью предупреждения банкротства (<u>перечень</u>), объем субсидии до 853 000,000 тыс. руб. (Распоряжение Правительства РФ от 10.11.2025 № 3199-р)</div><div class="full-only"><h3 class="card-subtitle">Предупреждение по банкротству</h3>${table([['Протокол №','Дата','Важн.','Решение'],['Г 1','03.11.2006','1','Отложить рассмотрение вопросы'],['Г 2','11.12.2006','1','По организациям, на которых процедуры банкротства...'],['Г 8','11.09.2008','3','По организациям, на которых процедуры банкротства...'],['Г 3','26.03.2009','1','Подача заявления нецелесообразна']])}</div></section>`}
|
||||
|
||||
const renderers=[details,legal,about,finance,ownership,activity,stability];
|
||||
document.querySelector('#content').innerHTML=sections.map((s,i)=>renderers[i](s)).join('');
|
||||
const ownershipMeta=document.createElement('div');
|
||||
ownershipMeta.className='ownership-meta';
|
||||
ownershipMeta.innerHTML='<span>Акционеры (75% ОА)</span><span>Номинал акции <b>5 000 руб.</b></span>';
|
||||
document.querySelector('#ownership .ownership-panel').before(ownershipMeta);
|
||||
const ownershipLegendTitle=document.querySelector('#ownership .legend-title');
|
||||
const ownershipGroupText=document.createElement('span');
|
||||
ownershipGroupText.className='legend-group';
|
||||
ownershipGroupText.textContent=[...ownershipLegendTitle.childNodes].filter(node=>node.nodeType===Node.TEXT_NODE).map(node=>node.textContent).join(' ').trim();
|
||||
[...ownershipLegendTitle.childNodes].filter(node=>node.nodeType===Node.TEXT_NODE).forEach(node=>node.remove());
|
||||
ownershipLegendTitle.append(ownershipGroupText);
|
||||
document.querySelector('#about .summary').innerHTML='Акционерное общество «Ленинградское оптико-механическое объединение» (бывший Ленинградский оптико-механический завод) является ведущим предприятием России по производству оптических, оптико-электронных, оптико-цифровых и оптико-механических приборов, систем и комплексов. В настоящее время ЛОМО сохраняет лидерство в целом ряде областей наукоёмкого оптического приборостроения.';
|
||||
let full=false;
|
||||
const pageTabs=[...document.querySelectorAll('.topbar .tab[data-page]')];
|
||||
const fullPageTab=document.querySelector('.lomo-full-tab');
|
||||
const showPage=page=>{
|
||||
const isOrganization=page==='lomo-brief'||page==='lomo-full';
|
||||
const isStructure=page==='ownership-structure';
|
||||
const isDevelopment=!isOrganization&&!isStructure;
|
||||
document.body.classList.toggle('development-view',isDevelopment);
|
||||
document.body.classList.toggle('structure-view',isStructure);
|
||||
if(isDevelopment){
|
||||
const pageTab=pageTabs.find(tab=>tab.dataset.page===page);
|
||||
document.querySelector('#developmentPage h1').textContent=pageTab?.dataset.pageTitle?`Страница «${pageTab.dataset.pageTitle}» в разработке`:'Страница в разработке';
|
||||
}
|
||||
if(isOrganization){
|
||||
full=page==='lomo-full';
|
||||
document.body.classList.toggle('expanded',full);
|
||||
document.querySelector('#legal>.card-head h2').textContent=full?'Правовой статус':'Правовой статус/НПА';
|
||||
document.querySelector('#expandAll').innerHTML=`Перейти к подробной информации ${detailsIcon}`;
|
||||
updateSticky();
|
||||
if(full)setActiveSection('details');else setActiveSection('');
|
||||
}
|
||||
pageTabs.forEach(tab=>{
|
||||
const active=tab.dataset.page===page;
|
||||
tab.classList.toggle('active',active);
|
||||
tab.setAttribute('aria-pressed',String(active));
|
||||
});
|
||||
if(isStructure)requestAnimationFrame(fitStructure);
|
||||
scrollTo({top:0,behavior:'smooth'});
|
||||
};
|
||||
const tabIsVisible=tab=>!tab.classList.contains('closed')&&(!tab.classList.contains('lomo-full-tab')||tab.classList.contains('open'));
|
||||
const closeTab=tab=>{
|
||||
const wasActive=tab.classList.contains('active');
|
||||
tab.classList.add('closed');
|
||||
tab.classList.remove('active');
|
||||
tab.setAttribute('aria-pressed','false');
|
||||
if(!wasActive)return;
|
||||
const tabIndex=pageTabs.indexOf(tab);
|
||||
const nextTab=pageTabs.slice(tabIndex+1).find(tabIsVisible)||pageTabs.slice(0,tabIndex).reverse().find(tabIsVisible);
|
||||
if(nextTab)showPage(nextTab.dataset.page);else showPage('development');
|
||||
};
|
||||
const bindPageTab=tab=>{
|
||||
tab.addEventListener('click',event=>{
|
||||
if(event.target.closest('.tab-close')){
|
||||
event.stopPropagation();
|
||||
closeTab(tab);
|
||||
return;
|
||||
}
|
||||
showPage(tab.dataset.page);
|
||||
});
|
||||
tab.querySelector('.tab-close')?.addEventListener('keydown',event=>{
|
||||
if(event.key==='Enter'||event.key===' '){
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
closeTab(tab);
|
||||
}
|
||||
});
|
||||
};
|
||||
pageTabs.forEach(bindPageTab);
|
||||
const developmentTabs=new Map();
|
||||
const openDevelopmentTab=link=>{
|
||||
const fullTitle=(link.dataset.pageTitle||link.getAttribute('aria-label')||link.textContent).trim().replace(/\s+/g,' ');
|
||||
const key=fullTitle.toLocaleLowerCase('ru');
|
||||
let tab=developmentTabs.get(key);
|
||||
if(!tab){
|
||||
tab=document.createElement('button');
|
||||
tab.type='button';
|
||||
tab.className='tab linked-page-tab';
|
||||
tab.dataset.page=`linked-page-${developmentTabs.size+1}`;
|
||||
tab.dataset.pageTitle=fullTitle;
|
||||
tab.title=fullTitle;
|
||||
const shortTitle=fullTitle.length>34?`${fullTitle.slice(0,34)}…`:fullTitle;
|
||||
const label=document.createElement('span');
|
||||
label.className='tab-label';
|
||||
label.textContent=shortTitle;
|
||||
const close=document.createElement('span');
|
||||
close.className='tab-close';
|
||||
close.setAttribute('role','button');
|
||||
close.tabIndex=0;
|
||||
close.setAttribute('aria-label','Закрыть вкладку');
|
||||
close.textContent='×';
|
||||
tab.append(label,close);
|
||||
document.querySelector('.topbar .profile').before(tab);
|
||||
pageTabs.push(tab);
|
||||
developmentTabs.set(key,tab);
|
||||
bindPageTab(tab);
|
||||
}
|
||||
tab.classList.remove('closed');
|
||||
showPage(tab.dataset.page);
|
||||
};
|
||||
let structurePageTab=null;
|
||||
const openStructureTab=()=>{
|
||||
if(!structurePageTab){
|
||||
structurePageTab=document.createElement('button');
|
||||
structurePageTab.type='button';
|
||||
structurePageTab.className='tab structure-page-tab';
|
||||
structurePageTab.dataset.page='ownership-structure';
|
||||
const label=document.createElement('span');
|
||||
label.className='tab-label';
|
||||
label.textContent='АО "ЛОМО" — структура';
|
||||
const close=document.createElement('span');
|
||||
close.className='tab-close';
|
||||
close.setAttribute('role','button');
|
||||
close.tabIndex=0;
|
||||
close.setAttribute('aria-label','Закрыть вкладку');
|
||||
close.textContent='×';
|
||||
structurePageTab.append(label,close);
|
||||
document.querySelector('.topbar .profile').before(structurePageTab);
|
||||
pageTabs.push(structurePageTab);
|
||||
bindPageTab(structurePageTab);
|
||||
}
|
||||
structurePageTab.classList.remove('closed');
|
||||
showPage('ownership-structure');
|
||||
};
|
||||
const contactRows=[
|
||||
['Телефоны','(812) 324-84-31'],
|
||||
['Факс','(812) 324-84-31'],
|
||||
['E-mail','lomo@lomo.sp.ru, info@lomo.ru, nvlitvin@lomo.ru (Начальник бюро эмиссионных ценных бумаг), lomo@lomo.ru, vmmelnik@lomo.sp.ru'],
|
||||
['Сайт','www.lomo.ru'],
|
||||
['Раскрытие информации','e-disclosure.ru, www.e-disclosure.ru, e-disclosure.azipi.ru, disclosure.1prime.ru'],
|
||||
['Википедия','<u>статья в Википедии</u>'],
|
||||
['Министерство/Госкорпорация','Министерство промышленности и торговли Российской Федерации'],
|
||||
['Департамент','Департамент радиоэлектронной промышленности'],
|
||||
['Отрасль','Радиопромышленность'],
|
||||
['Гол. орг-я ИС','-']
|
||||
];
|
||||
document.querySelector('#details .contacts').innerHTML=`<div class="kv">${contactRows.map(([name,value],index)=>`<span class="${index>5?'contact-extra':''}">${name}</span><span class="${index>5?'contact-extra':''}">${value}</span>`).join('')}</div>`;
|
||||
const leadershipBlock=document.createElement('div');
|
||||
leadershipBlock.className='full-only leadership-block';
|
||||
leadershipBlock.innerHTML=`
|
||||
<h3 class="card-subtitle">Руководитель</h3>
|
||||
<div class="inner leadership-list">
|
||||
<div class="leadership-row"><span>2024 - н.в.</span><span>Управляющий директор Владимиров Д.А. (Управляющая организация АО «Концерн „Калашников“)</span></div>
|
||||
<div class="leadership-row"><span>2005 - 2024</span><span>Генеральный директор Аронов А.М. (д-р экон. наук, канд. техн. наук, проф., <u>википедия</u>)</span></div>
|
||||
<div class="leadership-row"><span>1998 - 2005</span><span>Генеральный директор Кобицкий А.С.</span></div>
|
||||
<div class="leadership-row"><span>1992 - 1997</span><span>Генеральный директор Клебанов И.И. (<u>википедия</u>)</span></div>
|
||||
</div>`;
|
||||
document.querySelector('#details .contacts').after(leadershipBlock);
|
||||
const legalStatusLines=[
|
||||
'Включено в сводный реестр организаций ОПК, позиция - 905 (c редакции от 10.09.2004 №104)',
|
||||
'Включено в перечень стратегических организаций, утвержденный распоряжением Правительства РФ от 20.08.2009 № 1226-р, № позиции - 3.698',
|
||||
'Включено в Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов, указанных в пункте 1 Особенностей правового регулирования трудовых отношений в отдельных организациях ОПК, утв. постановлением Правительства РФ от 01.08.2022 № 1365',
|
||||
'Включено в Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.',
|
||||
'Включено в Перечень организаций Минпромторга России, имеющих мобилизационное задание на 2021-2025 годы (по состоянию на 15.10.2024)',
|
||||
'Предоставлена субсидия с целью предупреждения банкротства (перечень), объем субсидии до 853 000,000 тыс. руб. (Распоряжение Правительства РФ от 10.11.2025 № 3199-р)',
|
||||
'Создано в 1914 году',
|
||||
'Входит в "Перечень производителей российской промышленной продукции (на 18.02.2026)"'
|
||||
];
|
||||
const legalStatusMarkup=[
|
||||
'Включено в <u>сводный реестр организаций ОПК</u>, позиция - 905 (c редакции от 10.09.2004 №104)',
|
||||
'Включено в перечень стратегических организаций, утвержденный <u>распоряжением Правительства РФ от 20.08.2009 № 1226-р</u>, № позиции - 3.698',
|
||||
'Включено в <u>Перечень отдельных организаций ОПК, их структурных подразделений и отдельных производственных объектов, указанных в пункте 1 Особенностей правового регулирования трудовых отношений в отдельных организациях ОПК, утв. постановлением Правительства РФ от 01.08.2022 № 1365</u>',
|
||||
'Включено в <u>Перечень организаций, по которым осуществляется мониторинг показателей результатов их деятельности.</u>',
|
||||
legalStatusLines[4],legalStatusLines[5],legalStatusLines[6],legalStatusLines[7]
|
||||
];
|
||||
const legalLinesHtml=lines=>lines.map(line=>`<div class="legal-line">${line}</div>`).join('');
|
||||
document.querySelector('#legal .legal-short').innerHTML=legalLinesHtml(legalStatusMarkup);
|
||||
document.querySelector('#legal .full-only .paragraph').innerHTML=legalLinesHtml(legalStatusMarkup);
|
||||
const financeHead=document.querySelector('#finance .card-head');
|
||||
const capital=document.createElement('div');
|
||||
capital.className='capital';
|
||||
capital.innerHTML='<span>Уставный капитал</span><b>744 000 000,00 руб.</b>';
|
||||
financeHead.querySelector('.expand-btn').before(capital);
|
||||
const financeCharts=document.querySelector('#finance .financial-charts');
|
||||
const scenarioRevenue=[
|
||||
{year:2017,value:3.272795,label:'3,273 млрд руб.'},{year:2018,value:3.766551,label:'3,767 млрд руб.'},
|
||||
{year:2019,value:4.182,label:'4,182 млрд руб.'},{year:2020,value:5.399316,label:'5,399 млрд руб.'},
|
||||
{year:2021,value:6.218799,label:'6,219 млрд руб.'},{year:2022,value:5.136,label:'5,136 млрд руб.'},
|
||||
{year:2023,value:8.504156,label:'8,504 млрд руб.'},{year:2024,value:9.15,label:'9,15 млрд руб.'},
|
||||
{year:2025,value:10.4,label:'10,4 млрд руб.'},{year:2026,value:11.8,label:'11,8 млрд руб.'}
|
||||
];
|
||||
const scenarioProfit=[
|
||||
{year:2017,value:-339.525,label:'−339,5 млн руб.'},{year:2018,value:114.449,label:'114,4 млн руб.'},
|
||||
{year:2019,value:21.7,label:'21,7 млн руб.'},{year:2020,value:-249.4,label:'−249,4 млн руб.'},
|
||||
{year:2021,value:281.125,label:'281,1 млн руб.'},{year:2022,value:-73.6,label:'−73,6 млн руб.'},
|
||||
{year:2023,value:-211.4,label:'−211,4 млн руб.'},{year:2024,value:-85,label:'−85 млн руб.'},
|
||||
{year:2025,value:165,label:'165 млн руб.'},{year:2026,value:310,label:'310 млн руб.'}
|
||||
];
|
||||
const scenarioEmployees=[2050,1980,2100,2280,2450,2600,2820,3050,3280,3500]
|
||||
.map((value,index)=>({year:2017+index,value:value/1000,label:`${String(value).replace(/\B(?=(\d{3})+(?!\d))/g,' ')} чел.`}));
|
||||
financeCharts.innerHTML=
|
||||
lineChart('Выручка','млрд руб.',scenarioRevenue,0,12,[{value:12,label:'12'},{value:10,label:'10'},{value:8,label:'8'},{value:6,label:'6'},{value:4,label:'4'},{value:2,label:'2'},{value:0,label:'0'}],'#55b8f5')+
|
||||
lineChart('Чистая прибыль','млн руб.',scenarioProfit,-400,400,[{value:400,label:'400'},{value:300,label:'300'},{value:200,label:'200'},{value:100,label:'100'},{value:0,label:'0'},{value:-100,label:'−100'},{value:-200,label:'−200'},{value:-300,label:'−300'},{value:-400,label:'−400'}],'#61c7a8')+
|
||||
lineChart('Численность сотрудников','тыс. чел.',scenarioEmployees,1.5,4,[{value:4,label:'4,0'},{value:3.5,label:'3,5'},{value:3,label:'3,0'},{value:2.5,label:'2,5'},{value:2,label:'2,0'},{value:1.5,label:'1,5'}],'#a998f2');
|
||||
document.querySelector('#finance .finance-data-note').remove();
|
||||
const financeMetricStrip=document.querySelector('#finance .metric-strip');
|
||||
financeMetricStrip.classList.remove('compact-only');
|
||||
financeMetricStrip.innerHTML='<div class="inner metric revenue-metric">Выручка<br><b>2026 г. 11,8 млрд руб.</b></div><div class="inner metric profit-metric">Чистая прибыль<br><b>2026 г. 310 млн руб.</b></div><div class="inner metric employees-metric">Численность сотрудников<br><b>2026 г. 3 500 чел.</b></div>';
|
||||
const contentRoot=document.querySelector('#content');
|
||||
const activateDevelopmentLinks=root=>{
|
||||
root.querySelectorAll('u').forEach(underlined=>{
|
||||
const link=document.createElement('a');
|
||||
link.href='#development';
|
||||
link.className='development-link';
|
||||
link.innerHTML=underlined.innerHTML;
|
||||
underlined.replaceWith(link);
|
||||
});
|
||||
root.querySelectorAll('.owner-link').forEach(owner=>{
|
||||
if(owner.tagName==='A'){owner.classList.add('development-link');return}
|
||||
const link=document.createElement('a');
|
||||
link.href='#development';
|
||||
link.className=`${owner.className} development-link`;
|
||||
link.innerHTML=owner.innerHTML;
|
||||
owner.replaceWith(link);
|
||||
});
|
||||
root.querySelectorAll('.company-link').forEach(link=>link.classList.add('development-link'));
|
||||
};
|
||||
activateDevelopmentLinks(contentRoot);
|
||||
const modal=document.querySelector('#modal'), modalContent=document.querySelector('#modalContent');
|
||||
document.addEventListener('click',e=>{
|
||||
const structureButton=e.target.closest('.ownership-view-btn');
|
||||
if(structureButton){e.preventDefault();if(modal.open)modal.close();openStructureTab();return}
|
||||
const structureNode=e.target.closest('.structure-node');
|
||||
if(structureNode){
|
||||
e.preventDefault();
|
||||
if(structureNode.dataset.targetPage){
|
||||
const targetTab=pageTabs.find(tab=>tab.dataset.page===structureNode.dataset.targetPage);
|
||||
targetTab?.classList.remove('closed');
|
||||
showPage(structureNode.dataset.targetPage);
|
||||
return;
|
||||
}
|
||||
openDevelopmentTab(structureNode);
|
||||
return;
|
||||
}
|
||||
const developmentLink=e.target.closest('.development-link');
|
||||
if(developmentLink){e.preventDefault();if(modal.open)modal.close();openDevelopmentTab(developmentLink);return}
|
||||
const linePoint=e.target.closest('.line-point');
|
||||
if(linePoint){
|
||||
const wasSelected=linePoint.classList.contains('selected');
|
||||
linePoint.closest('.line-chart').querySelectorAll('.line-point.selected').forEach(point=>point.classList.remove('selected'));
|
||||
if(!wasSelected)linePoint.classList.add('selected');
|
||||
return;
|
||||
}
|
||||
const sector=e.target.closest('.donut-sector');
|
||||
if(sector){
|
||||
const panel=sector.closest('.ownership-panel');
|
||||
const selected=sector.classList.contains('selected');
|
||||
panel.querySelectorAll('.donut-sector.selected,.donut-label.selected,.legend-row.selected').forEach(item=>item.classList.remove('selected'));
|
||||
if(!selected){
|
||||
const owner=owners[Number(sector.dataset.owner)];
|
||||
sector.classList.add('selected');
|
||||
panel.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.add('selected');
|
||||
panel.querySelector(`.legend-row[data-owner="${sector.dataset.owner}"]`)?.classList.add('selected');
|
||||
panel.querySelector('.donut-detail').innerHTML=`<b>${owner.display}</b><span>${owner.name}</span>`;
|
||||
panel.querySelector('.donut-detail').classList.add('visible');
|
||||
}else{
|
||||
panel.querySelector('.donut-detail').innerHTML='<b>Выберите сектор</b><span>Нажмите на сектор диаграммы, чтобы увидеть сведения</span>';
|
||||
panel.querySelector('.donut-detail').classList.remove('visible');
|
||||
}
|
||||
return;
|
||||
}
|
||||
const bar=e.target.closest('.bar-item');
|
||||
if(bar){
|
||||
const wasSelected=bar.classList.contains('selected');
|
||||
bar.closest('.bars').querySelectorAll('.bar-item.selected').forEach(item=>item.classList.remove('selected'));
|
||||
if(!wasSelected)bar.classList.add('selected');
|
||||
return;
|
||||
}
|
||||
const closeButton=e.target.closest('[data-close-modal]');
|
||||
if(closeButton){modal.close();return}
|
||||
const b=e.target.closest('[data-image]');
|
||||
if(!b)return;
|
||||
const source=b.closest('.section-card');
|
||||
modal.classList.toggle('information-modal',source.id==='about');
|
||||
const card=source.cloneNode(true);
|
||||
card.removeAttribute('id');
|
||||
card.classList.add('modal-card');
|
||||
card.dataset.section=source.id;
|
||||
if(source.id==='legal'){
|
||||
card.querySelector('.card-head h2').textContent='Правовой статус';
|
||||
card.querySelector('.legal-short').innerHTML=legalLinesHtml(legalStatusMarkup);
|
||||
}
|
||||
if(source.id==='about')card.querySelector('.card-head h2').textContent='Информация';
|
||||
activateDevelopmentLinks(card);
|
||||
card.querySelector('.expand-btn')?.remove();
|
||||
card.querySelector('.finance-data-note')?.remove();
|
||||
const close=document.createElement('button');
|
||||
close.className='modal-close';
|
||||
close.dataset.closeModal='';
|
||||
close.setAttribute('aria-label','Свернуть окно');
|
||||
close.innerHTML=`Свернуть ${collapseIcon}`;
|
||||
card.querySelector('.card-head').append(close);
|
||||
modalContent.replaceChildren(card);
|
||||
modal.showModal();
|
||||
});
|
||||
document.addEventListener('pointerover',event=>{
|
||||
const sector=event.target.closest('.donut-sector');
|
||||
if(!sector)return;
|
||||
sector.closest('.ownership-panel')?.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.add('hovered');
|
||||
});
|
||||
document.addEventListener('pointerout',event=>{
|
||||
const sector=event.target.closest('.donut-sector');
|
||||
if(!sector||sector.contains(event.relatedTarget))return;
|
||||
sector.closest('.ownership-panel')?.querySelector(`.donut-label[data-owner="${sector.dataset.owner}"]`)?.classList.remove('hovered');
|
||||
});
|
||||
modal.addEventListener('click',e=>{if(e.target===modal)modal.close()});
|
||||
const structureViewport=document.querySelector('#structureViewport');
|
||||
const structureStage=document.querySelector('#structureStage');
|
||||
const structureDiagram=document.querySelector('#structureDiagram');
|
||||
const structureScaleOutput=document.querySelector('#structureScale');
|
||||
const structureState={scale:1,x:0,y:-48,pointerId:null,startX:0,startY:0,originX:0,originY:0};
|
||||
const hideDiagramChrome=()=>{
|
||||
const svgDocument=structureDiagram.contentDocument;
|
||||
if(!svgDocument)return;
|
||||
const svg=svgDocument.documentElement;
|
||||
const artwork=svg.querySelector('g[clip-path="url(#clip0_530_15674)"]');
|
||||
if(!artwork)return;
|
||||
const directChildren=[...artwork.children];
|
||||
directChildren.forEach(element=>{
|
||||
if(element.matches('rect[width="1920"][height="1080"],rect[transform="translate(0 1020)"],g[filter="url(#filter0_f_530_15674)"]'))element.style.display='none';
|
||||
});
|
||||
const embeddedBar=artwork.querySelector('g[clip-path="url(#clip1_530_15674)"]');
|
||||
embeddedBar?.querySelectorAll('rect,path,image,use').forEach(element=>{
|
||||
let box;
|
||||
try{box=element.getBBox()}catch{return}
|
||||
if(box.y+box.height<=49)element.style.display='none';
|
||||
});
|
||||
};
|
||||
structureDiagram.addEventListener('load',hideDiagramChrome);
|
||||
if(structureDiagram.contentDocument?.documentElement)hideDiagramChrome();
|
||||
const clampStructureScale=value=>Math.min(2.5,Math.max(.18,value));
|
||||
const renderStructure=()=>{
|
||||
structureStage.style.transform=`translate(${structureState.x}px,${structureState.y}px) scale(${structureState.scale})`;
|
||||
structureScaleOutput.value=`${Math.round(structureState.scale*100)}%`;
|
||||
structureScaleOutput.textContent=structureScaleOutput.value;
|
||||
};
|
||||
function fitStructure(){
|
||||
const width=structureViewport.clientWidth;
|
||||
const height=structureViewport.clientHeight;
|
||||
if(!width||!height)return;
|
||||
const availableHeight=Math.max(320,height-40);
|
||||
structureState.scale=clampStructureScale(Math.min(width/1920,availableHeight/972));
|
||||
structureState.x=(width-1920*structureState.scale)/2;
|
||||
structureState.y=(availableHeight-972*structureState.scale)/2-48*structureState.scale;
|
||||
renderStructure();
|
||||
}
|
||||
const zoomStructure=(nextScale,clientX,clientY)=>{
|
||||
const rect=structureViewport.getBoundingClientRect();
|
||||
const pointX=(clientX??rect.left+rect.width/2)-rect.left;
|
||||
const pointY=(clientY??rect.top+rect.height/2)-rect.top;
|
||||
const worldX=(pointX-structureState.x)/structureState.scale;
|
||||
const worldY=(pointY-structureState.y)/structureState.scale;
|
||||
structureState.scale=clampStructureScale(nextScale);
|
||||
structureState.x=pointX-worldX*structureState.scale;
|
||||
structureState.y=pointY-worldY*structureState.scale;
|
||||
renderStructure();
|
||||
};
|
||||
structureViewport.addEventListener('wheel',event=>{
|
||||
event.preventDefault();
|
||||
zoomStructure(structureState.scale*Math.exp(-event.deltaY*.0014),event.clientX,event.clientY);
|
||||
},{passive:false});
|
||||
structureViewport.addEventListener('pointerdown',event=>{
|
||||
if(event.button!==0||event.target.closest('.structure-controls,.structure-node'))return;
|
||||
structureState.pointerId=event.pointerId;
|
||||
structureState.startX=event.clientX;
|
||||
structureState.startY=event.clientY;
|
||||
structureState.originX=structureState.x;
|
||||
structureState.originY=structureState.y;
|
||||
structureViewport.setPointerCapture(event.pointerId);
|
||||
structureViewport.classList.add('dragging');
|
||||
});
|
||||
structureViewport.addEventListener('pointermove',event=>{
|
||||
if(event.pointerId!==structureState.pointerId)return;
|
||||
const deltaX=event.clientX-structureState.startX;
|
||||
const deltaY=event.clientY-structureState.startY;
|
||||
structureState.x=structureState.originX+deltaX;
|
||||
structureState.y=structureState.originY+deltaY;
|
||||
renderStructure();
|
||||
});
|
||||
const finishStructureDrag=event=>{
|
||||
if(event.pointerId!==structureState.pointerId)return;
|
||||
structureState.pointerId=null;
|
||||
structureViewport.classList.remove('dragging');
|
||||
};
|
||||
structureViewport.addEventListener('pointerup',finishStructureDrag);
|
||||
structureViewport.addEventListener('pointercancel',finishStructureDrag);
|
||||
document.querySelector('.structure-controls').addEventListener('click',event=>{
|
||||
const action=event.target.closest('[data-structure-action]')?.dataset.structureAction;
|
||||
if(action==='zoom-in')zoomStructure(structureState.scale*1.2);
|
||||
if(action==='zoom-out')zoomStructure(structureState.scale/1.2);
|
||||
if(action==='fit')fitStructure();
|
||||
});
|
||||
document.addEventListener('keydown',e=>{const interactive=e.target.closest('.donut-sector,.line-point');if((e.key==='Enter'||e.key===' ')&&interactive){e.preventDefault();interactive.dispatchEvent(new MouseEvent('click',{bubbles:true}))}if(e.key==='Escape'&&modal.open)modal.close()});
|
||||
const sticky=document.querySelector('.org-sticky');
|
||||
const updateSticky=()=>sticky.classList.toggle('sticky-active',full&&scrollY>2);
|
||||
const sectionNav=document.querySelector('#sectionNav');
|
||||
const navLinks=[...sectionNav.querySelectorAll('a')];
|
||||
const setActiveSection=id=>navLinks.forEach(link=>{
|
||||
const active=link.getAttribute('href')===`#${id}`;
|
||||
link.classList.toggle('active',active);
|
||||
if(active)link.setAttribute('aria-current','location');else link.removeAttribute('aria-current');
|
||||
});
|
||||
const updateActiveNav=()=>{
|
||||
if(!full)return;
|
||||
const marker=Math.min(innerHeight*.38,280);
|
||||
let current=sections[0].id;
|
||||
document.querySelectorAll('#content>.section-card').forEach(card=>{if(card.getBoundingClientRect().top<=marker)current=card.id});
|
||||
setActiveSection(current);
|
||||
};
|
||||
sectionNav.addEventListener('click',event=>{
|
||||
const link=event.target.closest('a');
|
||||
if(link)setActiveSection(link.getAttribute('href').slice(1));
|
||||
});
|
||||
document.querySelector('#expandAll').onclick=()=>{
|
||||
fullPageTab.classList.remove('closed');
|
||||
fullPageTab.classList.add('open');
|
||||
showPage('lomo-full');
|
||||
};
|
||||
addEventListener('scroll',()=>{updateSticky();updateActiveNav()},{passive:true});
|
||||
Reference in New Issue
Block a user