diff --git a/client/src/actions/propertysale/sales_by_regions.js b/client/src/actions/propertysale/sales_by_regions.js new file mode 100644 index 0000000000000000000000000000000000000000..b717ebc732c6c2e5f2f4ada5c7fd8bbc43242f47 --- /dev/null +++ b/client/src/actions/propertysale/sales_by_regions.js @@ -0,0 +1,30 @@ +import { fetch } from '../../utils/dataAccess'; + +export function loading(loading) { + return { type: 'PROPERTY_SALE_SALES_BY_REGION_LOADING', loading }; +} + +export function success(retrieved) { + return { type: 'PROPERTY_SALE_SALES_BY_REGION_SUCCESS', retrieved }; +} + +export function error(error) { + return { type: 'PROPERTY_SALE_SALES_BY_REGION_ERROR', error }; +} + +export function fetch_data(year) { + return dispatch => { + dispatch(loading(true)); + + return fetch("property_sales/sales_by_region/?year="+encodeURIComponent(year), { method: "GET" }) + .then(res => { + dispatch(loading(false)); + return res.json(); + }) + .then(retrieved => dispatch(success(retrieved))) + .catch(e => { + dispatch(loading(false)); + dispatch(error(e.message)); + }); + }; +} diff --git a/client/src/components/charts/BarChart.js b/client/src/components/charts/BarChart.js index 9d35d63d634c12fb818a85738a57f8dff1d6e0b2..a6bf422c61c8901b25d7ddc7a1a2e3250a6d81a8 100644 --- a/client/src/components/charts/BarChart.js +++ b/client/src/components/charts/BarChart.js @@ -13,7 +13,8 @@ class BarChart extends Component { drawChart() { - const data = [12, 5, 6, 6, 9, 10, 20, 10,20,34,11,21]; + const data = [12, 5, 6, 6, 9, 10, 20, 10,20,34,11,21,51]; + const Tick = [12, 5, 6, 6, 9, 10, 20, 10,20,34,11,21,51]; // const data = this.props.data; const margin = {top:100, right: 40, bottom: 100, left: 100}; const x = 400; @@ -37,6 +38,7 @@ class BarChart extends Component { .tickSizeInner(5) .tickSizeOuter(5) .tickPadding(10) + var y_axis = d3.axisLeft() .scale(yScale) @@ -49,7 +51,6 @@ class BarChart extends Component { .attr("height", height) .style("margin-top", margin.top) .style("margin-left", margin.left) - .style("border", "1px solid black"); // - - - - - - - - - - - // Draw header @@ -122,7 +123,7 @@ class BarChart extends Component { .attr("y", (d, i) => height - 10 * d) .attr("width", 27) .attr("height", (d, i) => d * 10) - .attr("fill", '#b5a') + .attr("fill", "rgb(8, 48, 107)") .attr("transform", `translate(${margin.left}, ${-margin.top})`) svg.selectAll("text") diff --git a/client/src/components/charts/Donut.js b/client/src/components/charts/Donut.js index e21a455c386d73b899a49c7486defbbd43ebc018..a47db7ddec30f6ed86df27e55ae8a5139149eef0 100644 --- a/client/src/components/charts/Donut.js +++ b/client/src/components/charts/Donut.js @@ -1,49 +1,48 @@ import React, { Component } from 'react'; +import PropTypes from "prop-types"; import * as d3 from 'd3'; -import './Donut.css'; +import './css/Donut.css'; class Donut extends Component { - - componentDidMount() { - this.drawChart(); - } - - componentDidUpdate() { - this.drawChart(); - } - - - drawChart() { - var regions = ["Normandie", "Normandie-2", "Region centre loire", "Bretage", "PACA", "elit", "sed", "do", "eiusmod", "tempor", "incididunt"]; - var percentage = [0, 1, 2, 3, 4, 5, 6, 8, 8, 9, 10]; - var datas = [51, 12, 32, 48, 51, 63, 48, 39, 60, 48, 10]; - var data2 = [10, 84, 28, 12, 1, 58, 64, 1, 30, 10, 80]; - - var regionsjson = [ - { nom: "reg1", percentage: "10" }, - { nom: "reg2", percentage: "20" }, - { nom: "reg3", percentage: "10" }, - { nom: "reg4", percentage: "20" }, - ] - - var width = 960, - height = 430; + static propTypes = { + data: PropTypes.array.isRequired + }; + + render(svg) { + const HIDE_LIMIT = 2; + d3.select("svg").remove(); + let regions = []; + let percentage = []; + let datas = []; + this.props.data.forEach(element => { + regions.push(element.region); + datas.push(element.value); + }); + + let total = datas.reduce((a,b)=>{return a+b},0); + percentage = datas.map(x => parseInt((x/total)*100)); + console.log("dat tasse"); + console.log(datas); + + console.log("percentage"); + console.log(percentage); + var width = window.screen.width - window.screen.width/2, + height = window.screen.height - window.screen.height/2; var svg = d3.select("div#app") - .append("svg") - .attr("width", width + 100) - .attr("height", height + 100) - .append("g") - - svg.append("g") - .attr("class", "slices"); - svg.append("g") - .attr("class", "percent"); - svg.append("g") - .attr("class", "labels"); - svg.append("g") - .attr("class", "lines"); - + .append("svg") + .attr("width", 3*width) + .attr("height", 3*height) + .append("g") + + svg.append("g") + .attr("class", "slices"); + svg.append("g") + .attr("class", "percent"); + svg.append("g") + .attr("class", "labels"); + svg.append("g") + .attr("class", "lines"); var radius = Math.min(width, height) / 2; var pie = d3.pie() @@ -61,11 +60,13 @@ class Donut extends Component { .outerRadius(radius * 0.9); svg.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); - var key = function (d) { return d.data.label; }; var percentkey = function (d, i) { return { idx: i, data: d.data.percent }; }; - var colorRange = d3.schemePastel1; - colorRange.push(...d3.schemePaired); + var colorRange = []; + + for(let i=0;i HIDE_LIMIT){ + return d.data.percent + "%"; + } + else { + return " "; + } }).transition().duration(1000) .attrTween("transform", function (d) { this._current = this._current || d; @@ -143,7 +144,12 @@ class Donut extends Component { .append("text") .attr("dy", ".35em") .text(function (d) { - return d.data.label; + if(d.data.percent > HIDE_LIMIT){ + return d.data.label; + } + else { + return " "; + } }).transition().duration(1000) .attrTween("transform", function (d) { this._current = this._current || d; @@ -180,12 +186,21 @@ class Donut extends Component { this._current = this._current || d; var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); - return function (t) { - var d2 = interpolate(t); - var pos = outerArc.centroid(d2); - pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); - return [arc.centroid(d2), outerArc.centroid(d2), pos]; - }; + if(d.data.percent < HIDE_LIMIT){ + return function(t){ + return [[0,0],[0,0],[0,0]]; + } + } + else { + return function (t) { + console.log(t); + var d2 = interpolate(t); + var pos = outerArc.centroid(d2); + pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); + return [arc.centroid(d2), outerArc.centroid(d2), pos]; + }; + } + }); polyline.exit() @@ -226,7 +241,12 @@ class Donut extends Component { .append("text") .attr("dy", ".35em") .text(function (d) { - return d.data.percent + "%"; + if(d.data.percent > HIDE_LIMIT){ + return d.data.percent+"%"; + } + else { + return " "; + } }); percent.transition().duration(1000) @@ -258,7 +278,12 @@ class Donut extends Component { .append("text") .attr("dy", ".35em") .text(function (d) { - return d.data.label; + if(d.data.percent > HIDE_LIMIT){ + return d.data.label; + } + else { + return " "; + } }); text.transition().duration(1000) @@ -298,21 +323,26 @@ class Donut extends Component { this._current = this._current || d; var interpolate = d3.interpolate(this._current, d); this._current = interpolate(0); - return function (t) { - var d2 = interpolate(t); - var pos = outerArc.centroid(d2); - pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); - return [arc.centroid(d2), outerArc.centroid(d2), pos]; - }; + if(d.data.percent < HIDE_LIMIT){ + return function(t){ + return [[0,0],[0,0],[0,0]]; + } + } + else { + return function (t) { + console.log(t); + var d2 = interpolate(t); + var pos = outerArc.centroid(d2); + pos[0] = radius * 0.95 * (midAngle(d2) < Math.PI ? 1 : -1); + return [arc.centroid(d2), outerArc.centroid(d2), pos]; + }; + } }); polyline.exit() .remove(); }; - - - d3.select(".randomize") .on("click", function () { color = d3.scaleOrdinal() @@ -321,13 +351,11 @@ class Donut extends Component { changeupdate(randomData()); }); changeinit(randomData()); - } + return
- - - render() { - return
+
; } } + export default Donut; \ No newline at end of file diff --git a/client/src/components/charts/Donut.css b/client/src/components/charts/css/Donut.css similarity index 88% rename from client/src/components/charts/Donut.css rename to client/src/components/charts/css/Donut.css index 43be2f595698b517fda6e1181e35da864a2d4fd3..92803f5fb14c0500c56ec923ed8024f022b2f6f7 100644 --- a/client/src/components/charts/Donut.css +++ b/client/src/components/charts/css/Donut.css @@ -5,8 +5,6 @@ div#root { body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - width: 960px; - height: 500px; position: relative; } diff --git a/deps.json b/client/src/components/charts/deps.json similarity index 100% rename from deps.json rename to client/src/components/charts/deps.json diff --git a/client/src/components/charts/index.js b/client/src/components/charts/index.js index 9c093f6ca9eb57e93ead1e65712b664b46913027..b7a1a2189f09c7b901bf021cecf3793e9eba496d 100644 --- a/client/src/components/charts/index.js +++ b/client/src/components/charts/index.js @@ -2,7 +2,7 @@ import LineChart from "./LineChart"; import BarChart from "./BarChart"; import Donut from "./Donut"; -export { +export default { LineChart, Donut, BarChart, diff --git a/client/src/components/propertysale/AverageSurfacePrice.js b/client/src/components/propertysale/AverageSurfacePrice.js index 90dc94eec6b29f9fbd9d4273c20efd5493d1f17a..83cf2bfbabaca4100a2f8ad2321b49e8cebb7b1a 100644 --- a/client/src/components/propertysale/AverageSurfacePrice.js +++ b/client/src/components/propertysale/AverageSurfacePrice.js @@ -2,7 +2,7 @@ import React from "react"; import { connect } from "react-redux"; import PropTypes from "prop-types"; import { Header, Footer } from "../layout" -import { LineChart } from "../charts"; +import LineChart from "../charts/LineChart"; import * as actions from "../../actions/propertysale/average_surface_price"; diff --git a/client/src/components/propertysale/SalesByGranularity.js b/client/src/components/propertysale/SalesByGranularity.js index e3f06572c86568660016ba2e266040ffca4b6931..b1eb559a72b0933b7b462fea08176775e18faf9e 100644 --- a/client/src/components/propertysale/SalesByGranularity.js +++ b/client/src/components/propertysale/SalesByGranularity.js @@ -3,7 +3,6 @@ import { connect } from "react-redux"; import PropTypes from "prop-types"; import { Header, Footer } from "../layout" import { BarChart } from "../charts"; - import * as actions from "../../actions/propertysale/sales_by_granularity"; class SalesByGranularity extends React.Component { diff --git a/client/src/components/propertysale/SalesByRegions.js b/client/src/components/propertysale/SalesByRegions.js new file mode 100644 index 0000000000000000000000000000000000000000..239c17571cb41a18271c0adde3208e652aac8981 --- /dev/null +++ b/client/src/components/propertysale/SalesByRegions.js @@ -0,0 +1,71 @@ +import React from "react"; +import { connect } from "react-redux"; +import PropTypes from "prop-types"; +import { Header, Footer } from "../layout" +import Donut from "../charts/Donut"; +import './css/salesByRegions.css'; +import * as actions from "../../actions/propertysale/sales_by_regions"; + +class SalesByRegions extends React.Component { + static propTypes = { + error: PropTypes.string, + loading: PropTypes.bool.isRequired, + data: PropTypes.array, + fetch_data: PropTypes.func.isRequired, + }; + + componentDidMount() { + this.props.fetch_data(this.props.year); + } + + render() { + return
+
+

Répartiton du nombre de ventes par région

+ { + this.props.error && +

{this.props.error}

+ } + + { + this.props.loading ? +

Chargement...

+ : + + + } +
+
; + } +} + +const mapStateToProps = state => { + const { + propertysale: { + salesbyregion: {//doit respecter la case du combiner des reducers, sinon le data récupéré est vide + year = 2015, + data = [], + loading = false, + error, + } = {}, + } = {}, + } = state; + + return { year, data, loading, error }; +} + +const mapDispatchToProps = dispatch => ({ + fetch_data: (year) => dispatch(actions.fetch_data(year)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SalesByRegions); \ No newline at end of file diff --git a/client/src/components/propertysale/css/salesByRegions.css b/client/src/components/propertysale/css/salesByRegions.css new file mode 100644 index 0000000000000000000000000000000000000000..f9c892677b50dc6c0d515431e5345a578a5dce8c --- /dev/null +++ b/client/src/components/propertysale/css/salesByRegions.css @@ -0,0 +1,48 @@ +div#root { + width: 100%; + height: 600; +} + +body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + position: relative; + } + + svg { + width: 100%; + height: 100%; + } + +.custom-select { + position: relative; +} + +.custom-select--container { + position: relative; + + background-color: #fff; + /*border: #777 1px solid; + margin: 0 0 1.5em 0;*/ + + overflow: hidden; + /* + Le select natif pourra + dépasser sans être vu + */ +} + +.custom-select--container::after { + /* Le pointeur du select */ + content: ''; + position: absolute; + top: 50%; + margin-top: -3px; + right: .75em; + display: block; + width: 0; height: 0; + border-color: transparent; + border-top-color: #444; + border-width: 6px; + border-style: solid; + pointer-events: none; +} \ No newline at end of file diff --git a/client/src/components/propertysale/index.js b/client/src/components/propertysale/index.js index 64c65ffcdfdb78aa474199a6e116266da8a855bb..b6cb803e6e23da297cb2e71d09bfd72aaa393ab4 100644 --- a/client/src/components/propertysale/index.js +++ b/client/src/components/propertysale/index.js @@ -1,4 +1,5 @@ import AverageSurfacePrice from "./AverageSurfacePrice"; +import SalesByRegions from "./SalesByRegions"; import SalesByGranularity from "./SalesByGranularity"; -export { AverageSurfacePrice, SalesByGranularity }; +export { AverageSurfacePrice, SalesByGranularity, SalesByRegions }; diff --git a/client/src/homepage.js b/client/src/homepage.js index ab40164c8032d05680b1a565ed4dfd2b4b66df99..013f4b18850986213eb6f609564b3ab33d299080 100644 --- a/client/src/homepage.js +++ b/client/src/homepage.js @@ -16,7 +16,7 @@ const homepage = () => (
- Graphique1 + Graphique1
Prix du M²
@@ -24,7 +24,7 @@ const homepage = () => (
- Graphique2 + Graphique2
Nombre de Vente
diff --git a/client/src/index.js b/client/src/index.js index 7f2b63e9a5f09a6f3297e64a31e78e1bb270265d..65db189e382f17a745980e1eefcc9575f9035f39 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -34,7 +34,6 @@ const store = createStore( }), applyMiddleware(routerMiddleware(history), thunk) ); - ReactDOM.render( diff --git a/client/src/reducers/propertysale/index.js b/client/src/reducers/propertysale/index.js index 423bc04a5dc66369037fa41954555a901fb1f014..6150f4adca093cfec8f6e6b50e7f6c83de3c9951 100644 --- a/client/src/reducers/propertysale/index.js +++ b/client/src/reducers/propertysale/index.js @@ -1,9 +1,10 @@ import { combineReducers } from 'redux'; import averageSurfacePrice from "./averageSurfacePrice"; +import salesbyregion from "./salesByRegions"; import salesByGranularity from "./salesByGranularity"; - export default combineReducers({ averageSurfacePrice, salesByGranularity, + salesbyregion }); \ No newline at end of file diff --git a/client/src/reducers/propertysale/salesByRegions.js b/client/src/reducers/propertysale/salesByRegions.js new file mode 100644 index 0000000000000000000000000000000000000000..dc4c26480dc9621016906b5ca6f3b2445dcdddc0 --- /dev/null +++ b/client/src/reducers/propertysale/salesByRegions.js @@ -0,0 +1,34 @@ +import { combineReducers } from 'redux'; + +function data(state = [], action) { + switch(action.type) { + case "PROPERTY_SALE_SALES_BY_REGION_SUCCESS": + return action.retrieved; + default: + return state; + } +} + +function error(state = null, action) { + switch(action.type) { + case "PROPERTY_SALE_SALES_BY_REGION_ERROR": + return action.error; + default: + return state; + } +} + +function loading(state = false, action) { + switch(action.type) { + case "PROPERTY_SALE_SALES_BY_REGION_LOADING": + return action.loading; + default: + return state; + } +} + +export default combineReducers({ + data, + error, + loading, +}); \ No newline at end of file diff --git a/client/src/routes/propertysale.js b/client/src/routes/propertysale.js index f44a0f5bcb018fd40ce7e8482debd684cc42a1ee..d3d60da1c068f7b8ef30bb13d83c36594c7e4c15 100644 --- a/client/src/routes/propertysale.js +++ b/client/src/routes/propertysale.js @@ -1,8 +1,9 @@ import React from 'react'; import { Route } from 'react-router-dom'; -import { AverageSurfacePrice, SalesByGranularity } from '../components/propertysale'; +import { AverageSurfacePrice,SalesByRegions,SalesByGranularity } from '../components/propertysale'; export default [ , + , , -]; \ No newline at end of file +];