sadr0b0t / babbler-robots

0 stars 1 forks source link

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

Closed sadr0b0t closed 7 years ago

sadr0b0t commented 7 years ago

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

Выбрать движок SVG для React: система координат https://github.com/1i7/babbler-robots/issues/2

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

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

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

Первая проблема решилась добавлением стиля vector-effect:"non-scaling-stroke" к линии или прямоугольнику https://github.com/1i7/babbler-robots/issues/2#issuecomment-283461267

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

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

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

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

sadr0b0t commented 7 years ago

Так, самый правильный способ масштабировать одну часть картинки и не масштабировать вторую - мог бы быть использовать атрибут 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 commented 7 years ago

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

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 commented 7 years ago

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

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

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

sadr0b0t commented 7 years ago

Еще предлагают использовать 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 commented 7 years ago

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

    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 commented 7 years ago

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

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

    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 commented 7 years ago

готово дело https://github.com/1i7/babbler-robots/commit/88bffa189b248920e2a3b1a90b9b3243c206eb92

sadr0b0t commented 7 years ago

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