MutationObserver и window.onresize никогда не останавливаются, даже когда работа выполнена - PullRequest
0 голосов
/ 12 января 2019

Я не очень знаком с этим типом функций (MutationObserver и, возможно, больше ...). Я думал, что могу быть сохранен, установив setTimeout, но нет, он зацикливается на методе this._Resizing, и я понятия не имею, чтобы понять или решить эту проблему.

Идея состоит в том, чтобы сохранить одинаковую шкалу отображения в SVG, даже если окно меняет размер, то же самое, если оно выполняется скриптом. Сначала измените размер окна (размер 50%, и нажмите кнопку для переключения размера 100 / 200 пикселей)

Если я использую объект JS, он точно умножает его, потому что это точно один из принципов объектного программирования.

Код здесь только для иллюстрации моей проблемы, а эта кнопка только для иллюстрации: это принцип примеров.

В моем реальном интерфейсе нет кнопок, но есть другие элементы, которые могут изменить размер и могут повлиять на размер, оставленный для различных элементов SVG.

Вот объект преступления:

const vBxEnum = Object.freeze({ "left": 0, "top": 1, "width": 2, "height": 3 });

class SVG_kit {
  constructor(zID_SVG) {

    this.$_SVG = document.getElementById(zID_SVG);
    this._viewBox = this.$_SVG.getAttribute("viewBox").split(' ').map(v => +v);
    this.svg_rect = this.$_SVG.getBoundingClientRect();

    this._scale = this._viewBox[vBxEnum.width] / this.svg_rect.width;

    // do same ratio for height                    
    this._viewBox[vBxEnum.height] = this.svg_rect.height * this._scale;
    this.$_SVG.setAttribute("viewBox", this._viewBox.join(' '));

    this.TimeOutResize = 0;
    this.count = 0;           // just to see resize infinite loop in action !

    window.onresize = e => this._Resizing();

    let observer4Size = new MutationObserver(m => this._Resizing());

    observer4Size.observe(this.$_SVG, { attributes: true });
  }

  _Resizing() {
    this.TimeOutResize = setTimeout(function (thisObj) {
      console.log('resiz', ++thisObj.count); // resize never stop !

      thisObj.svg_rect = thisObj.$_SVG.getBoundingClientRect();

      thisObj._viewBox[vBxEnum.width] = thisObj.svg_rect.width * thisObj._scale;
      thisObj._viewBox[vBxEnum.height] = thisObj.svg_rect.height * thisObj._scale;

      thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' '));

      clearTimeout(thisObj.TimeOutResize);
    }, 100, this);
  }
} /// SVG_kit

var
  svg_SZ    = '100px',
  svg_E1    = document.getElementById('First-SVG'),
  Sz_Button = document.getElementById("Bt-ChgSize");

var First_SVG = new SVG_kit('First-SVG');

Sz_Button.onclick = function ()
{
  svg_E1.style.width = svg_SZ;
  svg_SZ = (svg_SZ === '100px') ? '200px' : '100px';
}
svg {
  margin: 1em;
  height: 200px;
  width: 50%;
  box-shadow: 0 0 1em #CCC;
  background-color: #8ed1d6;
}
<button id='Bt-ChgSize'>change Size (100px / 200px)</button>

<svg id="First-SVG" viewBox="0 0 1820 480">
  <circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="250" r="200" opacity="0.6" />
</svg>

1 Ответ

0 голосов
/ 12 января 2019

Вы загнали себя в угол с этим кодом.

MutationObserver наблюдает за элементом DOM и всеми его дочерними элементами на предмет изменений либо перемещаемых / добавляемых / удаляемых элементов, либо изменяемых атрибутов.

При инициализации вы просматриваете свой SVG-контейнер, используя его, и проверяете его атрибуты. При изменении чего-либо вам позвонят Resizing().

Однако внутри Resizing, в этой строке:

  thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' '));

Вы изменяете атрибут вашего контейнера SVG, который затем снова вызывает Resizing, и цикл повторяется.

Честно говоря, MutationObserver для этого является излишним и ненужным. Вы прекрасно справляетесь, просто привязывая onResize самостоятельно и обрабатывая событие оттуда (что вы и сделали), но, поскольку вам действительно нужен один , вот код ниже:

const vBxEnum = Object.freeze({ "left": 0, "top": 1, "width": 2, "height": 3 });

class SVG_kit {
  constructor(zID_SVG) {

    this.$_SVG = document.getElementById(zID_SVG);
    this._viewBox = this.$_SVG.getAttribute("viewBox").split(' ').map(v => +v);
    this.svg_rect = this.$_SVG.getBoundingClientRect();

    this._scale = this._viewBox[vBxEnum.width] / this.svg_rect.width;

    // do same ratio for height                    
    this._viewBox[vBxEnum.height] = this.svg_rect.height * this._scale;
    this.$_SVG.setAttribute("viewBox", this._viewBox.join(' '));

    this.TimeOutResize = 0;
    this.count = 0;           // just to see resize infinite loop in action !
    this._width = null;
    window.onresize = e => this._Resizing();
    let observer4Size = new MutationObserver(this._checkStyleChange.bind(this));

    observer4Size.observe(this.$_SVG, { attributes: true });
  }
  _checkStyleChange(mutations) {
    let callResizing = false;
    var element = this.$_SVG;
    var oldWidth = this._width;
    mutations.forEach(function(mutation) {
     if (mutation.target === element && mutation.attributeName === 'style') {
       if (oldWidth !== element.style.width) {
         oldWidth = element.style.width;
         callResizing = true;
        }
      }
    });
    if (callResizing) this._Resizing();
  }

  _Resizing() {
  console.log("Resizing");
  let thisObj = this;

      thisObj.svg_rect = thisObj.$_SVG.getBoundingClientRect();

      thisObj._viewBox[vBxEnum.width] = thisObj.svg_rect.width * thisObj._scale;
      thisObj._viewBox[vBxEnum.height] = thisObj.svg_rect.height * thisObj._scale;

      thisObj.$_SVG.setAttribute("viewBox", thisObj._viewBox.join(' '));

      clearTimeout(thisObj.TimeOutResize);
  }
} /// SVG_kit

var
  svg_SZ    = '100px',
  svg_E1    = document.getElementById('First-SVG'),
  Sz_Button = document.getElementById("Bt-ChgSize");

var First_SVG = new SVG_kit('First-SVG');

Sz_Button.onclick = function ()
{
  svg_E1.style.width = svg_SZ;
  svg_SZ = (svg_SZ === '100px') ? '200px' : '100px';
//  First_SVG._Resizing();
}
svg {
  margin: 1em;
  height: 200px;
  width: 50%;
  box-shadow: 0 0 1em #CCC;
  background-color: #8ed1d6;
}
<button id='Bt-ChgSize'>change Size (100px / 200px)</button>

<svg id="First-SVG" viewBox="0 0 1820 480">
  <circle fill="#F7941E" stroke="#231F20" stroke-width="10" cx="250" cy="250" r="200" opacity="0.6" />
</svg>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...