Chart.jsx:
Код: Выделить всё
import {
ColorType,
createChart,
CrosshairMode,
LineSeries,
} from "lightweight-charts";
import { useEffect, useRef } from "react";
export default function Chart({ renders }) {
const chartContainerRef = useRef();
useEffect(() => {
const chart = createChart(chartContainerRef.current, {
layout: {
background: { type: ColorType.Solid, color: "#000000" },
textColor: "#ffffff",
},
width: 600,
height: 300,
grid: {
vertLines: {
visible: false,
},
horzLines: {
visible: false,
},
},
crosshair: {
mode: CrosshairMode.Magnet,
},
timeScale: {
backgroundColor: "#3b3b3b",
timeVisible: true,
rightBarStaysOnScroll: true,
},
});
chart.timeScale().fitContent();
const series = chart.addSeries(LineSeries);
const data = [];
for (let i = 0; i < 1000000; ++i) {
data.push({
time: 1766877868 + i,
value: Math.floor(Math.random() * 2000),
});
}
series.setData(data);
const observer = new ResizeObserver((entries) => {
const { width, height } = entries[0].contentRect;
chart.applyOptions({ width, height });
chart.timeScale().fitContent();
});
observer.observe(chartContainerRef.current);
return () => {
chart.remove();
observer.disconnect();
};
}, [renders]);
return ;
}
Код: Выделить всё
import "./App.css";
import Chart from "./Chart.jsx";
import { useState } from "react";
import DirectTask from "./DirectTask.jsx";
export default function App() {
const [renders, setRenders] = useState(0);
return (
);
}
Код: Выделить всё
import { useEffect, useState } from "react";
import axios from "axios";
export default function DirectTask({ setRenders }) {
const [progress, setProgress] = useState("");
useEffect(() => {
(async () => {
const socket = new WebSocket(`ws://localhost:8000/ws/example/1234`);
socket.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case "progress":
setProgress(((message.current / message.total) * 100).toFixed(2));
}
};
return () => {
socket.close();
};
})();
}, []);
return (
{
setRenders((prev) => prev + 1);
await axios.get("http://localhost:8000/trigger/direct/");
}}
>
Direct {progress}
);
}
Код: Выделить всё
import json
from asgiref.sync import async_to_sync
def exec_task(channel_layer, task_id):
total = 10000
for i in range(total):
async_to_sync(channel_layer.group_send)(
f'task_{task_id}',
{
'type': 'update_count',
'data': json.dumps(
{'type': 'progress', 'current': i + 1, 'total': total}
),
},
)
Код: Выделить всё
from channels.generic.websocket import AsyncWebsocketConsumer
class ExampleConsumer(AsyncWebsocketConsumer):
def get_group_name(self):
task_id = self.scope['path'].strip('/').split('/')[-1]
return f'task_{task_id}'
async def connect(self):
await self.channel_layer.group_add(self.get_group_name(), self.channel_name)
await self.accept()
async def disconnect(self, close_code):
await self.channel_layer.group_discard(self.get_group_name(), self.channel_name)
async def update_count(self, event):
await self.send(event['data'])
Код: Выделить всё
from django.urls import re_path
from core.consumers import ExampleConsumer
websocket_urlpatterns = [
re_path(r'ws/example/(?P\w+)', ExampleConsumer.as_asgi()),
]

Точки данных 3M (отстает и начинает отсчет внезапно с 28%):

Что я пробовал до сих пор и не работает:
- Асинхронный запуск приводит к множеству проблем: одна из них — невозможность вернуть функцию очистки, поскольку вместо этого возвращается обещание, что приводит к дублированию диаграмм, а вторая — иногда портит диаграмму при повторной визуализации, возможно, из-за той же самой причина.
- Использование веб-воркера, который в данном случае бесполезен, поскольку манипуляции с dom являются узким местом и не поддерживаются этими воркёрами.
Подробнее здесь: https://stackoverflow.com/questions/798 ... ain-thread
Мобильная версия