अद्यतन एसवीजी तत्व जेड-इंडेक्स डी 3 के साथ


81

डी 3 लाइब्रेरी का उपयोग करके, एसवीजी तत्व को जेड-ऑर्डर के शीर्ष पर लाने का एक प्रभावी तरीका क्या है?

मेरे विशिष्ट परिदृश्य एक पाई चार्ट जो प्रकाश डाला (एक जोड़कर है strokeकरने के लिए pathजब माउस एक दिया टुकड़ा खत्म हो गया है)। मेरा चार्ट बनाने के लिए कोड ब्लॉक नीचे है:

svg.selectAll("path")
    .data(d)
  .enter().append("path")
    .attr("d", arc)
    .attr("class", "arc")
    .attr("fill", function(d) { return color(d.name); })
    .attr("stroke", "#fff")
    .attr("stroke-width", 0)
    .on("mouseover", function(d) {
        d3.select(this)
            .attr("stroke-width", 2)
            .classed("top", true);
            //.style("z-index", 1);
    })
    .on("mouseout", function(d) {
        d3.select(this)
            .attr("stroke-width", 0)
            .classed("top", false);
            //.style("z-index", -1);
    });

मैंने कुछ विकल्पों की कोशिश की है, लेकिन अब तक कोई भाग्य नहीं। दोनों का उपयोग करना style("z-index")और कॉल करना classedकाम नहीं करता था।

"सीएसएस" वर्ग को मेरे सीएसएस में निम्नानुसार परिभाषित किया गया है:

.top {
    fill: red;
    z-index: 100;
}

fillबयान मैं इसे चालू करने गया था / सही ढंग से बंद जानता था कि वहाँ सुनिश्चित करने के लिए है। यह है।

मैंने सुना है कि उपयोग sortकरना एक विकल्प है, लेकिन मैं इस बात पर स्पष्ट नहीं हूं कि इसे "चयनित" तत्व को शीर्ष पर लाने के लिए कैसे लागू किया जाएगा।

अपडेट करें:

मैंने अपनी विशेष स्थिति को निम्न कोड के साथ तय किया, जो mouseoverकि एक हाइलाइट दिखाने के लिए एसवीजी पर एक नया चाप जोड़ता है ।

svg.selectAll("path")
    .data(d)
  .enter().append("path")
    .attr("d", arc)
    .attr("class", "arc")
    .style("fill", function(d) { return color(d.name); })
    .style("stroke", "#fff")
    .style("stroke-width", 0)
    .on("mouseover", function(d) {
        svg.append("path")
          .attr("d", d3.select(this).attr("d"))
          .attr("id", "arcSelection")
          .style("fill", "none")
          .style("stroke", "#fff")
          .style("stroke-width", 2);
    })
    .on("mouseout", function(d) {
        d3.select("#arcSelection").remove();
    });

जवाबों:


52

