ডি 3 2 পৃথক জুম আচরণগুলি সিঙ্ক্রোনাইজ করছে


11

আমার নিম্নলিখিত ডি 3 / ডি 3 এফসি চার্ট রয়েছে

https://codepen.io/parliament718/pen/BaNQPXx

চার্টটির প্রধান ক্ষেত্রের জন্য একটি জুম আচরণ এবং y- অক্ষের জন্য একটি পৃথক জুম আচরণ রয়েছে। Y- অক্ষটি পুনরুদ্ধারে টেনে আনা যায়।

আমার যে সমস্যাটি সমাধান করতে সমস্যা হচ্ছে তা হ'ল y-অক্ষগুলি পুনরুদ্ধারের জন্য টেনে নিয়ে যাওয়ার পরে চার্টটি প্যান করার পরে চার্টটিতে একটি "জাম্প" রয়েছে "

স্পষ্টতই 2 জুম আচরণগুলির একটি সংযোগ বিচ্ছিন্ন হয়েছে এবং এটি সিঙ্ক্রোনাইজ করা দরকার তবে আমি এটি ঠিক করার চেষ্টা করছি আমার মস্তিষ্ককে।

const mainZoom = zoom()
    .on('zoom', () => {
       xScale.domain(t.rescaleX(x2).domain());
       yScale.domain(t.rescaleY(y2).domain());
    });

const yAxisZoom = zoom()
    .on('zoom', () => {
        const t = event.transform;
        yScale.domain(t.rescaleY(y2).domain());
        render();
    });

const yAxisDrag = drag()
    .on('drag', (args) => {
        const factor = Math.pow(2, -event.dy * 0.01);
        plotArea.call(yAxisZoom.scaleBy, factor);
    });

পছন্দসই আচরণটি জুমিং, প্যানিং এবং / বা অক্ষরটিকে উদ্ধার করার জন্য পূর্বের ক্রিয়াটি যেখানেই শেষ হয়েছে সেখান থেকে রূপান্তরটি সর্বদা প্রয়োগ করতে হবে, কোনও "জাম্প" ছাড়াই।

উত্তর:


10

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

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

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

সুবিধার জন্য, আমি এই সমস্তগুলি একটি চার্টের উপাদানগুলিতে গুটিয়ে রেখেছি:


const interactiveChart = (xScale, yScale) => {
  const zoom = d3.zoom();
  const xZoom = d3.zoom();
  const yZoom = d3.zoom();

  const chart = fc.chartCartesian(xScale, yScale).decorate(sel => {
    const plotAreaNode = sel.select(".plot-area").node();
    const xAxisNode = sel.select(".x-axis").node();
    const yAxisNode = sel.select(".y-axis").node();

    const applyTransform = () => {
      // apply the zoom transform from the x-scale
      xScale.domain(
        d3
          .zoomTransform(xAxisNode)
          .rescaleX(xScaleOriginal)
          .domain()
      );
      // apply the zoom transform from the y-scale
      yScale.domain(
        d3
          .zoomTransform(yAxisNode)
          .rescaleY(yScaleOriginal)
          .domain()
      );
      sel.node().requestRedraw();
    };

    zoom.on("zoom", () => {
      // compute how much the user has zoomed since the last event
      const factor = (plotAreaNode.__zoom.k - plotAreaNode.__zoomOld.k) / plotAreaNode.__zoomOld.k;
      plotAreaNode.__zoomOld = plotAreaNode.__zoom;

      // apply scale to the x & y axis, maintaining their aspect ratio
      xAxisNode.__zoom.k = xAxisNode.__zoom.k * (1 + factor);
      yAxisNode.__zoom.k = yAxisNode.__zoom.k * (1 + factor);

      // apply transform
      xAxisNode.__zoom.x = d3.zoomTransform(plotAreaNode).x;
      yAxisNode.__zoom.y = d3.zoomTransform(plotAreaNode).y;

      applyTransform();
    });

    xZoom.on("zoom", () => {
      plotAreaNode.__zoom.x = d3.zoomTransform(xAxisNode).x;
      applyTransform();
    });

    yZoom.on("zoom", () => {
      plotAreaNode.__zoom.y = d3.zoomTransform(yAxisNode).y;
      applyTransform();
    });

    sel
      .enter()
      .select(".plot-area")
      .on("measure.range", () => {
        xScaleOriginal.range([0, d3.event.detail.width]);
        yScaleOriginal.range([d3.event.detail.height, 0]);
      })
      .call(zoom);

    plotAreaNode.__zoomOld = plotAreaNode.__zoom;

    // cannot use enter selection as this pulls data through
    sel.selectAll(".y-axis").call(yZoom);
    sel.selectAll(".x-axis").call(xZoom);

    decorate(sel);
  });

  let xScaleOriginal = xScale.copy(),
    yScaleOriginal = yScale.copy();

  let decorate = () => {};

  const instance = selection => chart(selection);

  // property setters not show 

  return instance;
};

