D3.js विज़ुअलाइज़ेशन लेआउट को उत्तरदायी बनाने का सबसे अच्छा तरीका क्या है?


224

मान लें कि मेरे पास हिस्टोग्राम स्क्रिप्ट है जो एक 960 500 svg ग्राफिक बनाता है। ग्राफिक चौड़ाई और ऊंचाइयों के गतिशील होने पर मैं इसे कैसे उत्तरदायी बना सकता हूं?

<script> 

var n = 10000, // number of trials
    m = 10,    // number of random variables
    data = [];

// Generate an Irwin-Hall distribution.
for (var i = 0; i < n; i++) {
  for (var s = 0, j = 0; j < m; j++) {
    s += Math.random();
  }
  data.push(s);
}

var histogram = d3.layout.histogram()
    (data);

var width = 960,
    height = 500;

var x = d3.scale.ordinal()
    .domain(histogram.map(function(d) { return d.x; }))
    .rangeRoundBands([0, width]);

var y = d3.scale.linear()
    .domain([0, d3.max(histogram.map(function(d) { return d.y; }))])
    .range([0, height]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.selectAll("rect")
    .data(histogram)
  .enter().append("rect")
    .attr("width", x.rangeBand())
    .attr("x", function(d) { return x(d.x); })
    .attr("y", function(d) { return height - y(d.y); })
    .attr("height", function(d) { return y(d.y); });

svg.append("line")
    .attr("x1", 0)
    .attr("x2", width)
    .attr("y1", height)
    .attr("y2", height);

</script> 

पूर्ण उदाहरण हिस्टोग्राम जिस्ट है: https://gist.github.com/993912


5
मुझे इस उत्तर में विधि आसान
लगी

सबसे आसान तरीका है जो मैंने पाया है कि svg की चौड़ाई और ऊँचाई: 100% और DOM कंटेनर (जैसे div) stackoverflow.com/questions/47076163/…
mtx

जवाबों:


316

वहाँ एक और तरीका यह ग्राफ redrawing की आवश्यकता नहीं है कि क्या करना है, और यह बदलाव करना शामिल है viewBox और preserveAspectRatio पर जिम्मेदार बताते <svg>तत्व:

<svg id="chart" width="960" height="500"
  viewBox="0 0 960 500"
  preserveAspectRatio="xMidYMid meet">
</svg>

11/24/15 अपडेट करें : अधिकांश आधुनिक ब्राउज़र एसवीजी तत्वों के पहलू अनुपात का अनुमान लगा सकते हैंviewBox , इसलिए आपको चार्ट के आकार को अद्यतित रखने की आवश्यकता नहीं हो सकती है। यदि आपको पुराने ब्राउज़रों का समर्थन करने की आवश्यकता है, तो विंडो के आकार बदलने पर आप अपने तत्व का आकार बदल सकते हैं:

var aspect = width / height,
    chart = d3.select('#chart');
d3.select(window)
  .on("resize", function() {
    var targetWidth = chart.node().getBoundingClientRect().width;
    chart.attr("width", targetWidth);
    chart.attr("height", targetWidth / aspect);
  });

और svg सामग्री को स्वचालित रूप से बढ़ाया जाएगा। आप यहां (कुछ संशोधनों के साथ) इसका एक कार्यशील उदाहरण देख सकते हैं : यह देखने के लिए कि यह कैसे प्रतिक्रिया करता है, बस विंडो या निचले दाएं फलक का आकार बदलें।


1
मैं वास्तव में इस दृष्टिकोण को पसंद करता हूं, 2 प्रश्न। 1 क्या व्यूबॉक्स क्रॉस ब्राउज़र काम करता है? 2. आपके उदाहरण में मंडलियां आकार में हैं, लेकिन खिड़की में फिट नहीं है। कुछ गलत svg बॉक्स या पहलू अनुपात के साथ जा रहा है।
मैट एल्क

4
इस दृष्टिकोण से प्यार करें, सुनिश्चित करें कि उपरोक्त सही ढंग से काम नहीं करता है। जैसा कि मैट कहते हैं, मंडलियां फिर से आकार लेती हैं लेकिन ग्राफ़ के पहले सर्कल से बाईं ओर की दूरी सर्कल के समान दर पर आकार नहीं लेती है। मैंने jsfiddle में एक निष्पक्ष बिट की कोशिश की, लेकिन Google Chrome का उपयोग करके अपेक्षित रूप से काम करने के लिए इसे प्राप्त नहीं कर सका। कौन से ब्राउज़र व्यूबॉक्स हैं और किससे संरक्षित हैं?
क्रिस विथर्स

9
वास्तव में सिर्फ viewBox और संरक्षित करने के लिए एक एसवीजी के लिए एसवीजी को संरक्षित करें अनुपात जिसमें चौड़ाई 100% है, और अभिभावक मेरे लिए एक बूटस्ट्रैप / फ्लेक्स ग्रिड है जो बिना आकार के घटना को संभालने के लिए मेरे लिए काम करता है
दीपू

2
यह पुष्टि करते हुए कि दीपू सही है। बूटस्ट्रैप / फ्लेक्स ग्रिड के साथ काम करता है। धन्यवाद @ दीपू।
माइक ओ'कॉनर

3
नोट: HTML में कई d3 ट्यूटोरियल 1.) में svg की चौड़ाई और ऊंचाई निर्धारित की गई है और 2.) विज़ुअलाइज़ेशन को onload फ़ंक्शन कॉल के माध्यम से बनाया गया है । यदि वास्तविक HTML में svg चौड़ाई और ऊंचाई निर्धारित की जाती है और आप उपरोक्त तकनीक का उपयोग करते हैं, तो छवि स्केलेबल नहीं होगी।
SumNeuron

