উইন্ডোটি d3.js আকারে পরিবর্তন করা হলে এসভিজি-র আকার দিন


183

আমি d3.js দিয়ে একটি স্ক্র্যাপপ্লট আঁকছি। এই প্রশ্নের সাহায্যে:
স্ক্রিন, বর্তমান ওয়েব পৃষ্ঠা এবং ব্রাউজার উইন্ডোর আকার পান

আমি এই উত্তরটি ব্যবহার করছি:

var w = window,
    d = document,
    e = d.documentElement,
    g = d.getElementsByTagName('body')[0],
    x = w.innerWidth || e.clientWidth || g.clientWidth,
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;

সুতরাং আমি আমার প্লটটি ব্যবহারকারীর উইন্ডোতে এভাবে ফিট করতে সক্ষম:

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

এখন আমি চাই যে ব্যবহারকারী যখন উইন্ডোটি পুনরায় আকার দেবে তখন প্লটের আকার পরিবর্তন করার বিষয়ে কিছু যত্ন নেয়।

PS: আমি আমার কোডে jQuery ব্যবহার করছি না।


উত্তর:


294

'প্রতিক্রিয়াশীল এসভিজি' সন্ধান করুন কোনও এসভিজিকে প্রতিক্রিয়াশীল করা বেশ সহজ এবং আপনার আর মাপের বিষয়ে চিন্তা করতে হবে না।

আমি এটি কীভাবে করেছি তা এখানে:

d3.select("div#chartId")
   .append("div")
   // Container class to make it responsive.
   .classed("svg-container", true) 
   .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)
   // Fill with a rectangle for visualization.
   .append("rect")
   .classed("rect", true)
   .attr("width", 600)
   .attr("height", 400);
.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;
}