এখানে কাজের উদাহরণ সহ একটি কলম দেওয়া হয়েছে:

https://codepen.io/colineberhardt-the-bashful/pen/qBOEEGJ


কলিন, এটিকে আরও একবার দেওয়ার জন্য অনেক ধন্যবাদ। আমি আপনার কোডপেনটি খুললাম এবং লক্ষ্য করেছি এটি প্রত্যাশার মতো কাজ করে না। আমার কোডেপে, Y অক্ষকে টেনে নিয়ে যাওয়া চার্টটিকে আবার স্কেল করে (এটি পছন্দসই আচরণ)। আপনার কোডপেনে অক্ষটি টানলে কেবল চার্টটি প্রশমিত হয়।
সংসদ

1
আমি এমন একটি তৈরি করতে সক্ষম হয়েছি যা আপনাকে ওয়াই-স্কেল এবং প্লট অঞ্চল কোডেপেন.ইও / কোলাইনবারহার্ড- -বাশফুল / স্পেন / এমডিজেয়ারক উভয়ই টেনে আনতে দেয় - তবে প্লট এলাকায় জুম করা বেশ চ্যালেঞ্জ
কলিন

5

আপনার কোডটিতে বেশ কয়েকটি সমস্যা রয়েছে, এটি সমাধান করা সহজ এবং একটি যা না ...

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

আপনি নিম্নলিখিত রূপান্তরটি অনুলিপি করতে পারেন:

selection.call(zoom.transform, d3.event.transform);

যাইহোক, এটি জুম ইভেন্টগুলিও লক্ষ্য আচরণ থেকে বরখাস্ত করবে।

একটি বিকল্প হ'ল 'স্ট্যাশড' ট্রান্সফর্ম সম্পত্তিটিতে সরাসরি অনুলিপি করা:

selection.node().__zoom = d3.event.transform;

তবে আপনি যা অর্জন করতে চাইছেন তাতে আরও একটি বড় সমস্যা রয়েছে। ডি 3-জুম ট্রান্সফর্মটি রূপান্তর ম্যাট্রিক্সের 3 উপাদান হিসাবে সংরক্ষণ করা হয়:

https://github.com/d3/d3-zoom#zoomTransform

ফলস্বরূপ, জুম কেবল অনুবাদের সাথে একত্রে একটি প্রতিসম স্কেলিং উপস্থাপন করতে পারে। এক্স-অক্ষের প্রয়োগ হিসাবে আপনার অসামান্য জুমটি বিশ্বস্ততার সাথে এই রূপান্তর দ্বারা প্রতিনিধিত্ব করা যায় না এবং প্লট-অঞ্চলে পুনরায় প্রয়োগ করা যায়।


ধন্যবাদ কলিন, আমি আমার কাছে এই বোধগম্যতার কোনও ইচ্ছা করি তবে সমাধানটি কী তা আমি বুঝতে পারি না। আমি যত তাড়াতাড়ি পারব এই প্রশ্নের সাথে আমি 500 টি অনুমান যুক্ত করব এবং আশা করি কেউ আমার কোডপেন ঠিক করতে সহায়তা করতে পারে।
সংসদ