डेवलपर द्वारा प्रस्तुत समाधानों में से एक है: "तत्वों को फिर से व्यवस्थित करने के लिए डी 3 के सॉर्ट ऑपरेटर का उपयोग करें।" (देखें https://github.com/mbostock/d3/issues/252 )

इस प्रकाश में, कोई अपने डेटा, या स्थिति की तुलना करके तत्वों को क्रमबद्ध कर सकता है यदि वे घातक तत्व थे:

.on("mouseover", function(d) {
    svg.selectAll("path").sort(function (a, b) { // select the parent and sort the path's
      if (a.id != d.id) return -1;               // a is not the hovered element, send "a" to the back
      else return 1;                             // a is the hovered element, bring "a" to the front
  });
})

यह न केवल Z ऑर्डर पर काम करता है, यह किसी भी ड्रैगिंग को भी परेशान नहीं करता है जो अभी-अभी शुरू किया गया है।
ओलिवर बॉक

3
यह मेरे लिए भी काम नहीं करता है। a, b केवल डेटा प्रतीत होता है, d3 चयन तत्व या DOM तत्व नहीं है
nkint

वास्तव में, @nkint के लिए की तरह यह काम नहीं किया जब तुलना a.idऔर d.id। समाधान सीधे तुलना aऔर है d
शांति

यह बड़ी संख्या में बाल तत्वों के लिए पर्याप्त रूप से प्रदर्शन नहीं करेगा। बाद में उठाए गए तत्व को फिर से प्रस्तुत करना बेहतर है <g>
आदिवासी

1
वैकल्पिक रूप से, svg:useतत्व उठाए गए तत्व को गतिशील रूप से इंगित कर सकता है। समाधान के लिए stackoverflow.com/a/6289809/292085 देखें ।
आदिवासी

91

जैसा कि अन्य उत्तरों में बताया गया है, एसवीजी में जेड-इंडेक्स की धारणा नहीं है। इसके बजाय, दस्तावेज़ में तत्वों का क्रम ड्राइंग में क्रम निर्धारित करता है।

तत्वों को मैन्युअल रूप से पुन: व्यवस्थित करने के अलावा, कुछ स्थितियों के लिए एक और तरीका है:

डी 3 के साथ काम करते हुए आपके पास अक्सर कुछ प्रकार के तत्व होते हैं जिन्हें हमेशा अन्य प्रकार के तत्वों के शीर्ष पर खींचा जाना चाहिए

उदाहरण के लिए, रेखांकन करते समय, लिंक हमेशा नोड्स के नीचे रखे जाने चाहिए। अधिक आम तौर पर, कुछ पृष्ठभूमि तत्वों को आमतौर पर हर चीज के नीचे रखने की आवश्यकता होती है, जबकि कुछ हाइलाइट्स और ओवरले को ऊपर रखा जाना चाहिए।

यदि आपके पास इस तरह की स्थिति है, तो मैंने पाया कि तत्वों के उन समूहों के लिए मूल समूह तत्व बनाना सबसे अच्छा तरीका है। एसवीजी में, आप उसके लिए gतत्व का उपयोग कर सकते हैं । उदाहरण के लिए, यदि आपके पास ऐसे लिंक हैं जिन्हें हमेशा नोड्स के नीचे रखा जाना चाहिए, तो निम्न कार्य करें:

svg.append("g").attr("id", "links")
svg.append("g").attr("id", "nodes")

अब, जब आप अपने लिंक और नोड्स को पेंट करते हैं, तो निम्नानुसार चुनें (चयनकर्ता #तत्व आईडी के साथ शुरू होने वाले चयनकर्ता ):

svg.select("#links").selectAll(".link")
// add data, attach elements and so on

svg.select("#nodes").selectAll(".node")
// add data, attach elements and so on

अब, सभी लिंक हमेशा सभी नोड तत्वों से पहले संरचनात्मक रूप से जोड़ दिए जाएंगे। इस प्रकार, एसवीजी सभी नोड्स के नीचे सभी लिंक दिखाएगा, चाहे आप कितनी बार और किस क्रम में तत्वों को जोड़ या हटा दें। बेशक, एक ही प्रकार के सभी तत्व (यानी एक ही कंटेनर के भीतर) अभी भी उस क्रम के अधीन होंगे जिसमें उन्हें जोड़ा गया था।


1
मैं अपने दिमाग में इस विचार के साथ भाग गया कि मैं एक आइटम को स्थानांतरित कर सकता हूं, जब मेरी वास्तविक समस्या समूहों में मेरे तत्वों का संगठन थी। यदि आपकी "वास्तविक" समस्या व्यक्तिगत तत्वों की ओर बढ़ रही है, तो पिछले उत्तर में वर्णित क्रमबद्ध विधि जाने का एक अच्छा तरीका है।
जॉन डेविड पाँच

बहुत बढ़िया! धन्यवाद, notan3xit, आपने मेरा दिन बचाया! बस दूसरों के लिए एक विचार जोड़ने के लिए - यदि आपको वांछित दृश्यता क्रम से भिन्न क्रम में तत्वों को जोड़ने की आवश्यकता है, तो आप उचित दृश्यता क्रम में समूह बना सकते हैं (यहां तक ​​कि उन्हें किसी भी तत्व को जोड़ने से पहले), और फिर इन पर तत्वों को जोड़ दें किसी भी क्रम में समूह।
ओल्गा ग्नतेंको

1
यह सही तरीका है। स्पष्ट रूप से एक बार जब आप इसके बारे में सोचते हैं।
डेव

मेरे लिए, svg.select ('# लिंक') ... को काम करने के लिए d3.select ('# लिंक') ... से बदलना पड़ा। शायद यह दूसरों की मदद करेगा।
विनिमय

26

चूंकि एसवीजी में जेड-इंडेक्स नहीं है, लेकिन डोम तत्वों के क्रम का उपयोग करते हैं, आप इसे सामने ला सकते हैं:

this.parentNode.appendChild(this);

फिर आप इसे वापस डालने के लिए इन्सर्टबियर का उपयोग कर सकते हैं mouseout। हालाँकि, इसके लिए आवश्यक है कि आप अपने तत्व को सिबलिंग-नोड को लक्षित करने में सक्षम हों।

डेमो: इस JSFiddle पर एक नज़र डालें


यह एक महान समाधान होगा यदि यह फ़ायरफ़ॉक्स के लिए किसी भी :hoverशैली को प्रस्तुत करने में विफल नहीं था । मुझे यह भी नहीं लगता कि इस उपयोग के मामले में अंत में sertnsert फ़ंक्शन की आवश्यकता होगी।
जॉन सेलर्स

@swenedo, आपका समाधान मेरे लिए बहुत अच्छा काम करता है और तत्व को सामने लाता है। इसे वापस लाने के बारे में, मैं थोड़ा स्टैक्ड हूं और यह नहीं जानता कि इसे सही तरीके से कैसे लिखा जाए। क्या आप कृपया एक उदाहरण पोस्ट कर सकते हैं कि आप वस्तु को कैसे वापस ला सकते हैं। धन्यवाद।
माइक बी।

1
@ मायकेबी। ज़रूर, मैंने अभी-अभी अपना उत्तर अपडेट किया है। मुझे एहसास हुआ कि डी 3 का insertकार्य शायद जाने का सबसे अच्छा तरीका नहीं है, क्योंकि यह एक नया तत्व बनाता है । हम केवल एक मौजूदा तत्व को स्थानांतरित करना चाहते हैं, इसलिए मैं insertBeforeइसके बजाय इस उदाहरण में उपयोग करता हूं ।
स्वेन्दो

मैंने इस पद्धति का उपयोग करने की कोशिश की, लेकिन दुर्भाग्य से मैं IE11 में काम नहीं करता। क्या आपके पास इस ब्राउज़र के लिए कोई काम है?
एंटोनियो जियोवानी शियावोन

13

एसवीजी जेड-इंडेक्स नहीं करता है। जेड-ऑर्डर को उनके कंटेनर में एसवीजी डोम तत्वों के आदेश द्वारा निर्धारित किया जाता है।

जहां तक ​​मैं बता सकता हूं (और मैंने पिछले कुछ समय में यह कोशिश की है), डी 3 किसी भी तत्व को सामने या व्हाट्सएप पर लाने के लिए किसी भी तत्व को अलग करने और फिर से तैयार करने के तरीके प्रदान नहीं करता है।

एक .order()विधि है , जो चयन में दिखाई देने वाले क्रम से मिलान करने के लिए नोड्स को फेरबदल करती है। आपके मामले में, आपको किसी एक तत्व को सामने लाना होगा। इसलिए, तकनीकी रूप से, आप सामने के वांछित तत्व के साथ चयन का सहारा ले सकते हैं (या अंत में, याद नहीं कर सकते जो सबसे ऊपर है), और फिर उस order()पर कॉल करें ।

या, आप इस कार्य के लिए d3 को छोड़ सकते हैं और उस एकल DOM तत्व को फिर से सम्मिलित करने के लिए सादे JS (या jQuery) का उपयोग कर सकते हैं।


5
ध्यान दें कि कुछ ब्राउज़रों में माउसओवर हैंडलर के अंदर तत्वों को हटाने / सम्मिलित करने के मुद्दे हैं, इससे माउसआउट ईवेंट ठीक से नहीं भेजे जा सकते हैं, इसलिए मैं यह सुनिश्चित करने के लिए सभी ब्राउज़रों में यह कोशिश करने की सलाह दूंगा कि यह आपकी अपेक्षा के अनुरूप काम करता है।
एरिक डहलस्ट्रम

क्या ऑर्डर बदलने से मेरे पाई चार्ट का लेआउट भी नहीं बदलेगा? मैं jQuery के आसपास भी खुदाई कर रहा हूं ताकि तत्वों को फिर से सम्मिलित करना सीख सकें।
ईविल कोठरी बंदर

मैंने अपने प्रश्न को अपने हल के साथ अपडेट किया है, जो मैंने मूल प्रश्न के मूल का उपयोग नहीं किया है। अगर आपको इस समाधान के बारे में कुछ भी बुरा लगता है तो मैं टिप्पणियों का स्वागत करता हूं! मूल प्रश्न पर जानकारी के लिए धन्यवाद।
ईविल कोठरी बंदर

एक उचित दृष्टिकोण की तरह लगता है, मुख्य रूप से इस तथ्य के लिए धन्यवाद कि ओवरलैड आकार में एक भरण नहीं है। यदि ऐसा होता है, तो मुझे उम्मीद है कि यह माउस घटना को "चोरी" करने के लिए दिखाई देगा। और, मुझे लगता है कि @ EricDahlström की बात अभी भी खड़ी है: यह अभी भी कुछ ब्राउज़रों (IE9 मुख्य रूप से) में एक मुद्दा हो सकता है। अतिरिक्त "सुरक्षा" के लिए आप .style('pointer-events', 'none')ओवरलैड पथ में जोड़ सकते हैं । दुर्भाग्य से, यह संपत्ति आईई में कुछ भी नहीं करती है, लेकिन फिर भी ....
मीटमैट

@EvilClosetMonkey हाय ... इस सवाल को बहुत सारे विचार मिलते हैं, और मेरा मानना ​​है कि नीचे दिए गए भविष्य के उत्तर मेरी तुलना में अधिक उपयोगी हैं। तो, शायद फ्यूचर्स के स्वीकृत उत्तर को बदलने पर विचार करें, इसलिए यह उच्चतर प्रतीत होता है।
मीटमैट

10

सरल उत्तर डी 3 ऑर्डर करने के तरीकों का उपयोग करना है। D3.select ( 'जी') के अलावा। आदेश (), वहाँ है .lower () और .raise () संस्करण 4. यह परिवर्तन कैसे अपने तत्वों को दिखाई में। अधिक जानकारी के लिए डॉक्स से परामर्श लें - https://github.com/d3/d3/blob/master/API.md#selections-d3-selection


1
यह सबसे अच्छा जवाब है!
अहमद करीम

4

मैंने अपने कोड में भविष्य के समाधान को लागू किया और इसने काम किया, लेकिन बड़ी संख्या में जिन तत्वों का मैं उपयोग कर रहा था, यह बहुत धीमा था। यहाँ jQuery का उपयोग करके वैकल्पिक विधि है जो मेरे विशेष विज़ुअलाइज़ेशन के लिए तेजी से काम करती है। यह उन svgs पर निर्भर करता है जो आप सामान्य रूप से एक वर्ग के ऊपर चाहते हैं (मेरे उदाहरण में वर्ग को dkey के रूप में मेरे डेटा सेट में नोट किया गया है)। मेरे कोड <g>में वर्ग "स्थानों" के साथ है जिसमें उन सभी एसवीजी शामिल हैं जिन्हें मैं फिर से व्यवस्थित कर रहा हूं।

.on("mouseover", function(d) {
    var pts = $("." + d.key).detach();
    $(".locations").append(pts);
 });

इसलिए जब आप किसी विशेष डेटा बिंदु पर होवर करते हैं, तो कोड उस विशेष वर्ग के साथ एसवीजी डोम तत्वों के साथ अन्य सभी डेटा बिंदुओं को पाता है। फिर यह उन डेटा बिंदुओं से जुड़े एसवीजी डोम तत्वों को अलग करता है और फिर से सम्मिलित करता है।


4

एक पूरी नई उत्तर लिखने के बजाय @ notan3xit ने जो जवाब दिया, उसका विस्तार करना चाहता था (लेकिन मेरे पास पर्याप्त प्रतिष्ठा नहीं है)।

एलिमेंट ऑर्डर की समस्या को हल करने का एक और तरीका यह है कि ड्राइंग करते समय 'अपेंड' की बजाय 'इंसर्ट' का इस्तेमाल करें। इस तरह से रास्तों को हमेशा अन्य svg तत्वों से पहले रखा जाएगा (यह आपके कोड को पहले ही दर्ज करता है) (अन्य svg तत्वों के लिए) प्रवेश से पहले लिंक के लिए ()।

d3 इन्सर्ट एपी: https://github.com/mbostock/d3/wiki/Selections#insert


1

मौजूदा एसवीजी में जेड-ऑर्डर को कैसे ट्विक किया जाए, यह जानने में मुझे उम्र लग गई। मुझे वास्तव में टूलटिप व्यवहार के साथ d3.brush के संदर्भ में इसकी आवश्यकता थी। दो विशेषताओं को अच्छी तरह से एक साथ काम करने के लिए ( http://wrobstory.github.io/2013/11/D3-brush-and-tooltip.html ), आपको d3.brush की Z- क्रम में पहली आवश्यकता है (1 कैनवस पर खींचा जाना है, फिर एसवीजी तत्वों के बाकी हिस्सों द्वारा कवर किया गया है) और यह सभी माउस घटनाओं को कैप्चर करेगा, चाहे वह इसके शीर्ष पर हो (उच्च जेड सूचकांकों के साथ)।

अधिकांश फोरम टिप्पणियां कहती हैं कि आपको अपने कोड में पहले d3.brush जोड़ना चाहिए, फिर आपका SVG "ड्राइंग" कोड। लेकिन मेरे लिए यह संभव नहीं था क्योंकि मैंने एक बाहरी एसवीजी फ़ाइल लोड की थी। आप किसी भी समय आसानी से ब्रश जोड़ सकते हैं और बाद में जेड-ऑर्डर को बदल सकते हैं:

d3.select("svg").insert("g", ":first-child");

D3.brush सेटअप के संदर्भ में यह ऐसा दिखेगा:

brush = d3.svg.brush()
    .x(d3.scale.identity().domain([1, width-1]))
    .y(d3.scale.identity().domain([1, height-1]))
    .clamp([true,true])
    .on("brush", function() {
      var extent = d3.event.target.extent();
      ...
    });
d3.select("svg").insert("g", ":first-child");
  .attr("class", "brush")
  .call(brush);

d3.js इंसर्ट () फंक्शन API: https://github.com/mbostock/d3/wiki/Selectro#ster

उम्मीद है की यह मदद करेगा!


0

संस्करण 1

सिद्धांत रूप में, निम्नलिखित को ठीक काम करना चाहिए।

CSS कोड:

path:hover {
    stroke: #fff;
    stroke-width : 2;
}

यह सीएसएस कोड चयनित पथ पर एक स्ट्रोक जोड़ देगा।

जेएस कोड:

svg.selectAll("path").on("mouseover", function(d) {
    this.parentNode.appendChild(this);
});

यह JS कोड पहले DOM ट्री से रास्ता निकालता है और फिर इसे अपने माता-पिता के अंतिम बच्चे के रूप में जोड़ता है। यह सुनिश्चित करता है कि एक ही माता-पिता के अन्य सभी बच्चों के ऊपर से रास्ता निकाला जाए।

व्यवहार में, यह कोड Chrome में ठीक काम करता है लेकिन कुछ अन्य ब्राउज़रों में टूट जाता है। मैंने इसे अपने लिनक्स मिंट मशीन पर फ़ायरफ़ॉक्स 20 में आज़माया और इसे काम करने के लिए नहीं मिला। किसी तरह, फ़ायरफ़ॉक्स :hoverशैलियों को ट्रिगर करने में विफल रहता है और मुझे इसे ठीक करने का कोई तरीका नहीं मिला है।


संस्करण 2

तो मैं एक विकल्प के साथ आया था। यह थोड़ा 'गंदा' हो सकता है, लेकिन कम से कम यह काम करता है और इसे सभी तत्वों (कुछ अन्य उत्तरों के रूप में) पर लूपिंग की आवश्यकता नहीं होती है।

CSS कोड:

path.hover {
    stroke: #fff;
    stroke-width : 2;
}

:hoverPseudoselector का उपयोग करने के बजाय , मैं एक .hoverवर्ग का उपयोग करता हूं

जेएस कोड:

svg.selectAll(".path")
   .on("mouseover", function(d) {
       d3.select(this).classed('hover', true);
       this.parentNode.appendChild(this);
   })
   .on("mouseout", function(d) {
       d3.select(this).classed('hover', false);
   })

माउसओवर पर, मैं .hoverकक्षा को अपने पथ पर जोड़ता हूं। माउसआउट करने पर, मैं इसे हटा देता हूं। पहले मामले की तरह, कोड भी DOM ट्री से रास्ता निकालता है और फिर इसे अपने माता-पिता के अंतिम बच्चे के रूप में जोड़ता है।


0

आप इसे माउस पर ऐसा कर सकते हैं आप इसे शीर्ष पर खींच सकते हैं।

d3.selection.prototype.bringElementAsTopLayer = function() {
       return this.each(function(){
       this.parentNode.appendChild(this);
   });
};

d3.selection.prototype.pushElementAsBackLayer = function() { 
return this.each(function() { 
    var firstChild = this.parentNode.firstChild; 
    if (firstChild) { 
        this.parentNode.insertBefore(this, firstChild); 
    } 
}); 

};

nodes.on("mouseover",function(){
  d3.select(this).bringElementAsTopLayer();
});

यदि आप वापस पुश करना चाहते हैं

nodes.on("mouseout",function(){
   d3.select(this).pushElementAsBackLayer();
});
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.