34

'उत्तरदायी एसवीजी' देखें एसवीजी को उत्तरदायी बनाने के लिए यह बहुत सरल है और आपको आकारों के बारे में अधिक चिंता करने की आवश्यकता नहीं है।

यहाँ देखें कि मैंने यह कैसे किया:

d3.select("div#chartId")
   .append("div")
   .classed("svg-container", true) //container class to make it responsive
   .append("svg")
   //responsive SVG needs these 2 attributes and no width and height attr
   .attr("preserveAspectRatio", "xMinYMin meet")
   .attr("viewBox", "0 0 600 400")
   //class to make it responsive
   .classed("svg-content-responsive", true); 

CSS कोड:

.svg-container {
    display: inline-block;
    position: relative;
    width: 100%;
    padding-bottom: 100%; /* aspect ratio */
    vertical-align: top;
    overflow: hidden;
}
.svg-content-responsive {
    display: inline-block;
    position: absolute;
    top: 10px;
    left: 0;
}

अधिक जानकारी / ट्यूटोरियल:

http://demosthenes.info/blog/744/Make-SVG-Responsive

http://soqr.fr/testsvg/embed-svg-liquid-layout-responsive-web-design.php


1
मेरे मामले में, पेडिंग-बॉटम: 100% बना देगा मेरे कंटेनर में सबसे नीचे अतिरिक्त पैडिंग है, इसलिए मैंने इसे हटाने के लिए इसे 50% तक बदल दिया। अपने कोड का उपयोग किया और सफलतापूर्वक svg को उत्तरदायी बनाया, धन्यवाद।
V-SHY

20

मैंने इसे हल करने के लिए एक छोटा सा जिस्ट कोड किया है।

सामान्य समाधान पैटर्न यह है:

  1. गणना और ड्राइंग कार्यों में स्क्रिप्ट को ब्रेक लगाना।
  2. ड्राइंग फ़ंक्शन को गतिशील रूप से सुनिश्चित करें और विज़ुअलाइज़ेशन चौड़ाई और ऊंचाई चर से प्रेरित है (ऐसा करने का सबसे अच्छा तरीका d3.scale एपीआई का उपयोग करना है)
  3. मार्कअप में एक संदर्भ तत्व के लिए ड्राइंग को बाँध / चेन। (मैंने इसके लिए jquery का उपयोग किया, इसलिए इसे आयात किया)।
  4. इसे हटाने के लिए याद रखें अगर यह पहले से ही तैयार है। Jquery का उपयोग करके संदर्भित तत्व से आयाम प्राप्त करें।
  5. खिड़की के आकार में फ़ंक्शन को बाँध / चैन करें। इस श्रृंखला के लिए एक बहस (टाइमआउट) का परिचय दें ताकि यह सुनिश्चित हो सके कि हम केवल एक टाइमआउट के बाद फिर से तैयार हों।

