forked from enviPath/enviPy
Current Dev State
This commit is contained in:
642
static/js/ketcher2/script/render/restruct/index.js
Normal file
642
static/js/ketcher2/script/render/restruct/index.js
Normal file
@ -0,0 +1,642 @@
|
||||
/****************************************************************************
|
||||
* Copyright 2017 EPAM Systems
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
***************************************************************************/
|
||||
|
||||
// ReStruct is to store all the auxiliary information for
|
||||
// Struct while rendering
|
||||
var Box2Abs = require('../../util/box2abs');
|
||||
var Map = require('../../util/map');
|
||||
var Pool = require('../../util/pool');
|
||||
var Set = require('../../util/set');
|
||||
var Vec2 = require('../../util/vec2');
|
||||
var scale = require('../../util/scale');
|
||||
|
||||
var util = require('../util');
|
||||
var Struct = require('../../chem/struct');
|
||||
|
||||
var ReAtom = require('./reatom');
|
||||
var ReBond = require('./rebond');
|
||||
var ReRxnPlus = require('./rerxnplus');
|
||||
var ReRxnArrow = require('./rerxnarrow');
|
||||
var ReFrag = require('./refrag');
|
||||
var ReRGroup = require('./rergroup');
|
||||
var ReDataSGroupData = require('./redatasgroupdata');
|
||||
var ReChiralFlag = require('./rechiralflag');
|
||||
var ReSGroup = require('./resgroup');
|
||||
var ReLoop = require('./reloop');
|
||||
|
||||
var LAYER_MAP = {
|
||||
background: 0,
|
||||
selectionPlate: 1,
|
||||
highlighting: 2,
|
||||
warnings: 3,
|
||||
data: 4,
|
||||
indices: 5
|
||||
};
|
||||
|
||||
function ReStruct(molecule, render) { // eslint-disable-line max-statements
|
||||
this.render = render;
|
||||
this.atoms = new Map();
|
||||
this.bonds = new Map();
|
||||
this.reloops = new Map();
|
||||
this.rxnPluses = new Map();
|
||||
this.rxnArrows = new Map();
|
||||
this.frags = new Map();
|
||||
this.rgroups = new Map();
|
||||
this.sgroups = new Map();
|
||||
this.sgroupData = new Map();
|
||||
this.chiralFlags = new Map();
|
||||
this.molecule = molecule || new Struct();
|
||||
this.initialized = false;
|
||||
this.layers = [];
|
||||
this.initLayers();
|
||||
|
||||
this.connectedComponents = new Pool();
|
||||
this.ccFragmentType = new Map();
|
||||
|
||||
for (var map in ReStruct.maps)
|
||||
this[map + 'Changed'] = {};
|
||||
this.structChanged = false;
|
||||
|
||||
// TODO: eachItem ?
|
||||
molecule.atoms.each(function (aid, atom) {
|
||||
this.atoms.set(aid, new ReAtom(atom));
|
||||
}, this);
|
||||
|
||||
molecule.bonds.each(function (bid, bond) {
|
||||
this.bonds.set(bid, new ReBond(bond));
|
||||
}, this);
|
||||
|
||||
molecule.loops.each(function (lid, loop) {
|
||||
this.reloops.set(lid, new ReLoop(loop));
|
||||
}, this);
|
||||
|
||||
molecule.rxnPluses.each(function (id, item) {
|
||||
this.rxnPluses.set(id, new ReRxnPlus(item));
|
||||
}, this);
|
||||
|
||||
molecule.rxnArrows.each(function (id, item) {
|
||||
this.rxnArrows.set(id, new ReRxnArrow(item));
|
||||
}, this);
|
||||
|
||||
molecule.frags.each(function (id, item) {
|
||||
this.frags.set(id, new ReFrag(item));
|
||||
}, this);
|
||||
|
||||
molecule.rgroups.each(function (id, item) {
|
||||
this.rgroups.set(id, new ReRGroup(item));
|
||||
}, this);
|
||||
|
||||
molecule.sgroups.each(function (id, item) {
|
||||
this.sgroups.set(id, new ReSGroup(item));
|
||||
if (item.type === 'DAT' && !item.data.attached)
|
||||
this.sgroupData.set(id, new ReDataSGroupData(item)); // [MK] sort of a hack, we use the SGroup id for the data field id
|
||||
}, this);
|
||||
|
||||
if (molecule.isChiral) {
|
||||
var bb = molecule.getCoordBoundingBox();
|
||||
this.chiralFlags.set(0, new ReChiralFlag(new Vec2(bb.max.x, bb.min.y - 1)));
|
||||
}
|
||||
}
|
||||
|
||||
ReStruct.prototype.connectedComponentRemoveAtom = function (aid, atom) {
|
||||
atom = atom || this.atoms.get(aid);
|
||||
if (atom.component < 0)
|
||||
return;
|
||||
var cc = this.connectedComponents.get(atom.component);
|
||||
Set.remove(cc, aid);
|
||||
if (Set.size(cc) < 1)
|
||||
this.connectedComponents.remove(atom.component);
|
||||
|
||||
atom.component = -1;
|
||||
};
|
||||
|
||||
ReStruct.prototype.clearConnectedComponents = function () {
|
||||
this.connectedComponents.clear();
|
||||
this.atoms.each(function (aid, atom) {
|
||||
atom.component = -1;
|
||||
});
|
||||
};
|
||||
|
||||
ReStruct.prototype.getConnectedComponent = function (aid, adjacentComponents) {
|
||||
var list = (typeof (aid['length']) === 'number') ? [].slice.call(aid) : [aid];
|
||||
var ids = Set.empty();
|
||||
|
||||
while (list.length > 0) {
|
||||
(function () {
|
||||
var aid = list.pop();
|
||||
Set.add(ids, aid);
|
||||
var atom = this.atoms.get(aid);
|
||||
if (atom.component >= 0)
|
||||
Set.add(adjacentComponents, atom.component);
|
||||
for (var i = 0; i < atom.a.neighbors.length; ++i) {
|
||||
var neiId = this.molecule.halfBonds.get(atom.a.neighbors[i]).end;
|
||||
if (!Set.contains(ids, neiId))
|
||||
list.push(neiId);
|
||||
}
|
||||
}).apply(this);
|
||||
}
|
||||
|
||||
return ids;
|
||||
};
|
||||
|
||||
ReStruct.prototype.addConnectedComponent = function (ids) {
|
||||
var compId = this.connectedComponents.add(ids);
|
||||
var adjacentComponents = Set.empty();
|
||||
var atomIds = this.getConnectedComponent(Set.list(ids), adjacentComponents);
|
||||
Set.remove(adjacentComponents, compId);
|
||||
var type = -1;
|
||||
Set.each(atomIds, function (aid) {
|
||||
var atom = this.atoms.get(aid);
|
||||
atom.component = compId;
|
||||
if (atom.a.rxnFragmentType != -1) {
|
||||
if (type != -1 && atom.a.rxnFragmentType != type)
|
||||
throw new Error('reaction fragment type mismatch');
|
||||
type = atom.a.rxnFragmentType;
|
||||
}
|
||||
}, this);
|
||||
|
||||
this.ccFragmentType.set(compId, type);
|
||||
return compId;
|
||||
};
|
||||
|
||||
ReStruct.prototype.removeConnectedComponent = function (ccid) {
|
||||
Set.each(this.connectedComponents.get(ccid), function (aid) {
|
||||
this.atoms.get(aid).component = -1;
|
||||
}, this);
|
||||
return this.connectedComponents.remove(ccid);
|
||||
};
|
||||
|
||||
// TODO: remove? not used
|
||||
ReStruct.prototype.connectedComponentMergeIn = function (ccid, set) {
|
||||
Set.each(set, function (aid) {
|
||||
this.atoms.get(aid).component = ccid;
|
||||
}, this);
|
||||
Set.mergeIn(this.connectedComponents.get(ccid), set);
|
||||
};
|
||||
|
||||
ReStruct.prototype.assignConnectedComponents = function () {
|
||||
this.atoms.each(function (aid, atom) {
|
||||
if (atom.component >= 0)
|
||||
return;
|
||||
var adjacentComponents = Set.empty();
|
||||
var ids = this.getConnectedComponent(aid, adjacentComponents);
|
||||
Set.each(adjacentComponents, function (ccid) {
|
||||
this.removeConnectedComponent(ccid);
|
||||
}, this);
|
||||
this.addConnectedComponent(ids);
|
||||
}, this);
|
||||
};
|
||||
|
||||
// TODO: remove? not used
|
||||
ReStruct.prototype.connectedComponentGetBoundingBox = function (ccid, cc, bb) {
|
||||
cc = cc || this.connectedComponents.get(ccid);
|
||||
bb = bb || { min: null, max: null };
|
||||
Set.each(cc, function (aid) {
|
||||
var ps = scale.obj2scaled(this.atoms.get(aid).a.pp, this.render.options);
|
||||
if (bb.min == null) {
|
||||
bb.min = bb.max = ps;
|
||||
} else {
|
||||
bb.min = bb.min.min(ps);
|
||||
bb.max = bb.max.max(ps);
|
||||
}
|
||||
}, this);
|
||||
return bb;
|
||||
};
|
||||
|
||||
ReStruct.prototype.initLayers = function () {
|
||||
for (var group in LAYER_MAP) {
|
||||
this.layers[LAYER_MAP[group]] =
|
||||
this.render.paper.rect(0, 0, 10, 10)
|
||||
.attr({
|
||||
class: group + 'Layer',
|
||||
fill: '#000',
|
||||
opacity: '0.0'
|
||||
}).toFront();
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.addReObjectPath = function (group, visel, path, pos, visible) { // eslint-disable-line max-params
|
||||
if (!path || !this.layers[LAYER_MAP[group]].node.parentNode)
|
||||
return;
|
||||
var offset = this.render.options.offset;
|
||||
var bb = visible ? Box2Abs.fromRelBox(util.relBox(path.getBBox())) : null;
|
||||
var ext = pos && bb ? bb.translate(pos.negated()) : null;
|
||||
if (offset !== null) {
|
||||
path.translateAbs(offset.x, offset.y);
|
||||
bb = bb ? bb.translate(offset) : null;
|
||||
}
|
||||
visel.add(path, bb, ext);
|
||||
path.insertBefore(this.layers[LAYER_MAP[group]]);
|
||||
};
|
||||
|
||||
ReStruct.prototype.clearMarks = function () {
|
||||
for (var map in ReStruct.maps)
|
||||
this[map + 'Changed'] = {};
|
||||
this.structChanged = false;
|
||||
};
|
||||
|
||||
ReStruct.prototype.markItemRemoved = function () {
|
||||
this.structChanged = true;
|
||||
};
|
||||
|
||||
ReStruct.prototype.markBond = function (bid, mark) {
|
||||
this.markItem('bonds', bid, mark);
|
||||
};
|
||||
|
||||
ReStruct.prototype.markAtom = function (aid, mark) {
|
||||
this.markItem('atoms', aid, mark);
|
||||
};
|
||||
|
||||
ReStruct.prototype.markItem = function (map, id, mark) {
|
||||
var mapChanged = this[map + 'Changed'];
|
||||
mapChanged[id] = (typeof (mapChanged[id]) !== 'undefined') ?
|
||||
Math.max(mark, mapChanged[id]) : mark;
|
||||
if (this[map].has(id))
|
||||
this.clearVisel(this[map].get(id).visel);
|
||||
};
|
||||
|
||||
ReStruct.prototype.clearVisel = function (visel) {
|
||||
for (var i = 0; i < visel.paths.length; ++i)
|
||||
visel.paths[i].remove();
|
||||
visel.clear();
|
||||
};
|
||||
|
||||
ReStruct.prototype.eachItem = function (func, context) {
|
||||
for (var map in ReStruct.maps) {
|
||||
this[map].each(function (id, item) {
|
||||
func.call(context, item);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.getVBoxObj = function (selection) {
|
||||
selection = selection || {};
|
||||
if (isSelectionEmpty(selection)) {
|
||||
for (var map in ReStruct.maps)
|
||||
if (ReStruct.maps.hasOwnProperty(map)) selection[map] = this[map].keys();
|
||||
}
|
||||
var vbox = null;
|
||||
for (map in ReStruct.maps) {
|
||||
if (ReStruct.maps.hasOwnProperty(map) && selection[map]) {
|
||||
selection[map].forEach(function (id) {
|
||||
var box = this[map].get(id).getVBoxObj(this.render);
|
||||
if (box)
|
||||
vbox = vbox ? Box2Abs.union(vbox, box) : box.clone();
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
vbox = vbox || new Box2Abs(0, 0, 0, 0);
|
||||
return vbox;
|
||||
};
|
||||
|
||||
function isSelectionEmpty(selection) {
|
||||
if (selection) {
|
||||
for (var map in ReStruct.maps) {
|
||||
if (ReStruct.maps.hasOwnProperty(map) && selection[map] && selection[map].length > 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ReStruct.prototype.translate = function (d) {
|
||||
this.eachItem(function (item) {
|
||||
item.visel.translate(d);
|
||||
});
|
||||
};
|
||||
|
||||
ReStruct.prototype.scale = function (s) {
|
||||
// NOTE: bounding boxes are not valid after scaling
|
||||
this.eachItem(function (item) {
|
||||
scaleVisel(item.visel, s);
|
||||
});
|
||||
};
|
||||
|
||||
function scaleRPath(path, s) {
|
||||
if (path.type == 'set') { // TODO: rework scaling
|
||||
for (var i = 0; i < path.length; ++i)
|
||||
scaleRPath(path[i], s);
|
||||
} else {
|
||||
if (!(typeof path.attrs === 'undefined')) {
|
||||
if ('font-size' in path.attrs)
|
||||
path.attr('font-size', path.attrs['font-size'] * s);
|
||||
else if ('stroke-width' in path.attrs)
|
||||
path.attr('stroke-width', path.attrs['stroke-width'] * s);
|
||||
}
|
||||
path.scale(s, s, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function scaleVisel(visel, s) {
|
||||
for (var i = 0; i < visel.paths.length; ++i)
|
||||
scaleRPath(visel.paths[i], s);
|
||||
}
|
||||
|
||||
ReStruct.prototype.clearVisels = function () {
|
||||
this.eachItem(function (item) {
|
||||
this.clearVisel(item.visel);
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.update = function (force) { // eslint-disable-line max-statements
|
||||
force = force || !this.initialized;
|
||||
|
||||
// check items to update
|
||||
var id, map, mapChanged;
|
||||
if (force) {
|
||||
for (map in ReStruct.maps) {
|
||||
if (ReStruct.maps.hasOwnProperty(map)) {
|
||||
mapChanged = this[map + 'Changed'];
|
||||
this[map].each(function (id) {
|
||||
mapChanged[id] = 1;
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check if some of the items marked are already gone
|
||||
for (map in ReStruct.maps) {
|
||||
if (ReStruct.maps.hasOwnProperty(map)) {
|
||||
mapChanged = this[map + 'Changed'];
|
||||
for (id in mapChanged) {
|
||||
if (!this[map].has(id)) // eslint-disable-line max-depth
|
||||
delete mapChanged[id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (id in this.atomsChanged)
|
||||
this.connectedComponentRemoveAtom(id);
|
||||
|
||||
// clean up empty fragments
|
||||
// TODO: fragment removal should be triggered by the action responsible for the fragment contents removal and form an operation of its own
|
||||
var emptyFrags = this.frags.findAll(function (fid, frag) {
|
||||
return !frag.calcBBox(this.render.ctab, fid, this.render);
|
||||
}, this);
|
||||
for (var j = 0; j < emptyFrags.length; ++j) {
|
||||
var fid = emptyFrags[j];
|
||||
this.clearVisel(this.frags.get(fid).visel);
|
||||
this.frags.unset(fid);
|
||||
this.molecule.frags.remove(fid);
|
||||
}
|
||||
|
||||
for (map in ReStruct.maps) {
|
||||
mapChanged = this[map + 'Changed'];
|
||||
for (id in mapChanged) {
|
||||
this.clearVisel(this[map].get(id).visel);
|
||||
this.structChanged |= mapChanged[id] > 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: when to update sgroup?
|
||||
this.sgroups.each(function (sid, sgroup) {
|
||||
this.clearVisel(sgroup.visel);
|
||||
sgroup.highlighting = null;
|
||||
sgroup.selectionPlate = null;
|
||||
}, this);
|
||||
|
||||
// TODO [RB] need to implement update-on-demand for fragments and r-groups
|
||||
this.frags.each(function (frid, frag) {
|
||||
this.clearVisel(frag.visel);
|
||||
}, this);
|
||||
this.rgroups.each(function (rgid, rgroup) {
|
||||
this.clearVisel(rgroup.visel);
|
||||
}, this);
|
||||
|
||||
if (force) { // clear and recreate all half-bonds
|
||||
this.clearConnectedComponents();
|
||||
this.molecule.initHalfBonds();
|
||||
this.molecule.initNeighbors();
|
||||
}
|
||||
|
||||
// only update half-bonds adjacent to atoms that have moved
|
||||
this.molecule.updateHalfBonds(new Map(this.atomsChanged).findAll(function (aid, status) {
|
||||
return status >= 0;
|
||||
}, this));
|
||||
this.molecule.sortNeighbors(new Map(this.atomsChanged).findAll(function (aid, status) {
|
||||
return status >= 1;
|
||||
}, this));
|
||||
this.assignConnectedComponents();
|
||||
this.setImplicitHydrogen();
|
||||
this.initialized = true;
|
||||
|
||||
this.verifyLoops();
|
||||
var updLoops = force || this.structChanged;
|
||||
if (updLoops)
|
||||
this.updateLoops();
|
||||
this.showLabels();
|
||||
this.showBonds();
|
||||
if (updLoops)
|
||||
this.showLoops();
|
||||
this.showReactionSymbols();
|
||||
this.showSGroups();
|
||||
this.showFragments();
|
||||
this.showRGroups();
|
||||
if (this.render.options.hideChiralFlag !== true) {
|
||||
this.chiralFlags.each(function (id, item) {
|
||||
item.show(this, id, this.render.options);
|
||||
}, this);
|
||||
}
|
||||
this.clearMarks();
|
||||
return true;
|
||||
};
|
||||
|
||||
ReStruct.prototype.updateLoops = function () {
|
||||
this.reloops.each(function (rlid, reloop) {
|
||||
this.clearVisel(reloop.visel);
|
||||
}, this);
|
||||
var ret = this.molecule.findLoops();
|
||||
ret.bondsToMark.forEach(function (bid) {
|
||||
this.markBond(bid, 1);
|
||||
}, this);
|
||||
ret.newLoops.forEach(function (loopId) {
|
||||
this.reloops.set(loopId, new ReLoop(this.molecule.loops.get(loopId)));
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.showLoops = function () {
|
||||
var options = this.render.options;
|
||||
this.reloops.each(function (rlid, reloop) {
|
||||
reloop.show(this, rlid, options);
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.showReactionSymbols = function () {
|
||||
var options = this.render.options;
|
||||
var item;
|
||||
var id;
|
||||
for (id in this.rxnArrowsChanged) {
|
||||
item = this.rxnArrows.get(id);
|
||||
item.show(this, id, options);
|
||||
}
|
||||
for (id in this.rxnPlusesChanged) {
|
||||
item = this.rxnPluses.get(id);
|
||||
item.show(this, id, options);
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.showSGroups = function () {
|
||||
var options = this.render.options;
|
||||
this.molecule.sGroupForest.getSGroupsBFS().reverse().forEach(function (id) {
|
||||
var resgroup = this.sgroups.get(id);
|
||||
resgroup.show(this, id, options);
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.showFragments = function () {
|
||||
this.frags.each(function (id, frag) {
|
||||
var path = frag.draw(this.render, id);
|
||||
if (path) this.addReObjectPath('data', frag.visel, path, null, true);
|
||||
// TODO fragment selection & highlighting
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.showRGroups = function () {
|
||||
var options = this.render.options;
|
||||
this.rgroups.each(function (id, rgroup) {
|
||||
rgroup.show(this, id, options);
|
||||
}, this);
|
||||
};
|
||||
|
||||
ReStruct.prototype.eachCC = function (func, type, context) {
|
||||
this.connectedComponents.each(function (ccid, cc) {
|
||||
if (!type || this.ccFragmentType.get(ccid) == type)
|
||||
func.call(context || this, ccid, cc);
|
||||
}, this);
|
||||
};
|
||||
|
||||
// TODO: remove? not used
|
||||
ReStruct.prototype.getGroupBB = function (type) {
|
||||
var bb = { min: null, max: null };
|
||||
|
||||
this.eachCC(function (ccid, cc) {
|
||||
bb = this.connectedComponentGetBoundingBox(ccid, cc, bb);
|
||||
}, type, this);
|
||||
|
||||
return bb;
|
||||
};
|
||||
|
||||
ReStruct.prototype.setImplicitHydrogen = function () {
|
||||
// calculate implicit hydrogens for atoms that have been modified
|
||||
this.molecule.setImplicitHydrogen(Object.keys(this.atomsChanged));
|
||||
};
|
||||
|
||||
ReStruct.prototype.loopRemove = function (loopId) {
|
||||
if (!this.reloops.has(loopId))
|
||||
return;
|
||||
var reloop = this.reloops.get(loopId);
|
||||
this.clearVisel(reloop.visel);
|
||||
var bondlist = [];
|
||||
for (var i = 0; i < reloop.loop.hbs.length; ++i) {
|
||||
var hbid = reloop.loop.hbs[i];
|
||||
if (this.molecule.halfBonds.has(hbid)) {
|
||||
var hb = this.molecule.halfBonds.get(hbid);
|
||||
hb.loop = -1;
|
||||
this.markBond(hb.bid, 1);
|
||||
this.markAtom(hb.begin, 1);
|
||||
bondlist.push(hb.bid);
|
||||
}
|
||||
}
|
||||
this.reloops.unset(loopId);
|
||||
this.molecule.loops.remove(loopId);
|
||||
};
|
||||
|
||||
ReStruct.prototype.verifyLoops = function () {
|
||||
var toRemove = [];
|
||||
this.reloops.each(function (rlid, reloop) {
|
||||
if (!reloop.isValid(this.molecule, rlid))
|
||||
toRemove.push(rlid);
|
||||
}, this);
|
||||
for (var i = 0; i < toRemove.length; ++i)
|
||||
this.loopRemove(toRemove[i]);
|
||||
};
|
||||
|
||||
ReStruct.prototype.showLabels = function () { // eslint-disable-line max-statements
|
||||
var options = this.render.options;
|
||||
|
||||
for (var aid in this.atomsChanged) {
|
||||
var atom = this.atoms.get(aid);
|
||||
atom.show(this, aid, options);
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.showBonds = function () { // eslint-disable-line max-statements
|
||||
var options = this.render.options;
|
||||
|
||||
for (var bid in this.bondsChanged) {
|
||||
var bond = this.bonds.get(bid);
|
||||
bond.show(this, bid, options);
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.setSelection = function (selection) {
|
||||
var redraw = (arguments.length === 0); // render.update only
|
||||
|
||||
for (var map in ReStruct.maps) {
|
||||
if (ReStruct.maps.hasOwnProperty(map) && ReStruct.maps[map].isSelectable()) {
|
||||
this[map].each(function (id, item) {
|
||||
var selected = redraw ? item.selected :
|
||||
selection && selection[map] && selection[map].indexOf(id) > -1;
|
||||
this.showItemSelection(item, selected);
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.prototype.showItemSelection = function (item, selected) {
|
||||
var exists = item.selectionPlate != null && !item.selectionPlate.removed;
|
||||
// TODO: simplify me, who sets `removed`?
|
||||
item.selected = selected;
|
||||
if (item instanceof ReDataSGroupData) item.sgroup.selected = selected;
|
||||
if (selected) {
|
||||
if (!exists) {
|
||||
var render = this.render;
|
||||
var options = render.options;
|
||||
var paper = render.paper;
|
||||
|
||||
item.selectionPlate = item.makeSelectionPlate(this, paper, options);
|
||||
this.addReObjectPath('selectionPlate', item.visel, item.selectionPlate);
|
||||
}
|
||||
if (item.selectionPlate)
|
||||
item.selectionPlate.show(); // TODO [RB] review
|
||||
} else
|
||||
if (exists && item.selectionPlate) {
|
||||
item.selectionPlate.hide(); // TODO [RB] review
|
||||
}
|
||||
};
|
||||
|
||||
ReStruct.maps = {
|
||||
atoms: ReAtom,
|
||||
bonds: ReBond,
|
||||
rxnPluses: ReRxnPlus,
|
||||
rxnArrows: ReRxnArrow,
|
||||
frags: ReFrag,
|
||||
rgroups: ReRGroup,
|
||||
sgroupData: ReDataSGroupData,
|
||||
chiralFlags: ReChiralFlag,
|
||||
sgroups: ReSGroup,
|
||||
reloops: ReLoop
|
||||
};
|
||||
|
||||
module.exports = Object.assign(ReStruct, {
|
||||
Atom: ReAtom,
|
||||
Bond: ReBond,
|
||||
RxnPlus: ReRxnPlus,
|
||||
RxnArrow: ReRxnArrow,
|
||||
Frag: ReFrag,
|
||||
RGroup: ReRGroup,
|
||||
ChiralFlag: ReChiralFlag,
|
||||
SGroup: ReSGroup
|
||||
});
|
||||
Reference in New Issue
Block a user