簡體   English   中英

如何使反應 highcharts 高度響應通過反應網格布局調整大小?

[英]how to make react highcharts height responsive on resizing via react-grid-layout?

我需要你們的幫助。 我在使用 react-grid-layout 調整 highcharts 的大小時遇到問題。 當我調整寬度開始正常工作時,我得到了解決方案,但我的 highcharts 高度仍然沒有響應。 請檢查下面的代碼。 兩個總體出勤圖表下方均無響應。 我也在使用 react recharts 中的圖表,它們工作正常。 我用回流的東西來固定寬度,但我不知道如何固定高度。謝謝在此處輸入圖像描述 在此處輸入圖像描述 在此處輸入圖像描述

    import React, { useState } from 'react';
import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';
import { withSize } from 'react-sizeme';
import { withSnackbar } from 'notistack';
import html2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
import TopBar from './TopBar';
import Widget from './Widget';
import OverallAttendanceChart from './AttendanceCharts/OverallAttendanceChart';
import HeadlinesChart from './AttendanceCharts/HeadlinesChart';
import LineChartView from './AttendanceCharts/LineChart';
import MonthlyChart from './AttendanceCharts/MonthlyChart';
import DateChart from './AttendanceCharts/DateChart';
import AttendanceByChart from './AttendanceCharts/AttendanceByChart';
import WardsChart from './AttendanceCharts/WardsChart';
import GroupedPieChart from './AttendanceCharts/GroupedPieChart';
import StudentsAttendance from './StudentsAttendance';
import Headlines from './Headlines';
import { Box } from '@material-ui/core';
import { CourseBasedAttendence } from '../Attendance/AttendanceCharts/CourseBasedAttendence';
import ReportsFilter from '../ReportsFilter';
import Highcharts from 'highcharts';

const originalItems = [
  'a',
  'b',
  'c',
  'd',
  'e',
  'f',
  'g',
  'h',
  'i',
  'j',
  'k',
  'l',
  'm',
  'n',
  'o',
  'p',
];

const initialLayouts = {
  lg: [
    { w: 4, h: 8, x: 0, y: 0, i: 'a', moved: false, static: false },
    { w: 12, h: 8, x: 0, y: 0, i: 'b', moved: false, static: false },
    { w: 12, h: 6, x: 6, y: 0, i: 'c', moved: false, static: false },
    { w: 6, h: 6, x: 0, y: 6, i: 'd', moved: false, static: false },
    { w: 12, h: 12, x: 0, y: 0, i: 'e', moved: false, static: false },
    { w: 12, h: 12, x: 0, y: 0, i: 'f', moved: false, static: false },
    { w: 12, h: 6, x: 6, y: 0, i: 'g', moved: false, static: false },
    { w: 6, h: 6, x: 0, y: 0, i: 'h', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'i', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'j', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'k', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'l', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'm', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'n', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'o', moved: false, static: false },
    { w: 4, h: 8, x: 0, y: 0, i: 'p', moved: false, static: false },
  ],
};