svg .rect {
  fill: gold;
  stroke: steelblue;
  stroke-width: 5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<div id="chartId"></div>

দ্রষ্টব্য: এসভিজি চিত্রের সমস্ত কিছুই উইন্ডো প্রস্থের সাথে মাপবে। এর মধ্যে স্ট্রোক প্রস্থ এবং হরফ আকার (এমনকি সিএসএস সহ সেগুলি) অন্তর্ভুক্ত রয়েছে। যদি এটি পছন্দসই না হয় তবে নীচে আরও জড়িত বিকল্প সমাধান রয়েছে।

আরও তথ্য / টিউটোরিয়াল:

http://thenewcode.com/744/Make-SVG-Responsive

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


8
এটি আরও মার্জিত এবং এটি একটি ধারক স্কেলিং পদ্ধতির ব্যবহার করে যা প্রতিটি ফ্রন্ট-এন্ড বিকাশকারীর টুলকিটে থাকা উচিত (কোনও নির্দিষ্ট দিক অনুপাতের মধ্যে কোনও কিছু স্কেলিংয়ের জন্য ব্যবহার করা যেতে পারে)। শীর্ষ উত্তর হওয়া উচিত।
কনটুর

13
কেবল viewBoxএটিতে যুক্ত করুন: বৈশিষ্ট্যটি আপনার এসভিজি প্লটের প্রাসঙ্গিক উচ্চতা এবং প্রস্থে সেট করা উচিত: .attr("viewBox","0 0 " + width + " " + height) যেখানে widthএবং heightঅন্য কোথাও সংজ্ঞায়িত হয়েছে। এটি হ'ল আপনি যদি না চান তবে আপনার এসভিজি ভিউ বক্সের মাধ্যমে ক্লিপড। padding-bottomআপনার এসভিজি উপাদানটির অনুপাতের সাথে মেলে আপনি নিজের সিএসএসে প্যারামিটারটি আপডেট করতেও পারেন । যদিও দুর্দান্ত প্রতিক্রিয়া - খুব সহায়ক, এবং একটি ট্রিট কাজ করে। ধন্যবাদ!
অ্যান্ড্রু গাই

13
একই ধারণার ভিত্তিতে, এমন কোনও উত্তর দেওয়া আকর্ষণীয় হবে যা দিক অনুপাত সংরক্ষণে জড়িত না doesn't প্রশ্নটি একটি এসজিজি উপাদান সম্পর্কে ছিল যা পুরো উইন্ডোটিকে পুনরায় আকারে coveringেকে রাখে, যার বেশিরভাগ ক্ষেত্রে একটি ভিন্ন দিক অনুপাত থাকে।
নিকোলাস লে থিয়েরি ডি'নেখুইন

37
ইউএক্স সম্পর্কিত কেবল একটি নোট: কিছু ব্যবহারের ক্ষেত্রে, আপনার এসভিজি-ভিত্তিক ডি 3 চার্টকে একটি নির্দিষ্ট দিক অনুপাত সহ সম্পদের মতো চিকিত্সা করা আদর্শ নয়। যে লেখচিত্রগুলি পাঠ্য প্রদর্শন করে বা গতিশীল হয় বা সাধারণভাবে সম্পদের চেয়ে যথাযথ ইউজার ইন্টারফেসের মতো মনে হয়, আপডেট হওয়া মাত্রাগুলি সহ পুনরায় রেন্ডারিং করে আরও লাভ করতে পারে। উদাহরণস্বরূপ, ভিউবক্সটি অক্ষের ফন্ট এবং টিক্সকে উপরের / নীচে স্কেল করতে বাধ্য করে, এইচটিএমএল পাঠ্যের তুলনায় সম্ভাব্য বিশ্রী দেখাচ্ছে looking বিপরীতে, একটি রি-রেন্ডার চার্টটিকে একটি সামঞ্জস্যপূর্ণ আকারের লেবেল রাখতে সক্ষম করে, এবং এটি টিক্স যুক্ত বা সরিয়ে দেওয়ার সুযোগ সরবরাহ করে।
করিম হার্নান্দেজ

1
কেন top: 10px;? আমার কাছে ভুল বলে মনে হচ্ছে এবং অফসেট সরবরাহ করে। 0px লাগানো সূক্ষ্মভাবে কাজ করে।
টিমজামান

43

উইন্ডো.ন্রেসাইজ ব্যবহার করুন :

function updateWindow(){
    x = w.innerWidth || e.clientWidth || g.clientWidth;
    y = w.innerHeight|| e.clientHeight|| g.clientHeight;

    svg.attr("width", x).attr("height", y);
}
d3.select(window).on('resize.updatesvg', updateWindow);

http://jsfiddle.net/Zb85u/1/


11
এটি কোনও উত্তম উত্তর নয় কারণ এটি
ডিওএম ইভেন্টগুলির প্রতিদ্বন্দ্বী

@ আলেম0ালাররা মজাদারভাবে যথেষ্ট, সিএসএস / ডি 3 সংস্করণটি আমার পক্ষে কার্যকর হয়নি এবং এটি একটি করেছে ...
খ্রিস্টান

32

আপডেট আপডেট মাত্র @cminatti থেকে নতুন উপায়টি ব্যবহার করুন


historicতিহাসিক উদ্দেশ্যে পুরানো উত্তর

আইএমও নির্বাচন () এবং অন () ব্যবহার করা ভাল, যেহেতু আপনি একাধিক পুনরায় আকারের ইভেন্ট হ্যান্ডলার রাখতে পারেন ... কেবল খুব পাগল হয়ে যাবেন না

d3.select(window).on('resize', resize); 

function resize() {
    // update width
    width = parseInt(d3.select('#chart').style('width'), 10);
    width = width - margin.left - margin.right;

    // resize the chart
    x.range([0, width]);
    d3.select(chart.node().parentNode)
        .style('height', (y.rangeExtent()[1] + margin.top + margin.bottom) + 'px')
        .style('width', (width + margin.left + margin.right) + 'px');

    chart.selectAll('rect.background')
        .attr('width', width);

    chart.selectAll('rect.percent')
        .attr('width', function(d) { return x(d.percent); });

    // update median ticks
    var median = d3.median(chart.selectAll('.bar').data(), 
        function(d) { return d.percent; });

    chart.selectAll('line.median')
        .attr('x1', x(median))
        .attr('x2', x(median));


    // update axes
    chart.select('.x.axis.top').call(xAxis.orient('top'));
    chart.select('.x.axis.bottom').call(xAxis.orient('bottom'));

}

http://eyeseast.github.io/visible-data/2013/08/28/responsive-charts-with-d3/


আমি কম রাজি হতে পারি না। সিমানাটিটির পদ্ধতিটি আমরা ব্যবহার করি এমন সমস্ত ডি 3 জ ফাইলগুলিতে কাজ করবে। চার্ট প্রতি একটি আকার পরিবর্তন করে রূপান্তর করার এই পদ্ধতিটি ওভারকিল। এছাড়াও, এটি প্রতিটি সম্ভাব্য চার্টের জন্য নতুন করে লেখা দরকার যা আমরা ভাবতে পারি। উপরে উল্লিখিত পদ্ধতিটি সমস্ত কিছুর জন্য কাজ করে। আপনি উল্লিখিত পুনঃলোডের ধরণ সহ আমি 4 টি রেসিপি চেষ্টা করেছি এবং সেগুলির কোনওটি কিউবিজমে ব্যবহৃত একাধিক অঞ্চল প্লটের জন্য কাজ করে না।
ইমন কেনি

1
@ এমোনঙ্কেনি আমি আপনার সাথে আরও একমত হতে পারি না। ভবিষ্যতে 7 মাসের অন্য উত্তরটি উত্তম :)
slp

এই পদ্ধতির জন্য: "d3.select (উইন্ডো)।" "আমি" d3.select (উইন্ডো)। অফ "বা" d3.select (উইন্ডো) .উনবাইন্ড "খুঁজে পাইনি
সমুদ্র-কেজি

1
@ সমুদ্র কেজি stackoverflow.com/questions/20269384/...
SLF

এই উত্তরটি কোনওভাবেই নিকৃষ্ট নয়। তাদের উত্তর গ্রাফের প্রতিটি দিক (টিক্স, অক্ষ, লাইন এবং পাঠ্য টীকাগুলি সহ) স্কেল করবে যা কিছু স্ক্রিন আকারে, অন্যের মধ্যে খারাপ এবং চরম আকারে অপঠনযোগ্য দেখতে পারা যায়। আমি এটি ব্যবহার করে (বা আরও আধুনিক সমাধানের জন্য, @ অঙ্গু আগরওয়াল) পদ্ধতিটি ব্যবহার করে পুনরায় আকার দেওয়া আরও ভাল বলে মনে করি।
রোনার বার্গ

12

যদি আকার পরিবর্তনকারী কোডটি গ্রাফটি প্রথম স্থানে তৈরি করার কোডের মতো প্রায় দীর্ঘ হয় তবে এটি এক ধরনের কুৎসিত। সুতরাং বিদ্যমান চার্টের প্রতিটি উপাদানকে পুনরায় আকার দেওয়ার পরিবর্তে কেন কেবল এটিকে পুনরায় লোড করা হচ্ছে না? এটি আমার পক্ষে কীভাবে কাজ করেছে তা এখানে:

function data_display(data){
   e = document.getElementById('data-div');
   var w = e.clientWidth;
   // remove old svg if any -- otherwise resizing adds a second one
   d3.select('svg').remove();
   // create canvas
   var svg = d3.select('#data-div').append('svg')
                                   .attr('height', 100)
                                   .attr('width', w);
   // now add lots of beautiful elements to your graph
   // ...
}

data_display(my_data); // call on page load