मैंने स्पीड के लिए मिनिफाईड d3.js स्क्रिप्ट भी जोड़ी। यहाँ सार है: https://gist.github.com/2414111

jquery संदर्भ वापस कोड:

$(reference).empty()
var width = $(reference).width();

डेब्यू कोड:

var debounce = function(fn, timeout) 
{
  var timeoutID = -1;
  return function() {
     if (timeoutID > -1) {
        window.clearTimeout(timeoutID);
     }
   timeoutID = window.setTimeout(fn, timeout);
  }
};

var debounced_draw = debounce(function() {
    draw_histogram(div_name, pos_data, neg_data);
  }, 125);

 $(window).resize(debounced_draw);

का आनंद लें!


यह काम नहीं करता है; अगर मैं html फाइल की विंडो को सही जाइस्ट में शामिल करता हूं, तो हिस्टोग्राम अभी भी कटा हुआ है क्योंकि खिड़की छोटी हो गई है ...
Chris Withers

1
एसवीजी एक वेक्टर प्रारूप है। आप किसी भी वर्चुअल व्यूबॉक्स का आकार निर्धारित कर सकते हैं और फिर उसे वास्तविक आयामों में स्केल कर सकते हैं। जेएस का उपयोग करने की आवश्यकता नहीं है।
देल पिरोझकोव जूल

4

ViewBox का उपयोग किए बिना

यहाँ एक समाधान का एक उदाहरण है जो एक का उपयोग करने पर भरोसा नहीं करता है viewBox :

तराजू की सीमा को अद्यतन करने में कुंजी है जिसका उपयोग डेटा रखने के लिए किया जाता है।

सबसे पहले, अपने मूल पहलू अनुपात की गणना करें:

var ratio = width / height;

फिर, प्रत्येक आकार बदलने पर, अद्यतन rangeकी xऔर y:

function resize() {
  x.rangeRoundBands([0, window.innerWidth]);
  y.range([0, window.innerWidth / ratio]);
  svg.attr("height", window.innerHeight);
}

ध्यान दें कि ऊंचाई चौड़ाई और पहलू अनुपात पर आधारित है, ताकि आपके मूल अनुपात को बनाए रखा जाए।

अंत में, चार्ट को "रिड्रा" करें - किसी भी विशेषता को अपडेट करें जो xया तो yपैमानों पर निर्भर करती है :

function redraw() {
    rects.attr("width", x.rangeBand())
      .attr("x", function(d) { return x(d.x); })
      .attr("y", function(d) { return y.range()[1] - y(d.y); })
      .attr("height", function(d) { return y(d.y); });
}

ध्यान दें कि में फिर से आकार देने वाला rectsआप के ऊपरी बाध्य उपयोग कर सकते हैं rangeकी y, बल्कि स्पष्ट रूप से ऊंचाई का उपयोग करने से:

.attr("y", function(d) { return y.range()[1] - y(d.y); })


3

यदि आप c3.js के माध्यम से d3.js का उपयोग कर रहे हैं, तो जवाबदेही मुद्दे का समाधान काफी सीधा है:

var chart = c3.generate({bindTo:"#chart",...});
chart.resize($("#chart").width(),$("#chart").height());

उत्पन्न HTML कहां दिखता है:

<div id="chart">
    <svg>...</svg>
</div>

2

शॉन एलन का जवाब बहुत अच्छा था। लेकिन आप हर बार ऐसा नहीं करना चाहेंगे। यदि आप इसे vida.io पर होस्ट करते हैं , तो आपको अपने svg विज़ुअलाइज़ेशन के लिए स्वचालित उत्तरदायी मिल जाएगा।

आप इस सरल एम्बेड कोड के साथ उत्तरदायी iframe प्राप्त कर सकते हैं:

<div id="vida-embed">
<iframe src="http://embed.vida.io/documents/9Pst6wmB83BgRZXgx" width="auto" height="525" seamless frameBorder="0" scrolling="no"></iframe>
</div>

