Pull to refresh

Comments 18

UFO just landed and posted this here
Прочитал. Честно говоря, я не понял, как предлагается распределять ширину между столбцами с атрибутом width:auto. Написано, вроде бы, только как вычислить минимальную и максимальную ширину.

К тому же, утверждение
If possible, widen all spanned columns by approximately the same amount.
мне кажется подозрительным, потому что в одном столбце может быть много текста, а в другом — мало. Увеличивать их на примерно одну величну нерационально.
Эх, а я с первых строк понадеялся, что кто-то наконец допишет кусок FOP для таблиц…
Хм. В свободное время (еще б найти его) можно будет попробовать. Я правда Java не знаю. А вообще есть коммерческие процессоры же. Они вроде бы поддерживают.
А вы не смотрели алгоритмы верстки таблиц в LaTeX'е, в качестве образца? Там наверняка есть много поучительного, и идеи для верстки в ТеХе исходно стоят на хорошем алгоритмическом/математическом фундаменте.
Не смотрел. Спасибо за наводку. Сейчас нашел документ, описывающий разметку таблиц text. Как минимум, отличие в том, что там предлагают минимизировать a height(table) + width(table). Но вообще я рассматриваю более частный случай, когда таблица растянута по всей ширине страницы, отсутсвуют объединенные ячейки.
Сейчас прочитать статью по вашей ссылке не успел, только общую идею с первой страницы. Думаю, это частичные решения, потому что кроме расположения ячеек нужно еще учитывать «плохость» (термин не мой, а Кнута) текста внутри ячеек. Плохость в ТеХе определяется как функция отклонений межсловных интервалов от нормальных (эти значения берут из данных кернинга шрифта), штрафов за переносы и ряд характерных типографических событий типа «нельзя однобуквенный заглавный предлог оставлять в конце строки». Без оптимизации набора внутри ячеек получается то, что вы видите в поликлиниках на стенах, то есть — никуда не годится.
Мне тут подсказали: а вы не рассматривали простой перебор по всем возможным ширинам столбцов? Если таблица на лист формата А4 или около того, там вариантов то всего ничего, кажется.
Отчет большой. Таблица может быть и на 50 листов А4.
Ну если не 50 листов в ширину, а в длину (т.е. таблица шириной А4), то это не сильно увеличивает количество вариантов для перебора. Какая-нибудь стандартная таблица из 5 столбцов. 11 шрифтом у меня сейчас в вордпаде влезает 11 слов «привет» в строчку. Есть слова длиннее, есть короче. Для первого столбца есть около 7 вариантов длин (11 — 4). Для второго тоже, для третьего и четвертого тоже. Ширина пятого столбца и так понятна, если заданы все другие. Итого 7^4 = 2401 вариантов. Если шрифт мелкий и слова мелкие, то все равно это будет, пусть даже 20^4 вариантов. Если больше столбцов, то это увеличивает показатель степени, но уменьшает число, которое возводим. Плюс можно исключать варианты типа: первые два столбца шириной 7 т.к. это будет уже шире, чем лист, а нужно еще минимум 3 слова впихнуть. Это существенно сократит перебор, на случай, если таблицы нужно строить с 60 фпс :-) Конечно, каждую новую итерацию придется вычислять количество переносов в каждом столбце, но т.к. для каждого столбца есть только несколько вариантов, то и это самое количество переносов можно посчитать один раз вначале всего алгоритма и занести в массив, отдельный для каждого столбца (типа «кэшировать»).
В разных строках же разный текст, поэтому в общем случае получается, что для каждой ячейки могут быть свои градации. Не забывайте еще, что в примере я считал размер буквы равным единице, а в реальной жизни размер слова высчитывается с использованием метрики шрифта.
Все гораздо проще на самом деле.

Таблицы используют механизм сходный с flex layout
В той статье приведена моя имплеменация т.н. spring engine (Физическая инерпретация процесса — связанная системы пружин с ограничителями. )
www.terrainformatica.com/w3/flex-layout/spring-engine.h

Там два основных метода

spring::engine::add(int valmin, int valmax, int weight)
и
spring::engine::calc(int total_space)

Для каждого столбца таблицы зовем add c
valmin — минимальная ширина колонки без overflow.
valmax — или MAXINT или max-width если устанвленно.
weight — для флексов — flex units value, для таблиц либо процент если есть, либо привденный к процентам max-content width.

(max-content width это минимальная ширина блока в которм все параграфы в одну строку)

после вызова calc() с требуемой шириной таблицы получаем расситанные ширины столбцов.
Алгоритм финитный с хорошей сходимостью — макс. количество итераций N*N (где N это количество столбцов), но на практике просто N или 2N.
Можно делать и так. Собственно, с чего-то похожего я и начинал.

Основная проблема в том, чтобы правильно вычислить «жесткость пружинки». Если, как вы предлагаете, использовать в качестве жесткости максимальную ширину столбца, то у Вас размерность не сходится. столбец, состоящий в среднем из 2х коротких слов, но в одной строке содержащий 10 длинных, будет растянут гораздо больше, чем следовало.

Я пробовал вычислить коэффициент жесткости на основе функции числа переносов, но она все-таки обладает сильной нелинейностью и при линеаризации точность заметно теряется. Возможно, можно придумать метод вычисления коэффициента, который даст хороший результат, но его ведь еще нужно обосновать. Я решил, что проще не линеаризовывать.

Кстати, алгоритм не такой уж и сложный. Реализация занимает у меня строк 200-300 кода.
Я не слышал ни разу что использование числа переносов в качестве метрики кем-то используется вообще. Перенос в тексте это настолько language specific feature что закладываться на нея в алгоритмах таблиц это путь в никуда.

Данный spring::engine используется для рассчета HTML таблиц в моих движках HTMLayout и Sciter. Он воспроизводит auto layout HTML таблиц достаточно точно насколько это вообще возможно ибо у всех browsing движков (trident, gecko и webkit) несколько разные базовые алгоритмы).

Извиняюсь, но я не понял фразу «столбец, состоящий в среднем из 2х коротких слов, но в одной строке содержащий 10 длинных, будет растянут гораздо больше, чем следовало.» «10 длинных» чего?

Во всяком случае все HTML движки согласны что вот эти две колонки имеют ширины 2:1

<table width="100%" border=1> <tr> <td>123456789012345 6789</td> <td>12345 1234</td> </tr> </table>
Возможно браузеры и используют такой алгоритм, но на тех данных, про которые я говорил выше, они косячат. Вот пример

P.S. Куда постить html, чтобы было видно сразу и код и результат? Точно что-то было, но сейчас не могу найти.
Я не слышал ни разу что использование числа переносов в качестве метрики кем-то используется вообще


Возможно, вы имели ввиду верстку только таблиц, но в ТеХе именно число переносов (взвешенное, суммированное со штрафами за другие типографические события) является метрикой, которую оптимизируют во время верстки текста. Не возьмусь утверждать, что в ТеХе таблицы расчитываются ровно так же (давно не заглядывал в TeXbook).
Sign up to leave a comment.

Articles