Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Рисовать метки на осях координат и рабочий инструмент одним размером вне зависимости от масштаба рабочей области #8

Closed
sadr0b0t opened this issue Mar 10, 2017 · 8 comments
Labels

Comments

@sadr0b0t
Copy link
Owner

Подзадача отсюда отдельным тикетом

Выбрать движок SVG для React: система координат
#2

При достаточно большом реальном размере рабочей области 300000x200000 (микрометры) с масштабированием рабочей области к видимым размерам на экране было две проблемы:

  1. Линии, обозначавшие оси и границы рабочей области, при таком масштабе становились слишком тонки и исчезали.
  2. Проблема с масштабированием размеров шрифта и точки: названия осей и точка исчезнут (слишком мелкие при таком масштабе).

С полем 300x200 в обоих случаях всё ок.

Первая проблема решилась добавлением стиля vector-effect:"non-scaling-stroke" к линии или прямоугольнику
#2 (comment)

Со второй проблемой нужно разобраться в этом тикете.

Видятся решения:

  • пересчитывать размеры вручную
  • разнести линейку (с осями координат и метками) и рабочую область на отдельные компоненты с разными настройками масштабов (рабочий инструмент все равно придется рисовать на рабочей области)
  • как-нибудь извернуться с продвинутыми свойствами SVG, о которых еще не знаю

для затравки:
How to Scale SVG
https://css-tricks.com/scale-svg/

там идет тема, как сделать разные области SVG с разным масштабом

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

Так, самый правильный способ масштабировать одну часть картинки и не масштабировать вторую - мог бы быть использовать атрибут vector-effect="non-scaling-size" (по аналогии с vector-effect="non-scaling-stroke" для немасштабируемой толщины линии).

Проблема в том, что эта фича есть в черновике спецификаций SVG 2.0:
https://svgwg.org/svg2-draft/coords.html#VectorEffects
https://www.w3.org/Graphics/SVG/WG/wiki/SVG2_Requirements_Commitments
https://www.w3.org/2014/01/31-svg-minutes.html#item07
https://www.w3.org/Graphics/SVG/WG/wiki/Proposals/vector_effects_extension

Но вообще нигде не реализовано.

Обсуждение в багзиле Мозилы (есть патч, но не хотят добавлять, пока в остальных браузерах не изъявят желание добавить фичу тоже)
https://bugzilla.mozilla.org/show_bug.cgi?id=1318208

еще обсуждение для Мозилы (есть предложения с альтернативами)
https://groups.google.com/forum/#!topic/mozilla.dev.platform/T_7HTTdt-Es

Тикет для Хромиума
https://bugs.chromium.org/p/chromium/issues/detail?id=691398

Инкскейп
https://bugs.launchpad.net/inkscape/+bug/448286

Таблица фич SVG2 - строка 40 (нигде не рализовано)
https://docs.google.com/spreadsheets/d/1kkqzcxY53h7liRYppLSSFG2sjaJ8V8TCP5rWLZK0AxA/edit#gid=0

Еще варианты
запрос: scale svg while leaving one element unscaled
https://www.yandex.ru/yandsearch?text=scale%20svg%20while%20leaving%20one%20elemtn%20unscaled&sourceid=mozilla-search&lr=116673&redircnt=1494318898.1

Non Scaling Objects / constrained transforms
http://svg2.mbsrv.net/devinfo/devstd/non-scaling-objects-2/

=>
Использовать трансформацию transform-ref (тоже не работает в браузерах, есть только в черновиках спеков)
https://www.w3.org/TR/SVGTiny12/coords.html#transform-ref

Preserve descendant elements' size while scaling the parent element
http://stackoverflow.com/questions/8880668/preserve-descendant-elements-size-while-scaling-the-parent-element

There is transform="ref(svg)" which is defined in SVG Tiny 1.2. To the best of my knowledge this is not implemented in any browsers except Opera (Presto).

Keeping SVG elements to a fixed size while position scales
http://stackoverflow.com/questions/27991472/keeping-svg-elements-to-a-fixed-size-while-position-scales

Еще предлагают использовать elem.getCTM() в яваскрипте (в этом случае еще придется отлавливать события масштабирования).

var circle = document.getElementById('c');
var root = document.getElementById('root');
var matrix = circle.getCTM();
circle.r.baseVal.value /= matrix.a;

Еще getCTM() и другие варианты

Scale independent elements
http://stackoverflow.com/questions/10694347/scale-independent-elements

How to draw non-scalable circle in SVG with Javascript
http://stackoverflow.com/questions/10473328/how-to-draw-non-scalable-circle-in-svg-with-javascript

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

еще близко к теме