window.addEventListener('resize', function(event){
    data_display(my_data); // just call it again...
}

গুরুত্বপূর্ণ লাইন হয় d3.select('svg').remove();। অন্যথায় প্রতিটি আকার পরিবর্তন পূর্বেরটির নীচে আরেকটি এসভিজি উপাদান যুক্ত করবে।


আপনি যদি প্রতিটি উইন্ডো পুনরায়
আকারের

2
তবে এটি সঠিক: আপনি রেন্ডার হিসাবে আপনি নির্ধারণ করতে পারেন যে আপনার কীট অক্ষ থাকা উচিত, একটি কিংবদন্তি লুকানো উচিত, উপলভ্য সামগ্রীর উপর ভিত্তি করে অন্যান্য জিনিসগুলি করা উচিত। খাঁটি সিএসএস / ভিউবক্স সলিউশন ব্যবহার করে, এটি যা যা করে তা ভিজ্যুয়ালিয়েশনকে স্কোয়াড দেখাচ্ছে। চিত্রের জন্য ভাল, ডেটা জন্য খারাপ।
ক্রিস নোল

8

জোর লেআউটে কেবল 'উচ্চতা' এবং 'প্রস্থ' বৈশিষ্ট্যগুলি সেট করে প্লটটি পুনরায় কেন্দ্র করতে / এসভিজি ধারকটিতে স্থানান্তরিত করতে কাজ করবে না। তবে এখানে একটি খুব সহজ উত্তর রয়েছে যা এখানে পাওয়া ফোর্স লেআউটগুলির জন্য কাজ করে । সংক্ষেপে:

আপনার পছন্দ মত ইভেন্টগুলি একই (যে কোনও) ব্যবহার করুন।

window.on('resize', resize);

তারপরে ধরে নিবেন আপনার কাছে এসভিজি এবং ফোর্স ভেরিয়েবল রয়েছে:

var svg = /* D3 Code */;
var force = /* D3 Code */;    

function resize(e){
    // get width/height with container selector (body also works)
    // or use other method of calculating desired values
    var width = $('#myselector').width(); 
    var height = $('#myselector').height(); 

    // set attrs and 'resume' force 
    svg.attr('width', width);
    svg.attr('height', height);
    force.size([width, height]).resume();
}

এইভাবে, আপনি গ্রাফটি পুরোপুরি পুনরায় রেন্ডার করবেন না, আমরা বৈশিষ্ট্যগুলি সেট করি এবং ডি 3 প্রয়োজনীয় হিসাবে জিনিসগুলি পুনরায় গণনা করে। আপনি যখন মাধ্যাকর্ষণ বিন্দু ব্যবহার করেন এটি অন্তত কাজ করে। আমি নিশ্চিত না যে এটি এই সমাধানের পূর্বশর্ত কিনা। যে কেউ নিশ্চিত বা অস্বীকার করতে পারেন ?

চিয়ার্স, ছ


এটি আমার ফোর্স লেআউটে পুরোপুরি কাজ করেছে যার প্রায় 100 টি সংযোগ রয়েছে। ধন্যবাদ।
উপজাতি 84

1

D3 v4 / v5- তে বল নির্দেশিত গ্রাফগুলি ব্যবহার করার জন্য, sizeপদ্ধতিটির আর কোনও অস্তিত্ব নেই। নীচের মতো কিছু আমার জন্য কাজ করেছে ( এই গিথুব ইস্যুর উপর ভিত্তি করে ):

simulation
    .force("center", d3.forceCenter(width / 2, height / 2))
    .force("x", d3.forceX(width / 2))
    .force("y", d3.forceY(height / 2))
    .alpha(0.1).restart();

1

আপনি যদি ইভেন্টটিকে পুনরায় আকার দেওয়ার জন্য কাস্টম লজিককে আবদ্ধ করতে চান তবে আজকাল আপনি এসভিজিলেমেন্টের বাউন্ডিং বাক্সের জন্য রেসাইজঅবার্সার ব্রাউজার এপিআই ব্যবহার শুরু করতে পারেন ।
কাছের উপাদানগুলির আকারের পরিবর্তনের কারণে ধারকটি পুনরায় আকার দেওয়ার সময় এটি কেসটি পরিচালনা করবে। বিস্তৃত ব্রাউজার সমর্থনের জন্য
একটি পলিফিল রয়েছে

এটি ইউআই উপাদান হিসাবে এটি কাজ করতে পারে:

function redrawGraph(container, { width, height }) {
  d3
    .select(container)
    .select('svg')
    .attr('height', height)
    .attr('width', width)
    .select('rect')
    .attr('height', height)
    .attr('width', width);
}

// Setup observer in constructor
const resizeObserver = new ResizeObserver((entries, observer) => {
  for (const entry of entries) {
    // on resize logic specific to this component
    redrawGraph(entry.target, entry.contentRect);
  }
})

// Observe the container
const container = document.querySelector('.graph-container');
resizeObserver.observe(container)
.graph-container {
  height: 75vh;
  width: 75vw;
}

.graph-container svg rect {
  fill: gold;
  stroke: steelblue;
  stroke-width: 3px;
}
<script src="https://unpkg.com/resize-observer-polyfill@1.5.1/dist/ResizeObserver.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<figure class="graph-container">
  <svg width="100" height="100">
    <rect x="0" y="0" width="100" height="100" />
  </svg>
</figure>

// unobserve in component destroy method
this.resizeObserver.disconnect()
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.