Технічна стаття

Редагування діаграм Excel без втрати ChartML у HotXLS

HotXLS зберігає оригінальний ChartML імпортованої діаграми Excel і відтворює його побайтно, коли в типізованій моделі нічого не змінилося, тож відкриття та пересохранення книги тихо не обрізає ті частини діаграми, які об'єктна модель не репрезентує. Відредагуйте заголовок, ряд або вісь, і HotXLS структурно зливає нові типізовані вузли в оригінальне дерево, а не перегенеровує діаграму з нуля

Саме ця різниця — відтворення, коли не торкалися, злиття, коли редагували — і робить застосунок Delphi безпечним для спрямування на діаграми, що їх аналітик будував в Excel. Перегенерація діаграми з типізованої моделі завжди втрачає те, чого модель не знає, а діаграми Excel повні речей, яких бібліотека не знає: власні стилі, списки розширень, гілки альтернативного вмісту, форматування з просторів імен від надбудов

Чому пересохранення книги сплощує її діаграми?

Тому що звичайна реалізація читає те, що розуміє, і пише те, що розуміє. Усе між ними — extLst від новішої збірки Excel, гілка mc:AlternateContent, ефект фігури, для якого в моделі немає властивості, — існує у файлі, не має дому в об'єктній моделі та зникає під час збереження. Користувач бачить діаграму, що втратила градієнт, власні підписи даних або 3D-ефект, і книга не може пояснити чому

Із ввімкненим на книзі PreserveUnsupportedParts HotXLS зберігає оригінальні UTF-8-байти діаграми під час імпорту разом із довжиною та 64-бітовим відбитком типізованого вмісту. Якщо типізована модель не змінилася до моменту збереження, він пише оригінальні байти назад. Без переупорядкування XML, без дрейфу пробілів, без резидентної UTF-16-копії діаграми, що висить у пам'яті для діаграми, яку ніхто не редагував

var
  Workbook: TXLSXWorkbook;
  Chart: TXLSXChart;
begin
  Workbook := TXLSXWorkbook.Create(nil);
  try
    Workbook.PreserveUnsupportedParts := True;   // set before Open
    Workbook.Open('quarterly-review.xlsx');
    Chart := Workbook.Sheets[1].Charts[0];   // Sheets[] is 1-based
    if Chart.HasPreservedXml then
      Log('original ChartML retained; untouched charts replay exactly');
    Chart.Title := 'Revenue by region, Q3 2026';  // now the merge path runs
    Workbook.SaveAs('quarterly-review-out.xlsx');
  finally
    Workbook.Free;
  end;
end;

Що злиття зберігає і чим володіє модель

Правило — власність. Публічні вузли моделі — заголовок, ряди, кеші, групи графіків, осі — вирішуються новоствореним деревом. Нетипізовані піддерева переносяться з оригіналу. Ця асиметрія навмисна, і саме її треба усвідомити: видалення ряду не повинно воскресити старий ряд зі збереженого XML, тож усе, чим володіє модель, береться з моделі, навіть коли модель каже «зник»

Вміст без власника повторно вставляється поруч зі сполученими вузлами, де він сидів, а extLst залишається останнім усередині свого батька, бо там його вимагає схема. Очищення відомої властивості — скидання прапорця жирності, видалення кольору — трактується як очищення, а не як прогалина, яку заповнити з оригінального дерева. Невідомі атрибути в тій саме околиці зберігають своє місце

Вміст сумісності розмітки отримує специфічну обробку. Під час розбору HotXLS пропускає mc:Choice і читає mc:Fallback; якщо ця гілка резерву огортає групу графіків, яку знає модель, злиття пише новий типізований вміст назад у піддерево резерву. Без цього кроку збереження випустив би нову групу графіків і залишив би стару всередині резерву, і діаграма нісла б дві

Виключення однієї діаграми

ClearPreservedXml скидає оригінальний XML та відбиток для однієї діаграми, тож наступне збереження перебудовує цю діаграму суто з типізованої моделі. Це рішення на рівні діаграми; рівнева для книги PreserveUnsupportedParts усе ще визначає, чи будується стан збереження під час імпорту

Звертайтеся до неї, коли хочете чисту діаграму, а не вірну — наприклад, коли шаблонна діаграма несе форматування зі старої корпоративної теми і сенс операції — відкинути його. Не звертайтеся до неї як до налагоджувального рефлексу: діаграма, що рендериться неправильно після редагування, частіше є питанням моделювання, ніж збереження, а очищення збереженого XML руйнує докази

Комбіновані діаграми та друга вісь

AddPlotGroup будує впорядковані комбіновані діаграми, де кожна група графіків зберігає власну сім'ю діаграм і власну первинну або вторинну прив'язку осі. Це те, чого потребує всеприсутня бізнес-діаграма: дохід стовпцями на лівій осі, відсоток маржі лінією на правій

Діаграми виставляють первинні та вторинні осі категорій і значень плюс вісь рядів, із типізованими налаштуваннями категорії, значення, дати та осі рядів, що охоплюють позиції, ідентифікатори, перетини, одиниці дати, інтервали підписів і видимість. Старіший плоский API — ChartType, AddSeries, плоска колекція Series — усе ще адресує первинну групу графіків, тож наявний код продовжує працювати, тоді як модель під ним тримає кожну впорядковану групу

var
  Chart: TXLSXChart;
  Line: TXLSXChartPlotGroup;
begin
  // Column chart anchored over rows 1..15, columns 5..12
  Chart := Sheet.Charts.Add(xlsxChartColumn, 'Revenue and margin',
    1, 5, 15, 12);
  Chart.AddSeries('Revenue', 'Data!$A$2:$A$13', 'Data!$B$2:$B$13');
  // Second plot group: a line, read against the secondary value axis
  Line := Chart.AddPlotGroup(xlsxChartLine, xlsxAxisSecondary);
  Line.AddSeries('Margin %', 'Data!$A$2:$A$13', 'Data!$C$2:$C$13');
end;

До того, як ця модель існувала, відкриття та пересохранення комбінованої діаграми згортало її в одну сім'ю діаграм і втрачало вторинні, датні та рядні осі. Формульні посилання діаграм і кешовані значення рядів тепер переживають копії книги та цикли відкриття/збереження також, а прив'язки діаграм зіставляються з їхніми частинами діаграм за ідентифікатором зв'язку — тож застосунок, що переупорядковує записи зв'язків, більше не міняє вміст діаграм між позиціями аркуша

Пастка ручного компонування

Якщо ви розташовуєте область побудови, заголовок, заголовок осі або легенду вручну, пишіть усі чотири координати. Office вимагає x, y, w та h як повну групу, щойно присутній будь-який з них, і ігнорує весь manualLayout інакше. HotXLS завжди випускає повний прямокутник з цієї причини, а SetPositionAndSize встановлює та вмикає його за один виклик

Ще дві деталі слідують Excel, а не повній свободі специфікації. Позиція пишеться з xMode та yMode, установленими на edge, тоді як розмір використовує factor для wMode та hMode, бо саме це пише Excel і в що він перетворює інші комбінації. А layoutTarget випускається лише для області побудови, ніколи для заголовків або легенд, де примітки реалізації Microsoft це забороняють

Вписування цього в цикл книги

Збереження діаграм — один випадок загальної політики: бібліотека, що редагує документи, створені в іншому місці, має змінювати те, про що її попросили, й нічого більше. Те саме міркування рухає HotXLS у темах, ланцюгах обчислень та розширеннях аркушів, описане в нотатках про безвтратні цикли для теми, extLst та calcChain, а щодо проєктів VBA та зовнішніх посилань — у збереженні VBA та зовнішніх посилань. Щодо самої поверхні авторинга діаграм — створення діаграм, розміщення зображень та графіки з Delphi — дивіться нарис діаграм, зображень та графіки в HotXLS

HotXLS читає, редагує та пише діаграми XLSX з рідного коду Delphi та C++Builder без встановленого на машині Excel, що й робить точність проблемою бібліотеки, а не проблемою автоматизації — сторінка компонента електронних таблиць HotXLS містить список діаграмних можливостей та пробне завантаження