https://www.yandex.ru/yandsearch?text=scaled%20svg%20to%20screen%20units&sourceid=mozilla-search&lr=116673&redircnt=1494315957.1

Как попасть мышкой в элемент на отмасштабированном SVG

SVG coordinates with transform matrix
http://stackoverflow.com/questions/4850821/svg-coordinates-with-transform-matrix

ответ в виде интерактивного демо:
http://phrogz.net/svg/drag_under_transformation.xhtml

How do you convert screen coordinates to document space in a scaled SVG?
http://stackoverflow.com/questions/22183727/how-do-you-convert-screen-coordinates-to-document-space-in-a-scaled-svg

везде предлагают использовать getScreenCTM()

про режимы мастшабирования с viewBox и preserveAspectRatio в SVG
https://www.w3.org/TR/SVG11/coords.html#ViewBoxAttribute

единицы измерения SVG
https://www.w3.org/TR/SVG11/coords.html#Units

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

How to Scale SVG
https://css-tricks.com/scale-svg/

там идет тема, как сделать разные области SVG с разным масштабом

предлагают использовать вложенные блоки SVG

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

Еще предлагают использовать elem.getCTM() в яваскрипте (в этом случае еще придется отлавливать события масштабирования).

про масштабирование (изменение размера окна) - есть событие onresize.

https://www.w3schools.com/JSREF/event_onresize.asp
http://help.dottoro.com/ljorlllt.php

 <body onresize="myFunction()"> 

Но приклеить его можно только к окну window или тегу body (на div не сработает).

В реакте сделал следующее:

    render: function() {
        window.onresize = function() {
            console.log("resize");
        }
        ...
    }

все работает, сыпет в консоль сообщениями при любом изменении размеров окна или страницы.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

Для радиуса кружочка сработало вот так:

    window.onresize = function() {
            console.log("resize");
            var circle = document.getElementById('tool_x_y');
            var matrix = circle.getCTM();
            circle.r.baseVal.value = toolMM.z_radius / matrix.a;

здесь toolMM.z_radius - целевое значение радиуса (вычисленное заранее или константа).

делать так, как в примере выше (использовать значение радиуса из элемента):

circle.r.baseVal.value /= matrix.a;

нельзя, т.к. при множественных изменениях размеров окна значение радиуса в дефолтное значение сбрасываеться не будет и при множественных делениях на коэффециент улетит в ноль.

@sadr0b0t
Copy link
Owner Author

sadr0b0t commented May 9, 2017

Решение с кружочком и надписями, не зависящими от масштаба. Еще осталось разобраться с крестиком внутри кружочка с рабочим инструметом (это понятно) и боковыми отступами (это, похоже, будет похитрее).

это отрабатывает только при изменении размеров окна:

    render: function() {
        var lab_txt_size = 12;   
        window.onresize = function() {
            //console.log("resize");
            var circle = document.getElementById('tool_x_y');
            var matrix = circle.getCTM();
            
            document.getElementById('tool_x_y').r.baseVal.value = toolMM.z_radius / matrix.a;
            document.getElementById('lab_xy_0').style.fontSize = lab_txt_size / matrix.a;
            document.getElementById('lab_x').style.fontSize = lab_txt_size / matrix.a;
            document.getElementById('lab_y').style.fontSize = lab_txt_size / matrix.a;
            document.getElementById('lab_z_0').style.fontSize = lab_txt_size / matrix.a;
            document.getElementById('lab_z').style.fontSize = lab_txt_size / matrix.a;
        }
...
    }

при перересовке (и даже первой отрисовке) виджета средствами реакта колбэк вызван не будет и масштаб может быть покорежен.

Помогает вот такой хак (или, может, вполне справедливое решение):

    componentDidMount: function() {
        window.onresize();
    },
    componentDidUpdate: function() {
        window.onresize();
    }

componentDidMount вызывается после первой отрисовки виджета, componentDidUpdate - после каждой перерисовки, оба - после render (это значит, что все элементы уже отправлены в ДОМ).

React.Component, The Component Lifecycle
https://facebook.github.io/react/docs/react-component.html#the-component-lifecycle

@sadr0b0t sadr0b0t changed the title Рисовать линейку (метки на осях координат) и рабочий инструмент одним размером вне зависимости от масштаба рабочей области Рисовать метки на осях координат и рабочий инструмент одним размером вне зависимости от масштаба рабочей области May 11, 2017
@sadr0b0t
Copy link
Owner Author

готово дело
88bffa1

@sadr0b0t
Copy link
Owner Author

не зависят от текущего масштаба:

  • размер меток на осях
  • размеры рабочего инструмента (кружок на поле XY и штрих на оси Z)
  • отступы по краям рабочей области

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant