[英]d3js Moving SVG elements inside a transforming group
我正在研究一個查詢生成器項目。 我正在嘗試使用d3.js構建查詢生成器。 我陷入了要在轉換組內移動某些元素的部分。 這是回購協議 ,我被困在此功能中 。 連接后,我想移動操作員並更新連接的線。 誰能幫我?
var circleDrag = d3.behavior.drag()
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
})
.on('drag', function () {
var parentQboxGroupId = d3.select(this).select(function () {
return this.parentNode;
});
var grandParent = parentQboxGroupId.select(function(){
return this.parentNode;
});
var drawingGroup = d3.select('#'+grandParent.attr('id'));
var currentC = d3.select(this);
dragging = true;
drawingGroup
.select('.lineInsideQbox')
.attr('x1', currentC.attr('cx'))
.attr('y1', currentC.attr('cy'))
.style('stroke','green')
.style('stroke-width','2px');
dummyLine.src = currentC.attr('id');
console.log('CIRCLE IS BEING DRAGGED' + JSON.stringify(dummyLine));
})
.on('dragend', function () {
console.log('drag circle end');
//if(!selectedCircle.id){
// dummyLine.target = selectedQbox.id;
//}
dummyLine.target = selectedCircle.id;
dragging = false;
console.log('DRAG END : SELCTED NODE : '+ JSON.stringify(selectedCircle));
console.log('DRAG END : DUMMY LINE : '+ JSON.stringify(dummyLine));
var targetNode = d3.select('#'+dummyLine.target);
var srcNode = d3.select('#'+dummyLine.src);
console.log('split : ' + dummyLine.src.split('--'));
var group = '#' + (dummyLine.src).split('--')[1];
console.log('G: ' + group);
d3.select(group).append('line')
.attr('id', function () {
var a = (dummyLine.src).split('--');
var b = (dummyLine.target).split('--');
if( a[0]== 'nodeRight'){
return dummyLine.src + '__' + dummyLine.target;
}else{
return dummyLine.target + '__' + dummyLine.src;
}
})
.attr('class', function () {
var a = (dummyLine.src).split('--');
var b = (dummyLine.target).split('--');
return 'line '+ a[1]+' '+b[1];
})
.attr('x1', srcNode.attr('cx'))
.attr('y1',srcNode.attr('cy'))
.attr('x2',targetNode.attr('cx'))
.attr('y2',targetNode.attr('cy'))
.style('stroke', 'black')
.style('stroke-width', '3px')
;
dummyLine.src = null;
dummyLine.target = null;
});
編輯:當我嘗試刪除查詢框。 我可以在其中放其他運算符。 然后,我應該可以將它們連接到內部。 這是顯示我正在嘗試的圖像。
建立連接后,我嘗試分別移動大型操作箱和小型操作員。 那就是代碼中斷的地方。
主要問題是要移動運算符,請使用平移來移動整個組(標簽),其中包括圖像,兩個圓圈和一條直線。 然后,使用連接的另一運算符的CX,CY值設置該行的另一端。 這將行不通,因為執行平移時不會更新圓的CX和CY值,因此,第二步移動時,會將x,y值放在圓的原始點,而不是移動的點。 要解決,而不是翻譯整個組,只翻譯圖像,更新圓的cx和cy值,然后使用新的圓cx,cy更新線x,y值:
所有需要的修改都在您的operatorDrag.js文件中。 首先,當您添加圓時,添加一個屬性,該屬性包含原始的cx和cy值。 在計算新的cx時需要這些,在拖動運算符時需要cy:
從此更改:
var op = currGroup
.append('image')
.attr('class', 'operator')
.attr('width', elem.attr('width') * 0.75)
.attr('height', elem.attr('height') * 0.75)
.attr('x', d3.mouse(this)[0])
.attr('y', d3.mouse(this)[1])
.attr('xlink:href', elem.attr('href'));
currGroup
.append('circle')
.attr('class', 'node nodeLeft')
.attr('id', function () {
return 'nodeLeft--' + currGroup.attr('id');
})
.attr('cx', op.attr('x'))
.attr('cy', op.attr('height') / 2 + Number(op.attr('y')))
.attr('r', 5)
.style('fill', 'red')
.on('mouseover', function () {
selectedCircle = {
id: d3.select(this).attr('id'),
cls: 'nodeLeft'
}
})
.call(circleDrag)
;
currGroup
.append('circle')
.attr('class', 'node nodeRight')
.attr('id', function () {
return 'nodeRight--' + currGroup.attr('id');
})
.attr('cx', Number(op.attr('x')) + Number(op.attr('width')))
.attr('cy', op.attr('height') / 2 + Number(op.attr('y')))
.attr('r', 5)
.style('fill', 'red')
.on('mouseover', function () {
selectedCircle = {
id: d3.select(this).attr('id'),
cls: 'nodeRight'
}
})
.call(circleDrag)
;
為此(更新的代碼包含在以#SB開頭的注釋中):
var op = currGroup
.append('image')
.attr('class', 'operator')
.attr('width', elem.attr('width') * 0.75)
.attr('height', elem.attr('height') * 0.75)
.attr('x', d3.mouse(this)[0])
.attr('y', d3.mouse(this)[1])
.attr('xlink:href', elem.attr('href'));
currGroup
.append('circle')
.attr('class', 'node nodeLeft')
.attr('id', function () {
return 'nodeLeft--' + currGroup.attr('id');
})
.attr('cx', op.attr('x'))
.attr('cy', op.attr('height') / 2 + Number(op.attr('y')))
// #SB: add a reference to the original cx and cy position.
// we will need it to set new cx cy when moving operator
.attr('data-cx', op.attr('x'))
.attr('data-cy', op.attr('height') / 2 + Number(op.attr('y')))
//----------------------------------------------------------------------
.attr('r', 5)
.style('fill', 'red')
.on('mouseover', function () {
selectedCircle = {
id: d3.select(this).attr('id'),
cls: 'nodeLeft'
}
})
.call(circleDrag)
;
currGroup
.append('circle')
.attr('class', 'node nodeRight')
.attr('id', function () {
return 'nodeRight--' + currGroup.attr('id');
})
.attr('cx', Number(op.attr('x')) + Number(op.attr('width')))
.attr('cy', op.attr('height') / 2 + Number(op.attr('y')))
// #SB: add a reference to the original cx and cy position.
// we will need it to set new cx cy when moving operator
.attr('data-cx', Number(op.attr('x')) + Number(op.attr('width')))
.attr('data-cy', op.attr('height') / 2 + Number(op.attr('y')))
//----------------------------------------------------------------------
.attr('r', 5)
.style('fill', 'red')
.on('mouseover', function () {
selectedCircle = {
id: d3.select(this).attr('id'),
cls: 'nodeRight'
}
})
.call(circleDrag)
;
完成此操作后,請轉到操作員的拖動方法。 這是我們要更改的代碼:
.on('drag', function () {
var g = d3.select(this);
var currentOp = g.select('.operator');
var parent = g.select(function () {
return this.parentNode;
}).select('.qbox');
var dx = d3.event.x;
var dy = d3.event.y;
var mouse = {dx: d3.event.x, dy: d3.event.y};
var currentObj = {
x: currentOp.attr('x'),
y: currentOp.attr('y'),
width: currentOp.attr('width'),
height: currentOp.attr('height')
};
var parentObj = {
x: parent.attr('x'),
y: parent.attr('y'),
width: parent.attr('width'),
height: parent.attr('height')
};
//console.log('parent width : ' + parent.attr('width'));
//console.log('parent width : ' + currentOp.attr('width'));
//g.attr('transform', 'translate(' + x + ',' + y + ')');
var loc = getXY(mouse, currentObj, parentObj);
g.attr('transform', 'translate(' + loc.x + ',' + loc.y + ')');
d3.select('#' + g.attr('id')).selectAll('.line')[0].forEach(function (e1) {
var line = d3.select(e1);
console.log('-------------------');
console.log('line : ' + line.attr('id'));
console.log('-------------------');
var split = line.attr('id').split('__');
if(g.attr('id') == split[0]){
//change x2, y2
var otherNode = d3.select('#'+split[1]);
line.attr('x2', otherNode.attr('cx'));
line.attr('y2', otherNode.attr('cy'));
}else{
var otherNode = d3.select('#'+split[0]);
line.attr('x1', otherNode.attr('cx'));
line.attr('y1', otherNode.attr('cy'));
}
})
}))
第一件事是,不翻譯整個對象,僅翻譯圖像:
var g = d3.select(this);
var currentOp = g.select('.operator');
var parent = g.select(function () {
return this.parentNode;
}).select('.qbox');
//#SB: added a reference to the parent id
var parent_id = g.select(function () {
return this.parentNode;
}).attr('id');
//---------------------------------------
var dx = d3.event.x;
var dy = d3.event.y;
var mouse = {dx: d3.event.x, dy: d3.event.y};
var currentObj = {
x: currentOp.attr('x'),
y: currentOp.attr('y'),
width: currentOp.attr('width'),
height: currentOp.attr('height')
};
var parentObj = {
x: parent.attr('x'),
y: parent.attr('y'),
width: parent.attr('width'),
height: parent.attr('height')
};
var loc = getXY(mouse, currentObj, parentObj);
//#SB: Do not translate everything, the cx, cy values of the circle are not updated
// when translating which will make future moves calculate incorrectly
g.selectAll('image').attr('transform', 'translate(' + loc.x + ',' + loc.y + ')');
然后,不要平移圓,而是使用原始cx,cy和translate值更改其cx和cy值:
g.selectAll('circle')
.attr('cx', function () {
return parseFloat(d3.select(this).attr('data-cx')) + parseFloat(loc.x);
})
.attr('cy', function () {
return parseFloat(d3.select(this).attr('data-cy')) + parseFloat(loc.y);
});
最后一件事是更新行。 在原始代碼中,您選擇了運算符組中的所有行,但實際上僅選擇此組將錯過某些行。 某些線路可以是另一個操作員組的一部分,但可以連接到正在移動的操作員。 在這種情況下,我們應該選擇父組中的所有線路,並檢查線路是否連接到我們要移動的操作員。 如果已連接,則我們更新x和y值:
//#SB: Select all the lines in the parent group instead of only group of the
// operator we are moving. There can be lines that exists on other groups that
// do not exist within the group that is being moved.
d3.select('#' + parent_id).selectAll('.line')[0].forEach(function (el) {
var parent_id = g.attr('id')
var line = d3.select(el)
var nodeType = line.attr('id').split("__"); // id tells us if the line is connected to the left or right node
var operators = line.attr('class').split(" "); // class holds info on what operators the line is connected to
var sourceCircleId = nodeType[0].split("--")[0] + '--' + operators[1];
var targetCircleId = nodeType[1].split("--")[0] + '--' + operators[2];
if (parent_id == operators[1] || parent_id == operators[2]) { // the line is connected to the operator we are moving
line.attr('x1', d3.select('#' + sourceCircleId).attr('cx'))
line.attr('y1', d3.select('#' + sourceCircleId).attr('cy'))
line.attr('x2', d3.select('#' + targetCircleId).attr('cx'))
line.attr('y2', d3.select('#' + targetCircleId).attr('cy'))
}
});
完整的OnDrag代碼:
.on('drag', function () {
var g = d3.select(this);
var currentOp = g.select('.operator');
var parent = g.select(function () {
return this.parentNode;
}).select('.qbox');
//#SB: added a reference to the parent id
var parent_id = g.select(function () {
return this.parentNode;
}).attr('id');
//---------------------------------------
var dx = d3.event.x;
var dy = d3.event.y;
var mouse = {dx: d3.event.x, dy: d3.event.y};
var currentObj = {
x: currentOp.attr('x'),
y: currentOp.attr('y'),
width: currentOp.attr('width'),
height: currentOp.attr('height')
};
var parentObj = {
x: parent.attr('x'),
y: parent.attr('y'),
width: parent.attr('width'),
height: parent.attr('height')
};
var loc = getXY(mouse, currentObj, parentObj);
//#SB: Do not translate everything, the cx, cy values of the circle are not updated
// when translating which will make future moves calculate incorrectly
g.selectAll('image').attr('transform', 'translate(' + loc.x + ',' + loc.y + ')');
g.selectAll('circle')
.attr('cx', function () {
return parseFloat(d3.select(this).attr('data-cx')) + parseFloat(loc.x);
})
.attr('cy', function () {
return parseFloat(d3.select(this).attr('data-cy')) + parseFloat(loc.y);
});
//#SB: Select all the lines in the parent group instead of only group of the
// operator we are moving. There can be lines that exists on other groups that
// do not exist within the group that is being moved.
d3.select('#' + parent_id).selectAll('.line')[0].forEach(function (el) {
var parent_id = g.attr('id')
var line = d3.select(el)
var nodeType = line.attr('id').split("__"); // id tells us if the line is connected to the left or right node
var operators = line.attr('class').split(" "); // class holds info on what operators the line is connected to
var sourceCircleId = nodeType[0].split("--")[0] + '--' + operators[1];
var targetCircleId = nodeType[1].split("--")[0] + '--' + operators[2];
if (parent_id == operators[1] || parent_id == operators[2]) { // the line is connected to the operator we are moving
line.attr('x1', d3.select('#' + sourceCircleId).attr('cx'))
line.attr('y1', d3.select('#' + sourceCircleId).attr('cy'))
line.attr('x2', d3.select('#' + targetCircleId).attr('cx'))
line.attr('y2', d3.select('#' + targetCircleId).attr('cy'))
}
});
}))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.