const componentList = {
  a: OverallAttendanceChart,
  b: GroupedPieChart,
  c: LineChartView,
  d: MonthlyChart,
  e: HeadlinesChart,
  f: DateChart,
  g: AttendanceByChart,
  h: WardsChart,
  i: CourseBasedAttendence,
  j: OverallAttendanceChart,
  k: OverallAttendanceChart,
  l: OverallAttendanceChart,
  m: OverallAttendanceChart,
  n: OverallAttendanceChart,
  o: OverallAttendanceChart,
  p: OverallAttendanceChart,
};
function Attendance({
  size: { width },
  enqueueSnackbar,
  averageMarkLevel,
  fetchCourseBasedAttendance,
  courseBasedStudentList,
  courseList,
  reportType,
  totalStudents,
  coursesAttendance,
  attendanceOverMonth,
  attendanceOverDate,
  groupAttendanceSummary,
  attendanceOverAge,
}) {
  const [items, setItems] = useState(originalItems);
  const [layouts, setLayouts] = useState(
    getFromLS('layouts') || initialLayouts,
  );

  const onLayoutChange = (_, allLayouts) => {
    setLayouts(allLayouts);
    for (let i = 0; i < Highcharts.charts.length; i += 1) {
      if (Highcharts.charts[i] !== undefined) {
        Highcharts.charts[i].reflow();
      }
    }
  };
  const onLayoutSave = () => {
    saveToLS('layouts', layouts);
  };
  const onRemoveItem = itemId => {
    setItems(items.filter(i => i !== itemId));
  };
  const onAddItem = itemId => {
    setItems([...items, itemId]);
  };
  const printDocument = () => {
    enqueueSnackbar('Downloading pdf...', {
      variant: 'success',
      autoHideDuration: 5000,
    });
    const input = document.getElementById('divToPrint1');
    html2canvas(input).then(canvas => {
      const imgWidth = 210;
      const pageHeight = 295;
      const imgHeight = (canvas.height * imgWidth) / canvas.width;
      let heightLeft = imgHeight;

      const imgData = canvas.toDataURL('image/png');
      const pdf = new jsPDF('portrait', 'mm', 'a4');
      let position = 0;

      pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight);

      heightLeft -= pageHeight;

      while (heightLeft >= 0) {
        position = heightLeft - imgHeight;
        pdf.addPage();
        pdf.addImage(imgData, 'JPEG', 0, position, imgWidth, imgHeight);
        heightLeft -= pageHeight;
      }
      pdf.save('download.pdf');
    });
  };

  return (
    <div id="divToPrint1">
      <Box
        style={{
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'flex-end',
        }}
      >
        <ReportsFilter
          fetchCourseBasedAttendance={fetchCourseBasedAttendance}
          courseList={courseList}
          reportType={reportType}
        />
        <TopBar
          onLayoutSave={onLayoutSave}
          items={items}
          onRemoveItem={onRemoveItem}
          onAddItem={onAddItem}
          originalItems={originalItems}
          pdf={printDocument}
        />
      </Box>

      <StudentsAttendance totalStudents={totalStudents} />
      <Headlines totalStudents={totalStudents} />
      <ResponsiveGridLayout
        className="layout"
        layouts={layouts}
        breakpoints={{ lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 }}
        cols={{ lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 }}
        rowHeight={70}
        width={width}
        onLayoutChange={onLayoutChange}
      >
        {items.map(key => (
          <div
            key={key}
            className="widget"
            data-grid={{ w: 3, h: 2, x: 0, y: Infinity }}
          >
            <Widget
              id={key}
              onRemoveItem={onRemoveItem}
              component={componentList[key]}
              averageMarkLevel={averageMarkLevel}
              courseBasedStudentList={courseBasedStudentList}
              totalStudents={totalStudents}
              coursesAttendance={coursesAttendance}
              attendanceOverMonth={attendanceOverMonth}
              attendanceOverDate={attendanceOverDate}
              attendanceOverAge={attendanceOverAge}
              groupAttendanceSummary={groupAttendanceSummary}
            />
          </div>
        ))}
      </ResponsiveGridLayout>
    </div>
  );
}

export default withSnackbar(
  withSize({ refreshMode: 'debounce', refreshRate: 60 })(Attendance),
);

function getFromLS(key, reportId) {
  let ls = {};
  if (global.localStorage) {
    try {
      ls = JSON.parse(global.localStorage.getItem(`rgl-${reportId}`)) || {};
    } catch (e) {}
  }
  return ls[key];
}

function saveToLS(key, value, reportId) {
  if (global.localStorage) {
    global.localStorage.setItem(
      `rgl-${reportId}`,
      JSON.stringify({
        [key]: value,
      }),
    );
  }
}



import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import Typography from '@material-ui/core/Typography';

const useStyles = makeStyles({
  root: {
    width: '100%',
    height: '100%',
    display: 'flex',
    flexDirection: 'column',
  },
  header: {
    display: 'flex',
    alignItems: 'center',
    padding: '0.5rem',
  },
  spacer: {
    flexGrow: 1,
  },
  body: {
    padding: '0.5rem',
    flexGrow: 1,
  },
  typo: {
    textTransform: 'capitalize',
  },
});

const widgetNames = {
  a: 'Overall Attendance',
  b: 'Micro-cohorts',
  c: 'Attendance by Courses',
  d: 'No. of attendees by Months',
  e: 'Headline Chart',
  f: 'Attendance over Time',
  g: 'Attendance by Matric',
  h: 'Individual Wards',
  i: 'Course Based Attendance',
  j: 'Boys ',
  k: 'Attendance for Pupil Premium (PP)',
  l: 'Attendance for Non- Pupil Premium (PP)',
  m: 'White British ',
  n: 'Non White British ',
  o: 'Attendance for English as Additional Language (EAL) ',
  p: 'Attendance for Non-English as Additional Language (EAL) ',
};
export default function Widget({
  id,
  onRemoveItem,
  component: Item,
  averageMarkLevel,
  courseBasedStudentList,
  totalStudents,
  coursesAttendance,
  attendanceOverMonth,
  attendanceOverDate,
  attendanceOverAge,
  groupAttendanceSummary,
}) {
  const classes = useStyles();
  return (
    <Card className={classes.root}>
      <div className={classes.header}>
        <Typography variant="h6" gutterBottom className={classes.typo}>
          {widgetNames[id]}
        </Typography>
        <div className={classes.spacer} />
        <IconButton aria-label="delete" onClick={() => onRemoveItem(id)}>
          <CloseIcon fontSize="small" />
        </IconButton>
      </div>
      <div className={classes.body}>
        <Item
          averageMarkLevel={averageMarkLevel}
          courseBasedStudentList={courseBasedStudentList}
          totalStudents={totalStudents}
          coursesAttendance={coursesAttendance}
          attendanceOverMonth={attendanceOverMonth}
          attendanceOverDate={attendanceOverDate}
          attendanceOverAge={attendanceOverAge}
          groupAttendanceSummary={groupAttendanceSummary}
        />
      </div>
    </Card>
  );
}