#vida-embed iframe {
  position: absolute;
  top:0;
  left: 0;
  width: 100%;
  height: 100%;
}

http://jsfiddle.net/dnprock/npxp3v9d/1/

प्रकटीकरण: मैं इस सुविधा का निर्माण vida.io पर करता हूं


2

उस स्थिति में जब आप प्लॉटेबल.जेएस जैसे डी 3 रैपर का उपयोग कर रहे हैं , तो ध्यान रखें कि सबसे आसान समाधान एक ईवेंट श्रोता को जोड़ सकता है और फिर एक redraw फ़ंक्शन ( plottable.js में) कॉल कर सकता है। Plottable.js के मामले में यह उत्कृष्ट रूप से काम करेगा (यह दृष्टिकोण खराब दस्तावेज है):redraw

    window.addEventListener("resize", function() {
      table.redraw();
    });

इस फंक्शन को डिबेट करना सबसे अच्छा होगा, जितना संभव हो उतनी तेजी से रेड्रा फायर करने से बचने के लिए
इयान

1

मामले में लोग अभी भी इस सवाल पर जा रहे हैं - यहाँ मेरे लिए क्या काम किया गया है:

  • एक div में iframe संलग्न करें और उस div के 40% (कहते हैं, जो आप चाहते हैं पहलू अनुपात के आधार पर प्रतिशत) को जोड़ने के लिए css का उपयोग करें। फिर iframe की चौड़ाई और ऊंचाई दोनों को 100% पर सेट करें।

  • Html डॉक में चार्ट को iframe में लोड किया जाना है, उस sv की चौड़ाई को चौड़ाई पर सेट करें जिसमें svg को जोड़ा गया है (या शरीर की चौड़ाई के लिए) और चौड़ाई को ऊंचाई * पहलू अनुपात में सेट करें।

  • एक फ़ंक्शन लिखें जो विंडो के आकार पर iframe सामग्री को फिर से लोड करता है, ताकि चार्ट का आकार अनुकूलित करने के लिए जब लोग अपने फोन को घुमाएं।

मेरी वेबसाइट पर यहाँ उदाहरण: http://dirkmjk.nl/en/2016/05/embedding-d3js-charts-responsive-website

अद्यतन 30 दिसंबर 2016

ऊपर वर्णित दृष्टिकोण में कुछ कमियां हैं, विशेष रूप से यह कि यह किसी भी शीर्षक और कैप्शन के लिए ऊंचाई नहीं लेता है जो कि डी 3-निर्मित एसवीजी का हिस्सा नहीं है। जब से मुझे लगता है कि मैं एक बेहतर दृष्टिकोण है भर में आया हूँ:

  • डी 3 चार्ट की चौड़ाई को उस div की चौड़ाई पर सेट करें जो इसके साथ इसकी ऊंचाई सेट करने के लिए पहलू अनुपात से जुड़ा हुआ है और इसका उपयोग करता है;
  • एचटीएमएल 5 के पोस्टमासेज का उपयोग करके मूल पृष्ठ को अपनी ऊंचाई और यूआरएल भेजें;
  • मूल पृष्ठ पर, संबंधित iframe (यदि आपके पृष्ठ पर एक से अधिक iframe है) की पहचान करने के लिए url का उपयोग करें और एम्बेड किए गए पृष्ठ की ऊंचाई तक इसकी ऊंचाई को अपडेट करें।

मेरी वेबसाइट पर यहाँ उदाहरण: http://dirkmjk.nl/en/2016/12/embedding-d3js-charts-responsive-website-better-solution


0

डी 3 डेटा-जॉइन के मूल सिद्धांतों में से एक यह है कि यह एक आदर्श है। दूसरे शब्दों में, यदि आप बार-बार एक ही डेटा के साथ डेटा-जॉइन का मूल्यांकन करते हैं, तो रेंडर किया गया आउटपुट समान है। इसलिए, जब तक आप अपने चार्ट को सही ढंग से प्रस्तुत करते हैं, तब तक अपने प्रवेश, अपडेट और निकास चयन को ध्यान में रखते हुए - जब आप आकार बदलते हैं, तो आपको चार्ट को पूरी तरह से फिर से प्रस्तुत करना होगा।