কোনও উদ্বেগ নয়, ঠিক করার পক্ষে সহজ সমস্যা নয়, তবে অনুগ্রহ কিছু সাহায্যের প্রতি আকৃষ্ট হতে পারে।
কলিনে

2

এটি একটি আসন্ন বৈশিষ্ট্য , যেমনটি ইতিমধ্যে @ কলিনই উল্লেখ করেছে। আসল কোডটি সর্বদা একটি "অস্থায়ী জুম" করছে যা রূপান্তর ম্যাট্রিক্স থেকে আন-সিঙ্ক হয় d

xExtentপরিসীমাটিকে সারণী করার পক্ষে সর্বোত্তম কাজটি যাতে গ্রাফটি বিশ্বাস করে যে পাশে আরও মোমবাতি রয়েছে। পাশগুলিতে প্যাড যুক্ত করে এটি অর্জন করা যেতে পারে। accessors, হওয়ার পরিবর্তে

[d => d.date]

হয়ে,

[
  () => new Date(taken[0].date.addDays(-xZoom)), // Left pad
  d => d.date,
  () => new Date(taken[taken.length - 1].date.addDays(xZoom)) // Right pad
]

সিডিনোট: নোট করুন যে এখানে একটি padফাংশন রয়েছে যা করা উচিত তবে কিছু কারণে এটি কেবল একবারে কাজ করে এবং আর কখনও আপডেট হয় না কেন সেটিকে এটি হিসাবে যুক্ত করা হয় accessors

সিডিনোট 2: addDaysকেবলমাত্র সরলতার জন্য ফাংশনটি প্রোটোটাইপ হিসাবে করা হয়েছে (করার সেরা জিনিস নয়)।

এখন জুম ইভেন্টটি আমাদের এক্স জুম ফ্যাক্টরটিকে পরিবর্তন করে xZoom,

zoomFactor = Math.sign(d3.event.sourceEvent.wheelDelta) * -5;
if (zoomFactor) xZoom += zoomFactor;

সরাসরি থেকে ডিফারেনশিয়ালটি পড়া গুরুত্বপূর্ণwheelDelta । এটি যেখানে অসমর্থিত বৈশিষ্ট্যটি রয়েছে: t.xআপনি ওয়াই অক্ষটি টেনে নিয়ে গেলেও আমরা এটি পড়তে পারি না কারণ এটি পরিবর্তিত হবে।

অবশেষে, পুনরায় গণনা করুন chart.xDomain(xExtent(data.series));যাতে নতুন পরিমাণ উপলব্ধ is

এখানে জাম্প ছাড়াই ওয়ার্কিং ডেমোটি দেখুন: https://codepen.io/adelriosantiago/pen/QWjwRXa?editors=0011

স্থির: জুম বিপরীতকরণ, ট্র্যাকপ্যাডে উন্নত আচরণ।

প্রযুক্তিগতভাবে আপনি yExtentঅতিরিক্ত d.highএবং এর যোগ করে ত্বক করতে পারেন d.low। অথবা এমনকি উভয়ই xExtentএবং yExtentট্রান্সফর্ম ম্যাট্রিক্সটি একেবারেই এড়াতে।


ধন্যবাদ. দুর্ভাগ্যক্রমে এখানে জুম আচরণ সত্যিই গণ্ডগোল হয়েছে। জুমটি খুব হতাশাবোধ বোধ করে এবং কিছু ক্ষেত্রে এমনকি দিকটি কয়েকবার বিপরীত করে (ম্যাকবুক ট্র্যাকপ্যাড ব্যবহার করে)। জুম আচরণের জন্য মূল কলমের মতো থাকতে হবে।
সংসদ

আমি কয়েকটি উন্নতি, বিশেষত বিপরীত জুমের সাথে কলমটি আপডেট করেছি।
adelriosantiago

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

1
আমি শুধুমাত্র এক্স-অক্ষ বরাবর জুম করতে মূল কলম সামঞ্জস্য করেছি। এটি প্রাপ্য আচরণ এবং আমি এখন বুঝতে পারি এটি উত্তর জটিল করে তুলতে পারে।
সংসদ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.