浏览代码

Create grid based on responses values for friendliness, correctness, pleasantness and trustwhorthiness

Tatiana Inama 6 年之前
父节点
当前提交
ac2f09592e
共有 2 个文件被更改,包括 96 次插入38 次删除
  1. 10 0
      src/App.css
  2. 86 38
      src/Heatmap.tsx

+ 10 - 0
src/App.css

@@ -204,4 +204,14 @@ form button {
 
 .uva-terms li img {
   width: 100%;
+}
+
+#vom-heatmap-range {
+  background: rgb(0,0,255);
+  background: linear-gradient(to right, #ff0000 1%,#ffff00 25%,#28d328 50%,#1e9999 75%,#0000ff 100%);
+  width: 50%;
+  height: 30px;
+  display: flex;
+  justify-content: space-between;
+  font-weight: bold;
 }

+ 86 - 38
src/Heatmap.tsx

@@ -1,22 +1,34 @@
 import React, { Component } from 'react';
-import { Path, PaperScope, Point, Size, Rectangle, PointText, Color } from 'paper';
+import { Path, PaperScope, Point, Size, Rectangle, Color, PointText } from 'paper';
 
 const CANVAS_STYLE = {
   width: '50%',
   border: '2px solid black'
 };
 
-const X_SEGMENTS = 25;
+const X_SEGMENTS = 30;
 const Y_SEGMENTS = X_SEGMENTS * 1.25;
+const MAX = 200;
+const output_start = 0,
+      output_end = 240,
+      input_start = 1,
+      input_end = 5;
+const RANGE = (n: number) => output_start + ((output_end - output_start) / (input_end - input_start)) * (n - input_start);
+
+
+type Grid = Array<Array<{
+  area: paper.Path.Rectangle,
+  items: Array<paper.Item>
+}>>
 
 type HeatmapData = {
   id: [number, number],
-  shape: paper.Path,
   correctness: number,
   friendliness: number,
   pleasantness: number,
   trustworthiness: number
 }
+
 class Heatmap extends Component<HeatmapProps, HeatmapState> {
   
   constructor(props: HeatmapProps) {
@@ -25,11 +37,11 @@ class Heatmap extends Component<HeatmapProps, HeatmapState> {
     this.state = {
       data: [],
       canvas: undefined,
-      grid: []
+      grid: [],
     }
   }
 
-  drawShape = (path: string, scale: number, data: any) => {
+  drawShape = (path: string, scale: number, data: HeatmapData) => {
     const _path = new Path();
     _path.importJSON(path);
     _path.scale(scale, new Point(0, 0));
@@ -39,75 +51,111 @@ class Heatmap extends Component<HeatmapProps, HeatmapState> {
     return _path;
   }
 
-  mkGrid = (canvas: paper.PaperScope) => {
-    const width = canvas.view.size.width,
-          height = canvas.view.size.height;
-    const size = new Size(width/X_SEGMENTS, height/Y_SEGMENTS);
-
-    const data = this.props.data.reduce<Array<HeatmapData>>((newData, result) => {
+  drawMapData = (data: Result[], canvasWidth: number) => {
+    const _data = data.reduce<Array<HeatmapData>>((newData, result) => {
       return [
         ...newData,
         ...result.canvas.map((shape, shapeId) => {
-          let data = {
+          let data: HeatmapData = {
             id: [result.id, shapeId],
             correctness: shape.form.correctness,
             friendliness: shape.form.friendliness,
             pleasantness: shape.form.pleasantness,
             trustworthiness: shape.form.trustworthiness,
-            shape: {},
           }
-          data.shape = this.drawShape(shape.path, width / result.canvasSize.width, data);
+          this.drawShape(shape.path, canvasWidth / result.canvasSize.width, data);
           return data as HeatmapData;
         })
       ]
     }, [])
+    return _data;
+  }
 
+  mkGrid = (canvas: paper.PaperScope): Grid=> {
+    const width = canvas.view.size.width,
+          height = canvas.view.size.height;
+    const gridSectionSize = new Size(width/X_SEGMENTS, height/Y_SEGMENTS);
+    let grid: Grid = [];
 
-    let grid: Array<Array<paper.Path.Rectangle>> = [];
     for(let row = 0; row < Y_SEGMENTS; row ++) {
       grid[row] = [];
+
       for(let column = 0; column < X_SEGMENTS; column ++) {
         let rect = new Rectangle({
-          point: [column * size.width, row * size.height],
-          size: size,
+          point: [column * gridSectionSize.width, row * gridSectionSize.height],
+          size: gridSectionSize,
         });
 
-        let items = canvas.project.activeLayer.getItems({
-          overlapping: rect
-        })
-        new Path.Rectangle({
-          rectangle: rect,
-          fillColor: new Color(`rgb(${items.length}, ${items.length}, ${items.length})`)
-        })
-        new PointText({
-          point: rect.leftCenter,
-          content: items.length,
-          fillColor: items.length < 50 ? 'white' : 'black',
-          fontSize: 10
-        })
-        // grid[row][column] = new Path.Rectangle({
-        //   point: [column * size.width, row * size.height],
-        //   size: size,
-        // });
+        grid[row][column] = {
+          area: new Path.Rectangle(rect),
+          items: canvas.project.activeLayer.getItems({
+            overlapping: rect
+          })
+        }
       }
     }
-    this.setState({ grid, data })
+    return grid;
   }
 
+  heatmapByAmount = (grid: Grid) => {
+    let xs: number[] = [];
+    grid.forEach(section => {
+      section.forEach(({ area, items }) => {
+        xs = [
+          ...xs,
+          items.length
+        ];
+        area.fillColor = new Color(`rgb(${items.length}, ${items.length}, ${items.length})`)
+      })
+    })
+  }
 
+  heatmapBy = (key: 'correctness' | 'friendliness' | 'pleasantness' | 'trustworthiness', grid: Grid) => {    
+    grid.forEach(section => {
+      section.forEach(({area, items}) => {
+        const total = items.reduce<number>((tot, item) => {
+          return tot + (item.data[key] || 0);
+        }, 0);
+        if (total !== 0) {
+          area.fillColor = new Color({ hue: RANGE(total / items.length), saturation: 1, brightness: items.length/MAX})
+          new PointText({
+            point: area.bounds.leftCenter,
+            content: (total / items.length).toFixed(1)
+          })
+        }
+      })
+    })
+  }
 
   componentDidMount = () => {
     const canvas = new PaperScope();
     canvas.setup('vom-heatmap-canvas');
     canvas.view.viewSize.height = canvas.view.size.width * 1.25;
-    this.mkGrid(canvas);
+    const data = this.drawMapData(this.props.data, canvas.view.size.width);
+    const grid = this.mkGrid(canvas);
     this.setState({
+      data,
       canvas,
+      grid,
     })
   }
 
   render = () => (
-    <div className="vom-heatmap" style={{display: 'flex', justifyContent: 'center'}}>
+    <div className="vom-heatmap" style={{display: 'flex', flexDirection: 'column', justifyContent: 'center', alignItems: 'center'}}>
+      <div>
+        <button onClick={() => { this.heatmapByAmount(this.state.grid)}}>by shape amount</button>
+        <button onClick={() => { this.heatmapBy('friendliness', this.state.grid)}}>by friendliness</button>
+        <button onClick={() => { this.heatmapBy('correctness', this.state.grid)}}>by correct</button>
+        <button onClick={() => { this.heatmapBy('pleasantness', this.state.grid)}}>by pleasant</button>
+        <button onClick={() => { this.heatmapBy('trustworthiness', this.state.grid)}}>by trustworthiness</button>
+      </div>
+      <div id="vom-heatmap-range">
+        <div>1</div>
+        <div>2</div>
+        <div>3</div>
+        <div>4</div>
+        <div>5</div>
+      </div>
       <canvas id="vom-heatmap-canvas" style={CANVAS_STYLE}></canvas>
     </div>
   )
@@ -156,7 +204,7 @@ type HeatmapProps = {
 type HeatmapState = {
   data: HeatmapData[],
   canvas?: paper.PaperScope,
-  grid: Array<Array<paper.Path.Rectangle>>
+  grid: Grid,
 }