import React from 'react';
import Highcharts from 'highcharts/highcharts';
import highchartsMore from 'highcharts/highcharts-more';
import solidGauge from 'highcharts/modules/solid-gauge';
import HighchartsReact from 'highcharts-react-official';

highchartsMore(Highcharts);
solidGauge(Highcharts);

const chartOptions = {
  chart: {
    type: 'solidgauge',
  },
  credits: {
    enabled: false,
  },
  title: {
    text: '',
  },
  pane: {
    center: ['50%', '70%'],
    size: '100%',
    startAngle: -90,
    endAngle: 90,
    background: {
      backgroundColor:
        Highcharts.defaultOptions.legend.backgroundColor || '#EEE',
      innerRadius: '60%',
      outerRadius: '100%',
      shape: 'arc',
    },
  },

  yAxis: {
    min: 0,
    max: 100,
    stops: [[0, '#ff3118'], [0.5, '#ffd600'], [1, '#00bc06']],

    lineWidth: 0,
    tickWidth: 0,
    minorTickInterval: null,
    tickAmount: 2,
    title: {
      y: -70,
    },
    labels: {
      y: 16,
    },
  },

  exporting: {
    enabled: false,
  },

  tooltip: {
    enabled: false,
  },
  plotOptions: {
    solidgauge: {
      dataLabels: {
        y: 5,
        borderWidth: 0,
        useHTML: true,
      },
    },
  },
};
const chartOptionsLevel = {
  chart: {
    type: 'solidgauge',
  },
  credits: {
    enabled: false,
  },
  title: {
    text: 'Level',
  },
  pane: {
    center: ['50%', '70%'],
    size: '100%',
    startAngle: -90,
    endAngle: 90,
    background: {
      backgroundColor:
        Highcharts.defaultOptions.legend.backgroundColor || '#EEE',
      innerRadius: '60%',
      outerRadius: '100%',
      shape: 'arc',
    },
  },

  yAxis: {
    min: 0,
    max: 100,
    stops: [[0, '#ff3118'], [0.5, '#ffd600'], [1, '#00bc06']],

    lineWidth: 0,
    tickWidth: 0,
    minorTickInterval: null,
    tickAmount: 2,
    title: {
      y: -70,
    },
    labels: {
      y: 16,
    },
  },

  exporting: {
    enabled: false,
  },

  tooltip: {
    enabled: false,
  },
  plotOptions: {
    solidgauge: {
      dataLabels: {
        y: 5,
        borderWidth: 0,
        useHTML: true,
      },
    },
  },
};

const data = 65.14666666666666;

const getChartOptions = (size, anchorEl, range, title) => {
  if (size) {
    chartOptions.chart.width = size.width;
    chartOptions.chart.height = size.height;
  }
  if (typeof data === 'number') {
    chartOptions.series = [
      {
        data: [parseFloat(data.toFixed(2))],
        dataLabels: {
          format:
            '<div style="text-align:center">' +
            '<span style="font-size:22px">{y}</span><br/>' +
            '<span style="font-size:12px;opacity:0.4">%</span>' +
            '</div>',
        },
        tooltip: {
          valueSuffix: '%',
        },
      },
    ];
    if (anchorEl) Highcharts.chart(anchorEl, chartOptions);
  }
  if (typeof range === 'number') {
    chartOptions.yAxis.max = range;
  }
  if (title && title.length > 1) {
    chartOptions.title.text = title;
  }
  if (title === 'Level') {
    chartOptionsLevel.series = [
      {
        data: [parseFloat(data.toFixed(2))],
        dataLabels: {
          format:
            '<div style="text-align:center">' +
            '<span style="font-size:22px">{y}</span><br/>' +
            '<span style="font-size:12px;opacity:0.4">%</span>' +
            '</div>',
        },
        tooltip: {
          valueSuffix: '%',
        },
      },
    ];
    chartOptionsLevel.yAxis.max = range;
    return chartOptionsLevel;
  }

  return JSON.parse(JSON.stringify(chartOptions));
};

function OverallAttendanceChart(props) {
  const { size, anchorEl, range, title } = props;

  return (
    <HighchartsReact
      highcharts={Highcharts}
      options={getChartOptions(data, size, anchorEl, range, title)}
      containerProps={{ style: { height: '100%' } }}
    />
  );
}

export default OverallAttendanceChart;

為了反映HighchartsReact父組件的高度變化,除了調用chart.reflow ,還需要為圖表容器設置height: "100%"樣式。

  <HighchartsReact
    containerProps={{ style: { height: "100%" } }}
    highcharts={Highcharts}
    options={options}
  />

現場演示: https://codesandbox.io/s/highcharts-react-demo-ko0m91?file=/demo.jsx

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM