From 838fa295094c4397d8abf8c10cc0741cc05db50d Mon Sep 17 00:00:00 2001 From: OkunElya Date: Fri, 10 Apr 2026 11:59:01 +1000 Subject: [PATCH] hw 5 done --- site/package-lock.json | 459 ++++++++++++++++++++++++++++++ site/package.json | 1 + site/src/App.jsx | 7 +- site/src/CSS/App.css | 20 ++ site/src/components/Chart.jsx | 74 +++++ site/src/components/ChartDraw.jsx | 157 ++++++++++ site/src/components/Sorting.jsx | 2 +- site/src/components/Table.jsx | 7 +- 8 files changed, 721 insertions(+), 6 deletions(-) create mode 100644 site/src/components/Chart.jsx create mode 100644 site/src/components/ChartDraw.jsx diff --git a/site/package-lock.json b/site/package-lock.json index 7022161..16950f8 100644 --- a/site/package-lock.json +++ b/site/package-lock.json @@ -8,6 +8,7 @@ "name": "lab4", "version": "0.0.0", "dependencies": { + "d3": "^7.9.0", "react": "^19.2.4", "react-dom": "^19.2.4" }, @@ -1174,6 +1175,15 @@ "dev": true, "license": "MIT" }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1210,6 +1220,407 @@ "dev": true, "license": "MIT" }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -1235,6 +1646,15 @@ "dev": true, "license": "MIT" }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -1627,6 +2047,18 @@ "hermes-estree": "0.25.1" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -1664,6 +2096,15 @@ "node": ">=0.8.19" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2327,6 +2768,12 @@ "node": ">=4" } }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, "node_modules/rolldown": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.12.tgz", @@ -2368,6 +2815,18 @@ "dev": true, "license": "MIT" }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", diff --git a/site/package.json b/site/package.json index 9c96c60..c011708 100644 --- a/site/package.json +++ b/site/package.json @@ -10,6 +10,7 @@ "preview": "vite preview" }, "dependencies": { + "d3": "^7.9.0", "react": "^19.2.4", "react-dom": "^19.2.4" }, diff --git a/site/src/App.jsx b/site/src/App.jsx index db11dec..eef9533 100644 --- a/site/src/App.jsx +++ b/site/src/App.jsx @@ -2,11 +2,14 @@ import { useState } from 'react' import Table from './components/Table.jsx'; import ram_sticks from './data.js'; import './CSS/App.css' +import Chart from './components/Chart.jsx' function App() { + const [filteredData, setFilteredData] = useState(ram_sticks); return (
-

Самые высокие здания и сооружения

- +

Цены на оперативную память

+ +
) } diff --git a/site/src/CSS/App.css b/site/src/CSS/App.css index f716aeb..035c808 100644 --- a/site/src/CSS/App.css +++ b/site/src/CSS/App.css @@ -32,3 +32,23 @@ span:hover,.selected { background-color: blue; color:white; } + +svg { + width: 800px; + height: 400px; +} + +svg path, line { + fill: none; + stroke: black; + width: 1px; +} + +svg text { + font: 8px Verdana; +} + +.bad-selection{ + color: red; + border: solid thin red; +} \ No newline at end of file diff --git a/site/src/components/Chart.jsx b/site/src/components/Chart.jsx new file mode 100644 index 0000000..0e109d9 --- /dev/null +++ b/site/src/components/Chart.jsx @@ -0,0 +1,74 @@ +import { useState } from "react"; +import ChartDraw from './ChartDraw.jsx'; +import * as d3 from "d3"; + + +const Chart = (props) => { + const [ox, setOx] = useState("size"); + const [oy, setOy] = useState([true, false]); + const [graphType, setGraphType] = useState(0); + + const handleSubmit = (event) => { + event.preventDefault(); + setOx(event.target["ox"].value); + setOy([event.target["oy"][0].checked, event.target["oy"][1].checked]); + setGraphType(event.target["graphType"].value); + } + + const createArrGraph = (data, key) => { + const groupObj = d3.group(data, d => d[key]); + let arrGraph = []; + for (let entry of groupObj) { + let minMax = d3.extent(entry[1].map(d => d['price'])); + arrGraph.push({ labelX: entry[0], values: minMax }); + } + console.log(arrGraph) + return arrGraph; + } + + return ( + <> +

Визуализация

+ +

OX value:

+
+ + Size GB +
+ + Release date +
+ + Manufacturer + +
+
+ +

OY value

+ {(!oy[0] && !oy[1]) && Select at least one } +
+ + Min price +
+ + Max price + +
+

Тип диаграммы

+
+ +
+ +

+ +

+ + + + ) +} + +export default Chart; \ No newline at end of file diff --git a/site/src/components/ChartDraw.jsx b/site/src/components/ChartDraw.jsx new file mode 100644 index 0000000..8b24df8 --- /dev/null +++ b/site/src/components/ChartDraw.jsx @@ -0,0 +1,157 @@ +import * as d3 from "d3"; +import { useEffect, useRef, useState } from "react"; + + +function drawGraph(data, keyX, drawMin, drawMax, graphtype) { + // значения по оси ОХ + + // создаем массив для построения графика + // console.log(keyX) + if(keyX=="release" || keyX=="size"){ + data = d3.sort(data, (x,y)=>Number(x["labelX"])-Number(y["labelX"])); + } + const svg = d3.select("svg") + svg.selectAll('*').remove(); + + // создаем словарь с атрибутами области вывода графика + const attr_area = { + width: parseFloat(svg.style('width')), + height: parseFloat(svg.style('height')), + marginX: 50, + marginY: 50 + } + + // создаем шкалы преобразования и выводим оси + const [scX, scY] = createAxis(svg, data, attr_area,[drawMin,drawMax]); + + // рисуем график + + const scaleYDomain = d3.extent(data.map(d => d.values[1])); + if (drawMin && drawMax){ + createChart(svg, data, scX, scY, attr_area, "blue", 0,graphtype,0,scaleYDomain) + createChart(svg, data, scX, scY, attr_area, "red", 1,graphtype,0,scaleYDomain) + } + else if (drawMin) { + createChart(svg, data, scX, scY, attr_area, "blue", 0,graphtype,1,scaleYDomain) + } + else if (drawMax) { + createChart(svg, data, scX, scY, attr_area, "red", 1,graphtype,1,scaleYDomain) + } +} + +function createAxis(svg, data, attr_area, selections) { + // находим интервал значений, которые нужно отложить по оси OY + // максимальное и минимальное значение и максимальных высот по каждой стране + const max = d3.max(data,d => d.values[Number(selections[1])]); + const min = d3.min(data,d => d.values[Number(1-selections[0])]); + // console.log(max,min,data) + // функция интерполяции значений на оси + // по оси ОХ текстовые значения + const scaleX = d3.scaleBand() + .domain(data.map(d => d.labelX)) + .range([0, attr_area.width - 2 * attr_area.marginX]); + + const scaleY = d3.scaleLinear() + .domain([min * 0.85, max * 1.1]) + .range([attr_area.height - 2 * attr_area.marginY, 0]); + + // создание осей + const axisX = d3.axisBottom(scaleX); // горизонтальная + const axisY = d3.axisLeft(scaleY); // вертикальная + + // отрисовка осей в SVG-элементе + svg.append("g") + .attr("transform", `translate(${attr_area.marginX}, + ${attr_area.height - attr_area.marginY})`) + .call(axisX) + .selectAll("text") // подписи на оси - наклонные + .style("text-anchor", "end") + .attr("dx", "-.8em") + .attr("dy", ".15em") + .attr("transform", d => "rotate(-45)"); + + svg.append("g") + .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) + .call(axisY); + + return [scaleX, scaleY] +} + +function createChart(svg, data, scaleX, scaleY, attr_area, color, valueIdx,isHistogram,horisontalScale,scaleYDomain) { + if (isHistogram){ + svg.selectAll(".dot") + .data(data) + .enter() + .append("rect") + .attr("x", d => scaleX(d.labelX)+valueIdx*6) + .attr("y", d => scaleY(d.values[valueIdx])) + .attr("width",6*(horisontalScale+1)) + .attr("height",d => scaleY(scaleYDomain[0]*0.85)-scaleY(d.values[valueIdx])) + .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) + .style("fill", color) + + + } + else{ + const r = 4; + + svg.selectAll(".dot") + .data(data) + .enter() + .append("circle") + .attr("r", r) + .attr("cx", d => scaleX(d.labelX) + scaleX.bandwidth() / 2+valueIdx*4) + .attr("cy", d => scaleY(d.values[valueIdx])) + .attr("transform", `translate(${attr_area.marginX}, ${attr_area.marginY})`) + .style("fill", color) +} +} + + +const ChartDraw = (props) => { + const chartRef = useRef(null); + + const [width, setWidth] = useState(0); + const [height, setHeight] = useState(0); + + // заносим в состояния ширину и высоту svg-элемента + useEffect(() => { + const svg = d3.select(chartRef.current); + setWidth(parseFloat(svg.style('width'))); + setHeight(parseFloat(svg.style('height'))); + }); + // задаем отступы в svg-элементе + const margin = { + top:10, + bottom:60, + left:40, + right:10 + }; + + // вычисляем ширину и высоту области для вывода графиков + const boundsWidth = width - margin.left - margin.right; + const boundsHeight = height - margin.top - margin.bottom; + + useEffect(() => { + if(boundsWidth<0||boundsHeight<0){ + return; + } + const svg = d3.select(chartRef.current); + // выводим прямоугольник, + svg + .append("rect") + .attr("x", margin.left) + .attr("y", margin.top) + .attr("width", boundsWidth) + .attr("height", boundsHeight) + .style("fill", "lightgrey"); + // console.log(props) + drawGraph(props.data,props.ox,props.minMax[0],props.minMax[1],Number(props.graphType)) + }); + + return ( + + ) +} + +export default ChartDraw; \ No newline at end of file diff --git a/site/src/components/Sorting.jsx b/site/src/components/Sorting.jsx index 96c904f..ca85160 100644 --- a/site/src/components/Sorting.jsx +++ b/site/src/components/Sorting.jsx @@ -99,7 +99,7 @@ const Sorting = (props) => { // console.log(tempArr) } - props.setApplySort({f:clearSort}); + props.setClearSort({f:clearSort}); return ( diff --git a/site/src/components/Table.jsx b/site/src/components/Table.jsx index ab2c8ca..56bf979 100644 --- a/site/src/components/Table.jsx +++ b/site/src/components/Table.jsx @@ -14,12 +14,13 @@ const Table = (props) => { const [activePage, setActivePage] = useState("1"); const [dataTable, setDataTable] = useState(props.data); - const [applySort, setApplySort] = useState({f:(x)=>{x}}); + const [clearSort, setClearSort] = useState({f:(x)=>{x}}); const updateDataTable = (value) => { - applySort.f(); + clearSort.f(); + props.setFilteredDataCallback(value) setDataTable(value); } const changeActive = (event) => { @@ -44,7 +45,7 @@ const Table = (props) => {

Sort by

- +