_dirtyCheck() {
      this._dirtyAll = true;
      const items = this._dirty;
      if (!items.length || !this._dirtyID) return true;
      const id = ++this._dirtyID;
      let item, mark, type, mdef, i, n, o;
      for (i = 0, n = items.length; i < n; ++i) {
        item = items[i];
        mark = item.mark;
        if (mark.marktype !== type) {
          // memoize mark instance lookup
          type = mark.marktype;
          mdef = Marks[type];
        }
        if (mark.zdirty && mark.dirty !== id) {
          this._dirtyAll = false;
          dirtyParents(item, id);
          mark.items.forEach(i => {
            i.dirty = id;
          });
        }
        if (mark.zdirty) continue; // handle in standard drawing pass

        if (item.exit) {
          // EXIT
          if (mdef.nested && mark.items.length) {
            // if nested mark with remaining points, update instead
            o = mark.items[0];
            if (o._svg) this._update(mdef, o._svg, o);
          } else if (item._svg) {
            // otherwise remove from DOM
            o = item._svg.parentNode;
            if (o) o.removeChild(item._svg);
          }
          item._svg = null;
          continue;
        }
        item = mdef.nested ? mark.items[0] : item;
        if (item._update === id) continue; // already visited

        if (!item._svg || !item._svg.ownerSVGElement) {
          // ENTER
          this._dirtyAll = false;
          dirtyParents(item, id);
        } else {
          // IN-PLACE UPDATE
          this._update(mdef, item._svg, item);
        }
        item._update = id;
      }
      return !this._dirtyAll;
    }
Internal method to check dirty status and, if possible,
make targetted updates without a full rendering pass.