वहाँ कुछ अन्य चीजें हैं जो आपको करनी चाहिए, एक है डी-बाउंस खिड़की के आकार का हैंडलर इसे थ्रॉटल करने के लिए। इसके अलावा, हार्ड-कोडिंग चौड़ाई / ऊंचाइयों के बजाय, यह युक्त तत्व को मापने के द्वारा प्राप्त किया जाना चाहिए।

एक विकल्प के रूप में, यहां आपका चार्ट d3fc का उपयोग करके प्रदान किया गया है, जो कि डी 3 घटकों का एक सेट है जो डेटा- जॉइन को सही ढंग से संभालता है। इसका एक कार्टेशियन चार्ट भी है जो इसे मापने वाले तत्व को 'उत्तरदायी' चार्ट बनाने में आसान बनाता है:

// create some test data
var data = d3.range(50).map(function(d) {
  return {
    x: d / 4,
    y: Math.sin(d / 4),
    z: Math.cos(d / 4) * 0.7
  };
});

var yExtent = fc.extentLinear()
  .accessors([
    function(d) { return d.y; },
    function(d) { return d.z; }
  ])
  .pad([0.4, 0.4])
  .padUnit('domain');

var xExtent = fc.extentLinear()
  .accessors([function(d) { return d.x; }]);

// create a chart
var chart = fc.chartSvgCartesian(
    d3.scaleLinear(),
    d3.scaleLinear())
  .yDomain(yExtent(data))
  .yLabel('Sine / Cosine')
  .yOrient('left')
  .xDomain(xExtent(data))
  .xLabel('Value')
  .chartLabel('Sine/Cosine Line/Area Chart');

// create a pair of series and some gridlines
var sinLine = fc.seriesSvgLine()
  .crossValue(function(d) { return d.x; })
  .mainValue(function(d) { return d.y; })
  .decorate(function(selection) {
    selection.enter()
      .style('stroke', 'purple');
  });

var cosLine = fc.seriesSvgArea()
  .crossValue(function(d) { return d.x; })
  .mainValue(function(d) { return d.z; })
  .decorate(function(selection) {
    selection.enter()
      .style('fill', 'lightgreen')
      .style('fill-opacity', 0.5);
  });

var gridlines = fc.annotationSvgGridline();

// combine using a multi-series
var multi = fc.seriesSvgMulti()
  .series([gridlines, sinLine, cosLine]);

chart.plotArea(multi);

// render
d3.select('#simple-chart')
  .datum(data)
  .call(chart);

आप इसे इस कोडपेन में एक्शन में देख सकते हैं:

https://codepen.io/ColinEberhardt/pen/dOBvOy

जहाँ आप विंडो का आकार बदल सकते हैं और सत्यापित कर सकते हैं कि चार्ट सही तरीके से फिर से प्रस्तुत किया गया है।

कृपया ध्यान दें, पूर्ण प्रकटीकरण के रूप में, मैं d3fc के अनुरक्षकों में से एक हूं।


अपने उत्तर को अप-टू-डेट रखने के लिए धन्यवाद! मैंने आपकी कुछ पोस्टों के हालिया अपडेट देखे हैं, और मैं वास्तव में लोगों की सराहना करता हूं कि वे अपनी खुद की सामग्री पर ध्यान दें! हालांकि, सावधानी के एक शब्द के रूप में, इस संशोधन को पूरी तरह से सवाल अब, फिट नहीं करता है क्योंकि आप डी 3 में संपादित v4 , जबकि ओपी स्पष्ट रूप से के लिए संदर्भित करता v3 , जो भविष्य पाठकों को भ्रमित हो सकता है। व्यक्तिगत रूप से, अपने स्वयं के उत्तरों के लिए, मैं अभी भी मूल v3 अनुभाग को रखते हुए एक v4 अनुभाग जोड़ना चाहता हूं । मुझे लगता है कि v4 दोनों पोस्ट के लिए एक परस्पर संदर्भ जोड़कर अपने स्वयं के उत्तर के लायक हो सकता है। लेकिन यह सिर्फ मेरे दो सेंट है ...
altocumulus

