Skip to content

Commit

Permalink
add template example for map chart
Browse files Browse the repository at this point in the history
  • Loading branch information
= committed Feb 21, 2024
1 parent 13ecbe8 commit 06833ad
Show file tree
Hide file tree
Showing 8 changed files with 3,368 additions and 81 deletions.
125 changes: 118 additions & 7 deletions apps/www/app/[locale]/(user)/chart/Content.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
'use client';

import React from 'react';
import dynamic from 'next/dynamic';
import { EChartsOption } from 'echarts-for-react';
import { ShareDialog, useScreenshot } from 'opub-ui';
import { BarChart } from 'opub-ui/viz';
import { useMediaQuery } from 'usehooks-ts';

import { navigateEnd } from '@/lib/navigation';

const MapChart = dynamic(
() => import('opub-ui/viz').then((mod) => mod.MapChart),
{
ssr: false,
}
);

type Props = {
svg: string;
options: EChartsOption;
Expand All @@ -16,32 +24,54 @@ export function Content({
bar,
line,
stacked,
mapOptions,
}: {
bar: Props;
line: Props;
stacked: Props;
mapOptions: any;
}) {
const mapDataFn = (value: number) => {
return value >= 330
? '#a50f15'
: value >= 325
? '#de2d26'
: value >= 320
? '#fb6a4a'
: value >= 315
? '#fc9272'
: value >= 310
? '#fcbba1'
: '#fee5d9';
};

return (
<div className="mb-8 min-h-fit w-full">
<Chart
options={bar.options}
svg={bar.svg}
props={{
title: 'This title for bar chart is genrated in the template',
title: 'This title for bar chart is generated in the template',
}}
/>
<Chart
options={line.options}
svg={line.svg}
props={{
title: 'This title for line chart is genrated in the template',
title: 'This title for line chart is generated in the template',
}}
/>
<Chart
options={stacked.options}
svg={stacked.svg}
props={{
title: 'This title for stacked chart is genrated in the template',
title: 'This title for stack chart is generated in the template',
}}
/>
<ChartMap
options={{ ...mapOptions, mapDataFn: mapDataFn }}
props={{
title: 'This title for map chart is generated in the template',
}}
/>
</div>
Expand All @@ -64,7 +94,8 @@ const Chart = ({
const isDesktop = useMediaQuery('(min-width: 768px)');

const { createSvg, svgToPngURL, downloadFile } = useScreenshot();
const handleClick = async () => {

const generateImage = async () => {
const svg = await createSvg(
<Template data={dataUrlBar} title={props.title} />,
{
Expand All @@ -91,7 +122,72 @@ const Chart = ({
props={{
height: isDesktop ? 285 : 175,
}}
onOpen={handleClick}
onOpen={generateImage}
onDownload={() => downloadFile(svgURL, 'Chart', () => navigateEnd())}
>
Share
</ShareDialog>
</div>
);
};

const ChartMap = ({
options,
props,
}: {
options: any;
props: {
title: string;
};
}) => {
const [svgURL, setSvgURL] = React.useState<string>('');
const [isLoading, setIsLoading] = React.useState<boolean>(false);
const ref = React.useRef<HTMLDivElement>(null);
const [map, setMap] = React.useState<any>(null);

const isDesktop = useMediaQuery('(min-width: 768px)');
const { createSvg, svgToPngURL, downloadFile, domToUrl } = useScreenshot();

async function generateImage() {
setIsLoading(true);

const targetElm = ref.current?.querySelector('.leaflet-map-pane');
const dataImgURL = await domToUrl(targetElm as HTMLElement, {
width: map.getSize().x,
height: map.getSize().y,
backgroundColor: 'white',
});

const svg = await createSvg(
<Template data={dataImgURL} title={props.title} />,
{
width: map.getSize().x,
}
);
const dataURL = await svgToPngURL(svg);

setSvgURL(dataURL);
setIsLoading(false);
}

return (
<div className="mt-8 flex flex-col items-center">
{/* This is React version of Leaflet */}
<div className="mt-10 h-[600px] w-full p-10" ref={ref}>
<MapChart {...options} setMap={setMap} />
</div>

<ShareDialog
kind="secondary"
size="medium"
image={svgURL}
loading={isLoading}
alt="SVG"
title="Share"
props={{
height: isDesktop ? 285 : 175,
}}
onOpen={generateImage}
onDownload={() => downloadFile(svgURL, 'Chart', () => navigateEnd())}
>
Share
Expand All @@ -100,7 +196,18 @@ const Chart = ({
);
};

const Template = ({ data, title }: { data: string | null; title: string }) => {
const Template = ({
data,
title,
props,
}: {
data: string | null;
title: string;
props?: {
height: number;
width: number;
};
}) => {
return (
<div
style={{
Expand All @@ -121,7 +228,11 @@ const Template = ({ data, title }: { data: string | null; title: string }) => {
>
{title}
</p>
{data ? <img src={data} className="w-full" alt="SVG" /> : 'Loading...'}
{data ? (
<img src={data} {...props} className="w-full" alt="SVG" />
) : (
'Loading...'
)}
</div>
);
};
13 changes: 12 additions & 1 deletion apps/www/app/[locale]/(user)/chart/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import json from '@/public/json/assam.json';

import { eCharts } from '@/lib/eCharts';
import { barOptions, lineOptions, stackedOptions } from './chart';
import { Content } from './Content';
Expand All @@ -8,12 +10,21 @@ export default async function Home() {
const line = eCharts({ options: lineOptions });
const stacked = eCharts({ options: stackedOptions });

const mapOptions = {
mapProperty: 'dt_code',
mapZoom: 7.9,
fillOpacity: 1,
mapCenter: [26.193, 92.3],
features: json.features,
};

return (
<main className="flex w-full flex-col items-center justify-center gap-2">
<main className="flex w-full flex-col items-center justify-center gap-2">
<Content
bar={{ svg: bar, options: barOptions }}
line={{ svg: line, options: lineOptions }}
stacked={{ svg: stacked, options: stackedOptions }}
mapOptions={mapOptions}
/>
</main>
);
Expand Down
Loading

0 comments on commit 06833ad

Please sign in to comment.