यह एक बहुत अच्छी बात है! यह बहुत आसान है कि इसे दूर किया जाए और भविष्य पर ध्यान दिया जाए, और नया क्या है। नवीनतम d3 प्रश्नों को देखते हुए मुझे लगता है कि बहुत से लोग अभी भी v3 का उपयोग कर रहे हैं। यह भी निराशाजनक है कि कुछ अंतर कितने सूक्ष्म हैं! मैं अपना संपादन फिर से करूँगा :-)
कॉलिन डे

0

मैं प्लेग की तरह आकार बदलने / टिक समाधानों से बचता हूँ क्योंकि वे अक्षम हैं और आपके ऐप में समस्याएँ पैदा कर सकते हैं (उदाहरण के लिए टूलटिप उस स्थिति की गणना करता है जो उसे विंडो आकार बदलने पर दिखाई देनी चाहिए, फिर एक पल बाद आपका चार्ट भी आकार बदल जाता है और पृष्ठ फिर से आता है- लेआउट और अब आपका टूलटिप फिर से गलत है)।

आप कुछ पुराने ब्राउज़रों में इस व्यवहार का अनुकरण कर सकते हैं जो IE11 की तरह इसका ठीक से समर्थन नहीं करते हैं <canvas> तत्व जो इसे बनाए रखता है।

960x540 दिया गया जो 16: 9 का एक पहलू है:

<div style="position: relative">
  <canvas width="16" height="9" style="width: 100%"></canvas>
  <svg viewBox="0 0 960 540" preserveAspectRatio="xMidYMid meet" style="position: absolute; top: 0; right: 0; bottom: 0; left: 0; -webkit-tap-highlight-color: transparent;">
  </svg>
</div>

0

यहाँ जटिल उत्तर के बहुत सारे।

मूल रूप से आपको केवल इतना करना है कि वह खाई को खोदे widthऔर heightविशेषता के पक्ष में रहे viewBox:

width = 500;
height = 500;

const svg = d3
  .select("#chart")
  .append("svg")
  .attr("viewBox", `0 0 ${width} ${height}`)

यदि आपके पास मार्जिन है, तो आप उन्हें वहां की चौड़ाई / ऊंचाई में जोड़ सकते हैं, gउसके बाद बस उसके बाद उसे जोड़ देंगे और इसे बदल देंगे जैसे आप सामान्य रूप से करेंगे।


-1

आप विज़ुअलाइज़ेशन के आकार को अनुकूलित करने के लिए बूटस्ट्रैप 3 का भी उपयोग कर सकते हैं । उदाहरण के लिए, हम निम्नानुसार HTML कोड सेट कर सकते हैं :

<div class="container>
<div class="row">

<div class='col-sm-6 col-md-4' id="month-view" style="height:345px;">
<div id ="responsivetext">Something to write</div>
</div>

</div>
</div>

मैंने अपनी आवश्यकताओं के कारण एक निश्चित ऊंचाई तय की है, लेकिन आप आकार ऑटो को भी छोड़ सकते हैं। "Col-sm-6 col-md-4" विभिन्न उपकरणों के लिए div को उत्तरदायी बनाता है। आप http://getbootstrap.com/css/#grid-example-basic पर अधिक जान सकते हैं

हम आईडी महीने के दृश्य की मदद से ग्राफ तक पहुंच सकते हैं

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

var width = document.getElementById('month-view').offsetWidth;

var height = document.getElementById('month-view').offsetHeight - document.getElementById('responsivetext2').offsetHeight;

आईडी महीने के दृश्य के साथ div की चौड़ाई प्राप्त करके चौड़ाई निर्धारित की जाती है।

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

यह आपको एक बार करने की अनुमति देता है जो सभी अलग-अलग स्क्रीन / डिव साइज को अपनाएगा। यह करने का सबसे अच्छा तरीका नहीं हो सकता है, लेकिन यह निश्चित रूप से मेरी परियोजना की जरूरतों के लिए काम करता है।


1
नमस्ते, मैंने यह कोशिश की, लेकिन svg सामग्री आकार परिवर्तन नहीं कर रही है, जैसे कैलेंडर या चार्ट।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.