@pie-element/hotspot 6.3.2-next.2 → 6.3.2-next.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/configure/lib/DeleteWidget.js +19 -14
- package/configure/lib/DeleteWidget.js.map +1 -1
- package/configure/lib/buttons/circle.js +1 -1
- package/configure/lib/buttons/circle.js.map +1 -1
- package/configure/lib/defaults.js +2 -1
- package/configure/lib/defaults.js.map +1 -1
- package/configure/lib/hotspot-circle.js +229 -0
- package/configure/lib/hotspot-circle.js.map +1 -0
- package/configure/lib/hotspot-container.js +18 -7
- package/configure/lib/hotspot-container.js.map +1 -1
- package/configure/lib/hotspot-drawable.js +41 -14
- package/configure/lib/hotspot-drawable.js.map +1 -1
- package/configure/lib/hotspot-polygon.js +1 -2
- package/configure/lib/hotspot-polygon.js.map +1 -1
- package/configure/lib/hotspot-rectangle.js +0 -1
- package/configure/lib/hotspot-rectangle.js.map +1 -1
- package/configure/lib/index.js +8 -1
- package/configure/lib/index.js.map +1 -1
- package/configure/lib/shapes/circle.js +29 -10
- package/configure/lib/shapes/circle.js.map +1 -1
- package/configure/lib/utils.js +14 -1
- package/configure/lib/utils.js.map +1 -1
- package/configure/package.json +1 -1
- package/configure/src/DeleteWidget.jsx +16 -8
- package/configure/src/__tests__/__snapshots__/hotspot-container.test.js.snap +25 -0
- package/configure/src/__tests__/__snapshots__/hotspot-drawable.test.js.snap +0 -9
- package/configure/src/__tests__/__snapshots__/root.test.js.snap +18 -0
- package/configure/src/__tests__/hotspot-container.test.js +58 -3
- package/configure/src/__tests__/root.test.js +17 -0
- package/configure/src/__tests__/utils.test.js +18 -3
- package/configure/src/buttons/circle.jsx +1 -1
- package/configure/src/defaults.js +1 -0
- package/configure/src/hotspot-circle.jsx +145 -0
- package/configure/src/hotspot-container.jsx +13 -6
- package/configure/src/hotspot-drawable.jsx +26 -16
- package/configure/src/hotspot-polygon.jsx +1 -8
- package/configure/src/hotspot-rectangle.jsx +1 -9
- package/configure/src/index.js +3 -2
- package/configure/src/shapes/circle.js +21 -9
- package/configure/src/utils.js +12 -0
- package/controller/lib/index.js +8 -3
- package/controller/lib/index.js.map +1 -1
- package/controller/package.json +1 -1
- package/controller/src/index.js +16 -6
- package/lib/hotspot/circle.js +191 -0
- package/lib/hotspot/circle.js.map +1 -0
- package/lib/hotspot/container.js +34 -2
- package/lib/hotspot/container.js.map +1 -1
- package/lib/hotspot/index.js.map +1 -1
- package/package.json +3 -3
- package/src/hotspot/circle.jsx +141 -0
- package/src/hotspot/container.jsx +31 -1
- package/src/hotspot/index.jsx +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils.js"],"names":["updateImageDimensions","initialDim","nextDim","keepAspectRatio","resizeType","imageAspectRatio","width","height","getDelta","referenceInitialValue","referenceNextValue","currentValue","getUpdatedRectangle","shape","x","y","getUpdatedPlygon","points","map","point","getUpdatedShapes","shapes","group","getAllShapes","shapesMap","shapesArray","shapesKeys","Object","keys","length","reduce","acc","currentShapeKey","concat","index","groupShapes","rectangles","polygons","shapeProps","isPointInsidePolygon","polygon","inside","i","j","xi","yi","xj","yj","intersect","calculate","polygonPoints","xPoints","yPoints","minX","Math","min","minY","maxX","max","maxY","textX","textY","generateValidationMessage","config","minShapes","maxShapes","maxSelections","shapesMessage","selectionsMessage","message"],"mappings":"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","sourcesContent":["import cloneDeep from 'lodash/cloneDeep';\n\nconst updateImageDimensions = (initialDim, nextDim, keepAspectRatio, resizeType) => {\n // if we want to keep image aspect ratio\n if (keepAspectRatio) {\n const imageAspectRatio = initialDim.width / initialDim.height;\n\n if (resizeType === 'height') {\n // if we want to change image height => we update the width accordingly\n return {\n width: nextDim.height * imageAspectRatio,\n height: nextDim.height,\n };\n }\n\n // if we want to change image width => we update the height accordingly\n return {\n width: nextDim.width,\n height: nextDim.width / imageAspectRatio,\n };\n }\n\n // if we don't want to keep aspect ratio, we just update both values\n return {\n width: nextDim.width,\n height: nextDim.height,\n };\n};\n\n// referenceInitialValue = the initial value of the Stage\n// referenceNextValue = the next value of the Stage\n// currentValue = the value that has to be re-sized influenced by the changes that were made on the Stage\nconst getDelta = (referenceInitialValue, referenceNextValue, currentValue) =>\n (referenceNextValue / referenceInitialValue) * currentValue;\n\nconst getUpdatedRectangle = (initialDim, nextDim, shape) => ({\n ...shape,\n width: getDelta(initialDim.width, nextDim.width, shape.width),\n height: getDelta(initialDim.height, nextDim.height, shape.height),\n x: getDelta(initialDim.width, nextDim.width, shape.x),\n y: getDelta(initialDim.height, nextDim.height, shape.y),\n});\n\nconst getUpdatedPlygon = (initialDim, nextDim, shape) => ({\n ...shape,\n points: shape.points.map((point) => ({\n x: getDelta(initialDim.width, nextDim.width, point.x),\n y: getDelta(initialDim.height, nextDim.height, point.y),\n })),\n});\n\n// initialDim = the initial dimensions: { width, height } of the Stage\n// nextDim = the next dimensions: { width, height } of the Stage\n// shapes = array of shapes that have to be re-sized and re-positioned\nconst getUpdatedShapes = (initialDim, nextDim, shapes) => {\n return shapes.map((shape) => {\n if (shape.group === 'rectangles') {\n return getUpdatedRectangle(initialDim, nextDim, shape);\n }\n\n if (shape.group === 'polygons') {\n return getUpdatedPlygon(initialDim, nextDim, shape);\n }\n });\n};\n\n// converts shapes map to shapes array\n// example:\n// from: { rectangles: [r1], polygons: [p1, p2]}\n// to: [{ ...r1, group: 'rectangles' }, { ...p1, group: 'polygons' }, { ...p2, group: 'polygons' }]\n// if a shape has index defined, keep it, otherwise initialize it\n// index is used for the UNDO function\nconst getAllShapes = (shapesMap) => {\n shapesMap = shapesMap || {};\n const shapesArray = [];\n const shapesKeys = Object.keys(shapesMap);\n\n return shapesKeys.length\n ? shapesKeys.reduce(\n (acc, currentShapeKey) =>\n acc.concat(\n shapesMap[currentShapeKey]\n ? shapesMap[currentShapeKey].map((shape, index) => ({\n ...shape,\n group: currentShapeKey,\n index: shape.index || acc.length + index,\n }))\n : [],\n ),\n shapesArray,\n )\n : shapesArray;\n};\n\n// converts shapes array to shapes map\n// is the reverse of getAllShapes function\n// example:\n// from: [{ ...r1, group: 'rectangles' }, { ...p1, group: 'polygons' }, { ...p2, group: 'polygons' }]\n// to: { rectangles: [r1], polygons: [p1, p2]}\nconst groupShapes = (shapesArray) => {\n shapesArray = shapesArray || [];\n const shapesMap = {\n rectangles: [],\n polygons: [],\n };\n\n if (shapesArray.length) {\n return shapesArray.reduce((acc, { group, ...shapeProps }) => {\n acc[group] = [...(acc[group] || []), shapeProps];\n return acc;\n }, shapesMap);\n }\n\n return cloneDeep(shapesMap);\n};\n\nconst isPointInsidePolygon = (polygon, x, y) => {\n let inside = false;\n\n if (!polygon || polygon.length <= 0) {\n return inside;\n }\n\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x;\n const yi = polygon[i].y;\n const xj = polygon[j].x;\n const yj = polygon[j].y;\n\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;\n\n if (intersect) {\n inside = !inside;\n }\n }\n\n return inside;\n};\n\nconst calculate = (polygonPoints) => {\n if (!polygonPoints || polygonPoints.length <= 0) {\n return { x: 0, y: 0 };\n }\n\n const xPoints = polygonPoints.map((point) => point.x);\n const yPoints = polygonPoints.map((point) => point.y);\n const minX = Math.min(...xPoints);\n const minY = Math.min(...yPoints);\n const maxX = Math.max(...xPoints);\n const maxY = Math.max(...yPoints);\n\n // Find a suitable position for the text element within the polygon\n let textX, textY;\n\n for (let x = minX; x <= maxX - 20; x++) {\n for (let y = maxY - 20; y > minY; y--) {\n // Check if the text element's position (x, y) is within the polygon\n if (isPointInsidePolygon(polygonPoints, x, y)) {\n textX = x - 10;\n textY = y;\n break;\n }\n }\n }\n\n return { x: textX, y: textY };\n};\n\nconst generateValidationMessage = (config) => {\n const { minShapes, maxShapes, maxSelections } = config;\n\n const shapesMessage =\n `\\nThere should be at least ${minShapes} ` + (maxShapes ? `and at most ${maxShapes} ` : '') + 'shapes defined.';\n\n const selectionsMessage =\n '\\nThere should be at least 1 ' +\n (maxSelections ? `and at most ${maxSelections} ` : '') +\n 'shape' +\n (maxSelections ? 's' : '') +\n ' selected.';\n\n const message = 'Validation requirements:' + shapesMessage + selectionsMessage;\n\n return message;\n};\n\nexport {\n calculate,\n isPointInsidePolygon,\n updateImageDimensions,\n generateValidationMessage,\n getUpdatedShapes,\n getAllShapes,\n groupShapes,\n getUpdatedRectangle,\n getUpdatedPlygon,\n};\n"],"file":"utils.js"}
|
|
1
|
+
{"version":3,"sources":["../src/utils.js"],"names":["updateImageDimensions","initialDim","nextDim","keepAspectRatio","resizeType","imageAspectRatio","width","height","getDelta","referenceInitialValue","referenceNextValue","currentValue","getUpdatedRectangle","shape","x","y","getUpdatedCircles","radius","getUpdatedPlygon","points","map","point","getUpdatedShapes","shapes","group","getAllShapes","shapesMap","shapesArray","shapesKeys","Object","keys","length","reduce","acc","currentShapeKey","concat","index","groupShapes","rectangles","polygons","circles","shapeProps","isPointInsidePolygon","polygon","inside","i","j","xi","yi","xj","yj","intersect","calculate","polygonPoints","xPoints","yPoints","minX","Math","min","minY","maxX","max","maxY","textX","textY","generateValidationMessage","config","minShapes","maxShapes","maxSelections","shapesMessage","selectionsMessage","message"],"mappings":";;;;;;;;;;;;;;;AAAA;;;;;;;;AAEA,IAAMA,qBAAqB,GAAG,SAAxBA,qBAAwB,CAACC,UAAD,EAAaC,OAAb,EAAsBC,eAAtB,EAAuCC,UAAvC,EAAsD;AAClF;AACA,MAAID,eAAJ,EAAqB;AACnB,QAAME,gBAAgB,GAAGJ,UAAU,CAACK,KAAX,GAAmBL,UAAU,CAACM,MAAvD;;AAEA,QAAIH,UAAU,KAAK,QAAnB,EAA6B;AAC3B;AACA,aAAO;AACLE,QAAAA,KAAK,EAAEJ,OAAO,CAACK,MAAR,GAAiBF,gBADnB;AAELE,QAAAA,MAAM,EAAEL,OAAO,CAACK;AAFX,OAAP;AAID,KATkB,CAWnB;;;AACA,WAAO;AACLD,MAAAA,KAAK,EAAEJ,OAAO,CAACI,KADV;AAELC,MAAAA,MAAM,EAAEL,OAAO,CAACI,KAAR,GAAgBD;AAFnB,KAAP;AAID,GAlBiF,CAoBlF;;;AACA,SAAO;AACLC,IAAAA,KAAK,EAAEJ,OAAO,CAACI,KADV;AAELC,IAAAA,MAAM,EAAEL,OAAO,CAACK;AAFX,GAAP;AAID,CAzBD,C,CA2BA;AACA;AACA;;;;;AACA,IAAMC,QAAQ,GAAG,SAAXA,QAAW,CAACC,qBAAD,EAAwBC,kBAAxB,EAA4CC,YAA5C;AAAA,SACdD,kBAAkB,GAAGD,qBAAtB,GAA+CE,YADhC;AAAA,CAAjB;;AAGA,IAAMC,mBAAmB,GAAG,SAAtBA,mBAAsB,CAACX,UAAD,EAAaC,OAAb,EAAsBW,KAAtB;AAAA,yCACvBA,KADuB;AAE1BP,IAAAA,KAAK,EAAEE,QAAQ,CAACP,UAAU,CAACK,KAAZ,EAAmBJ,OAAO,CAACI,KAA3B,EAAkCO,KAAK,CAACP,KAAxC,CAFW;AAG1BC,IAAAA,MAAM,EAAEC,QAAQ,CAACP,UAAU,CAACM,MAAZ,EAAoBL,OAAO,CAACK,MAA5B,EAAoCM,KAAK,CAACN,MAA1C,CAHU;AAI1BO,IAAAA,CAAC,EAAEN,QAAQ,CAACP,UAAU,CAACK,KAAZ,EAAmBJ,OAAO,CAACI,KAA3B,EAAkCO,KAAK,CAACC,CAAxC,CAJe;AAK1BC,IAAAA,CAAC,EAAEP,QAAQ,CAACP,UAAU,CAACM,MAAZ,EAAoBL,OAAO,CAACK,MAA5B,EAAoCM,KAAK,CAACE,CAA1C;AALe;AAAA,CAA5B;;;;AAQA,IAAMC,iBAAiB,GAAG,SAApBA,iBAAoB,CAACf,UAAD,EAAaC,OAAb,EAAsBW,KAAtB;AAAA,yCACrBA,KADqB;AAExBI,IAAAA,MAAM,EAAET,QAAQ,CAACP,UAAU,CAACgB,MAAZ,EAAoBf,OAAO,CAACe,MAA5B,EAAoCJ,KAAK,CAACI,MAA1C,CAFQ;AAGxBH,IAAAA,CAAC,EAAEN,QAAQ,CAACP,UAAU,CAACK,KAAZ,EAAmBJ,OAAO,CAACI,KAA3B,EAAkCO,KAAK,CAACC,CAAxC,CAHa;AAIxBC,IAAAA,CAAC,EAAEP,QAAQ,CAACP,UAAU,CAACM,MAAZ,EAAoBL,OAAO,CAACK,MAA5B,EAAoCM,KAAK,CAACE,CAA1C;AAJa;AAAA,CAA1B;;AAOA,IAAMG,gBAAgB,GAAG,SAAnBA,gBAAmB,CAACjB,UAAD,EAAaC,OAAb,EAAsBW,KAAtB;AAAA,yCACpBA,KADoB;AAEvBM,IAAAA,MAAM,EAAEN,KAAK,CAACM,MAAN,CAAaC,GAAb,CAAiB,UAACC,KAAD;AAAA,aAAY;AACnCP,QAAAA,CAAC,EAAEN,QAAQ,CAACP,UAAU,CAACK,KAAZ,EAAmBJ,OAAO,CAACI,KAA3B,EAAkCe,KAAK,CAACP,CAAxC,CADwB;AAEnCC,QAAAA,CAAC,EAAEP,QAAQ,CAACP,UAAU,CAACM,MAAZ,EAAoBL,OAAO,CAACK,MAA5B,EAAoCc,KAAK,CAACN,CAA1C;AAFwB,OAAZ;AAAA,KAAjB;AAFe;AAAA,CAAzB,C,CAQA;AACA;AACA;;;;;AACA,IAAMO,gBAAgB,GAAG,SAAnBA,gBAAmB,CAACrB,UAAD,EAAaC,OAAb,EAAsBqB,MAAtB,EAAiC;AACxD,SAAOA,MAAM,CAACH,GAAP,CAAW,UAACP,KAAD,EAAW;AAC3B,QAAIA,KAAK,CAACW,KAAN,KAAgB,YAApB,EAAkC;AAChC,aAAOZ,mBAAmB,CAACX,UAAD,EAAaC,OAAb,EAAsBW,KAAtB,CAA1B;AACD;;AAED,QAAIA,KAAK,CAACW,KAAN,KAAgB,UAApB,EAAgC;AAC9B,aAAON,gBAAgB,CAACjB,UAAD,EAAaC,OAAb,EAAsBW,KAAtB,CAAvB;AACD;;AAED,QAAIA,KAAK,CAACW,KAAN,KAAgB,SAApB,EAA+B;AAC7B,aAAOR,iBAAiB,CAACf,UAAD,EAAaC,OAAb,EAAsBW,KAAtB,CAAxB;AACD;AACF,GAZM,CAAP;AAaD,CAdD,C,CAgBA;AACA;AACA;AACA;AACA;AACA;;;;;AACA,IAAMY,YAAY,GAAG,SAAfA,YAAe,CAACC,SAAD,EAAe;AAClCA,EAAAA,SAAS,GAAGA,SAAS,IAAI,EAAzB;AACA,MAAMC,WAAW,GAAG,EAApB;AACA,MAAMC,UAAU,GAAGC,MAAM,CAACC,IAAP,CAAYJ,SAAZ,CAAnB;AAEA,SAAOE,UAAU,CAACG,MAAX,GACHH,UAAU,CAACI,MAAX,CACE,UAACC,GAAD,EAAMC,eAAN;AAAA,WACED,GAAG,CAACE,MAAJ,CACET,SAAS,CAACQ,eAAD,CAAT,GACIR,SAAS,CAACQ,eAAD,CAAT,CAA2Bd,GAA3B,CAA+B,UAACP,KAAD,EAAQuB,KAAR;AAAA,6CAC1BvB,KAD0B;AAE7BW,QAAAA,KAAK,EAAEU,eAFsB;AAG7BE,QAAAA,KAAK,EAAEvB,KAAK,CAACuB,KAAN,IAAeH,GAAG,CAACF,MAAJ,GAAaK;AAHN;AAAA,KAA/B,CADJ,GAMI,EAPN,CADF;AAAA,GADF,EAWET,WAXF,CADG,GAcHA,WAdJ;AAeD,CApBD,C,CAsBA;AACA;AACA;AACA;AACA;;;;;AACA,IAAMU,WAAW,GAAG,SAAdA,WAAc,CAACV,WAAD,EAAiB;AACnCA,EAAAA,WAAW,GAAGA,WAAW,IAAI,EAA7B;AACA,MAAMD,SAAS,GAAG;AAChBY,IAAAA,UAAU,EAAE,EADI;AAEhBC,IAAAA,QAAQ,EAAE,EAFM;AAGhBC,IAAAA,OAAO,EAAE;AAHO,GAAlB;;AAMA,MAAIb,WAAW,CAACI,MAAhB,EAAwB;AACtB,WAAOJ,WAAW,CAACK,MAAZ,CAAmB,UAACC,GAAD,QAAmC;AAAA,UAA3BT,KAA2B,QAA3BA,KAA2B;AAAA,UAAjBiB,UAAiB;AAC3DR,MAAAA,GAAG,CAACT,KAAD,CAAH,iDAAkBS,GAAG,CAACT,KAAD,CAAH,IAAc,EAAhC,IAAqCiB,UAArC;AACA,aAAOR,GAAP;AACD,KAHM,EAGJP,SAHI,CAAP;AAID;;AAED,SAAO,2BAAUA,SAAV,CAAP;AACD,CAhBD;;;;AAkBA,IAAMgB,oBAAoB,GAAG,SAAvBA,oBAAuB,CAACC,OAAD,EAAU7B,CAAV,EAAaC,CAAb,EAAmB;AAC9C,MAAI6B,MAAM,GAAG,KAAb;;AAEA,MAAI,CAACD,OAAD,IAAYA,OAAO,CAACZ,MAAR,IAAkB,CAAlC,EAAqC;AACnC,WAAOa,MAAP;AACD;;AAED,OAAK,IAAIC,CAAC,GAAG,CAAR,EAAWC,CAAC,GAAGH,OAAO,CAACZ,MAAR,GAAiB,CAArC,EAAwCc,CAAC,GAAGF,OAAO,CAACZ,MAApD,EAA4De,CAAC,GAAGD,CAAC,EAAjE,EAAqE;AACnE,QAAME,EAAE,GAAGJ,OAAO,CAACE,CAAD,CAAP,CAAW/B,CAAtB;AACA,QAAMkC,EAAE,GAAGL,OAAO,CAACE,CAAD,CAAP,CAAW9B,CAAtB;AACA,QAAMkC,EAAE,GAAGN,OAAO,CAACG,CAAD,CAAP,CAAWhC,CAAtB;AACA,QAAMoC,EAAE,GAAGP,OAAO,CAACG,CAAD,CAAP,CAAW/B,CAAtB;AAEA,QAAMoC,SAAS,GAAGH,EAAE,GAAGjC,CAAL,KAAWmC,EAAE,GAAGnC,CAAhB,IAAqBD,CAAC,GAAI,CAACmC,EAAE,GAAGF,EAAN,KAAahC,CAAC,GAAGiC,EAAjB,CAAD,IAA0BE,EAAE,GAAGF,EAA/B,IAAqCD,EAAhF;;AAEA,QAAII,SAAJ,EAAe;AACbP,MAAAA,MAAM,GAAG,CAACA,MAAV;AACD;AACF;;AAED,SAAOA,MAAP;AACD,CArBD;;;;AAuBA,IAAMQ,SAAS,GAAG,SAAZA,SAAY,CAACC,aAAD,EAAmB;AACnC,MAAI,CAACA,aAAD,IAAkBA,aAAa,CAACtB,MAAd,IAAwB,CAA9C,EAAiD;AAC/C,WAAO;AAAEjB,MAAAA,CAAC,EAAE,CAAL;AAAQC,MAAAA,CAAC,EAAE;AAAX,KAAP;AACD;;AAED,MAAMuC,OAAO,GAAGD,aAAa,CAACjC,GAAd,CAAkB,UAACC,KAAD;AAAA,WAAWA,KAAK,CAACP,CAAjB;AAAA,GAAlB,CAAhB;AACA,MAAMyC,OAAO,GAAGF,aAAa,CAACjC,GAAd,CAAkB,UAACC,KAAD;AAAA,WAAWA,KAAK,CAACN,CAAjB;AAAA,GAAlB,CAAhB;AACA,MAAMyC,IAAI,GAAGC,IAAI,CAACC,GAAL,OAAAD,IAAI,sCAAQH,OAAR,EAAjB;AACA,MAAMK,IAAI,GAAGF,IAAI,CAACC,GAAL,OAAAD,IAAI,sCAAQF,OAAR,EAAjB;AACA,MAAMK,IAAI,GAAGH,IAAI,CAACI,GAAL,OAAAJ,IAAI,sCAAQH,OAAR,EAAjB;AACA,MAAMQ,IAAI,GAAGL,IAAI,CAACI,GAAL,OAAAJ,IAAI,sCAAQF,OAAR,EAAjB,CAVmC,CAYnC;;AACA,MAAIQ,KAAJ,EAAWC,KAAX;;AAEA,OAAK,IAAIlD,CAAC,GAAG0C,IAAb,EAAmB1C,CAAC,IAAI8C,IAAI,GAAG,EAA/B,EAAmC9C,CAAC,EAApC,EAAwC;AACtC,SAAK,IAAIC,CAAC,GAAG+C,IAAI,GAAG,EAApB,EAAwB/C,CAAC,GAAG4C,IAA5B,EAAkC5C,CAAC,EAAnC,EAAuC;AACrC;AACA,UAAI2B,oBAAoB,CAACW,aAAD,EAAgBvC,CAAhB,EAAmBC,CAAnB,CAAxB,EAA+C;AAC7CgD,QAAAA,KAAK,GAAGjD,CAAC,GAAG,EAAZ;AACAkD,QAAAA,KAAK,GAAGjD,CAAR;AACA;AACD;AACF;AACF;;AAED,SAAO;AAAED,IAAAA,CAAC,EAAEiD,KAAL;AAAYhD,IAAAA,CAAC,EAAEiD;AAAf,GAAP;AACD,CA3BD;;;;AA6BA,IAAMC,yBAAyB,GAAG,SAA5BA,yBAA4B,CAACC,MAAD,EAAY;AAC5C,MAAQC,SAAR,GAAgDD,MAAhD,CAAQC,SAAR;AAAA,MAAmBC,SAAnB,GAAgDF,MAAhD,CAAmBE,SAAnB;AAAA,MAA8BC,aAA9B,GAAgDH,MAAhD,CAA8BG,aAA9B;AAEA,MAAMC,aAAa,GACjB,qCAA8BH,SAA9B,UAA8CC,SAAS,yBAAkBA,SAAlB,SAAiC,EAAxF,IAA8F,iBADhG;AAGA,MAAMG,iBAAiB,GACrB,mCACCF,aAAa,yBAAkBA,aAAlB,SAAqC,EADnD,IAEA,OAFA,IAGCA,aAAa,GAAG,GAAH,GAAS,EAHvB,IAIA,YALF;AAOA,MAAMG,OAAO,GAAG,6BAA6BF,aAA7B,GAA6CC,iBAA7D;AAEA,SAAOC,OAAP;AACD,CAhBD","sourcesContent":["import cloneDeep from 'lodash/cloneDeep';\n\nconst updateImageDimensions = (initialDim, nextDim, keepAspectRatio, resizeType) => {\n // if we want to keep image aspect ratio\n if (keepAspectRatio) {\n const imageAspectRatio = initialDim.width / initialDim.height;\n\n if (resizeType === 'height') {\n // if we want to change image height => we update the width accordingly\n return {\n width: nextDim.height * imageAspectRatio,\n height: nextDim.height,\n };\n }\n\n // if we want to change image width => we update the height accordingly\n return {\n width: nextDim.width,\n height: nextDim.width / imageAspectRatio,\n };\n }\n\n // if we don't want to keep aspect ratio, we just update both values\n return {\n width: nextDim.width,\n height: nextDim.height,\n };\n};\n\n// referenceInitialValue = the initial value of the Stage\n// referenceNextValue = the next value of the Stage\n// currentValue = the value that has to be re-sized influenced by the changes that were made on the Stage\nconst getDelta = (referenceInitialValue, referenceNextValue, currentValue) =>\n (referenceNextValue / referenceInitialValue) * currentValue;\n\nconst getUpdatedRectangle = (initialDim, nextDim, shape) => ({\n ...shape,\n width: getDelta(initialDim.width, nextDim.width, shape.width),\n height: getDelta(initialDim.height, nextDim.height, shape.height),\n x: getDelta(initialDim.width, nextDim.width, shape.x),\n y: getDelta(initialDim.height, nextDim.height, shape.y),\n});\n\nconst getUpdatedCircles = (initialDim, nextDim, shape) => ({\n ...shape,\n radius: getDelta(initialDim.radius, nextDim.radius, shape.radius),\n x: getDelta(initialDim.width, nextDim.width, shape.x),\n y: getDelta(initialDim.height, nextDim.height, shape.y),\n});\n\nconst getUpdatedPlygon = (initialDim, nextDim, shape) => ({\n ...shape,\n points: shape.points.map((point) => ({\n x: getDelta(initialDim.width, nextDim.width, point.x),\n y: getDelta(initialDim.height, nextDim.height, point.y),\n })),\n});\n\n// initialDim = the initial dimensions: { width, height } of the Stage\n// nextDim = the next dimensions: { width, height } of the Stage\n// shapes = array of shapes that have to be re-sized and re-positioned\nconst getUpdatedShapes = (initialDim, nextDim, shapes) => {\n return shapes.map((shape) => {\n if (shape.group === 'rectangles') {\n return getUpdatedRectangle(initialDim, nextDim, shape);\n }\n\n if (shape.group === 'polygons') {\n return getUpdatedPlygon(initialDim, nextDim, shape);\n }\n\n if (shape.group === 'circles') {\n return getUpdatedCircles(initialDim, nextDim, shape);\n }\n });\n};\n\n// converts shapes map to shapes array\n// example:\n// from: { rectangles: [r1], polygons: [p1, p2]}\n// to: [{ ...r1, group: 'rectangles' }, { ...p1, group: 'polygons' }, { ...p2, group: 'polygons' }]\n// if a shape has index defined, keep it, otherwise initialize it\n// index is used for the UNDO function\nconst getAllShapes = (shapesMap) => {\n shapesMap = shapesMap || {};\n const shapesArray = [];\n const shapesKeys = Object.keys(shapesMap);\n\n return shapesKeys.length\n ? shapesKeys.reduce(\n (acc, currentShapeKey) =>\n acc.concat(\n shapesMap[currentShapeKey]\n ? shapesMap[currentShapeKey].map((shape, index) => ({\n ...shape,\n group: currentShapeKey,\n index: shape.index || acc.length + index,\n }))\n : [],\n ),\n shapesArray,\n )\n : shapesArray;\n};\n\n// converts shapes array to shapes map\n// is the reverse of getAllShapes function\n// example:\n// from: [{ ...r1, group: 'rectangles' }, { ...p1, group: 'polygons' }, { ...p2, group: 'polygons' }]\n// to: { rectangles: [r1], polygons: [p1, p2]}\nconst groupShapes = (shapesArray) => {\n shapesArray = shapesArray || [];\n const shapesMap = {\n rectangles: [],\n polygons: [],\n circles: [],\n };\n\n if (shapesArray.length) {\n return shapesArray.reduce((acc, { group, ...shapeProps }) => {\n acc[group] = [...(acc[group] || []), shapeProps];\n return acc;\n }, shapesMap);\n }\n\n return cloneDeep(shapesMap);\n};\n\nconst isPointInsidePolygon = (polygon, x, y) => {\n let inside = false;\n\n if (!polygon || polygon.length <= 0) {\n return inside;\n }\n\n for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\n const xi = polygon[i].x;\n const yi = polygon[i].y;\n const xj = polygon[j].x;\n const yj = polygon[j].y;\n\n const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;\n\n if (intersect) {\n inside = !inside;\n }\n }\n\n return inside;\n};\n\nconst calculate = (polygonPoints) => {\n if (!polygonPoints || polygonPoints.length <= 0) {\n return { x: 0, y: 0 };\n }\n\n const xPoints = polygonPoints.map((point) => point.x);\n const yPoints = polygonPoints.map((point) => point.y);\n const minX = Math.min(...xPoints);\n const minY = Math.min(...yPoints);\n const maxX = Math.max(...xPoints);\n const maxY = Math.max(...yPoints);\n\n // Find a suitable position for the text element within the polygon\n let textX, textY;\n\n for (let x = minX; x <= maxX - 20; x++) {\n for (let y = maxY - 20; y > minY; y--) {\n // Check if the text element's position (x, y) is within the polygon\n if (isPointInsidePolygon(polygonPoints, x, y)) {\n textX = x - 10;\n textY = y;\n break;\n }\n }\n }\n\n return { x: textX, y: textY };\n};\n\nconst generateValidationMessage = (config) => {\n const { minShapes, maxShapes, maxSelections } = config;\n\n const shapesMessage =\n `\\nThere should be at least ${minShapes} ` + (maxShapes ? `and at most ${maxShapes} ` : '') + 'shapes defined.';\n\n const selectionsMessage =\n '\\nThere should be at least 1 ' +\n (maxSelections ? `and at most ${maxSelections} ` : '') +\n 'shape' +\n (maxSelections ? 's' : '') +\n ' selected.';\n\n const message = 'Validation requirements:' + shapesMessage + selectionsMessage;\n\n return message;\n};\n\nexport {\n calculate,\n isPointInsidePolygon,\n updateImageDimensions,\n generateValidationMessage,\n getUpdatedShapes,\n getAllShapes,\n groupShapes,\n getUpdatedRectangle,\n getUpdatedPlygon,\n};\n"],"file":"utils.js"}
|
package/configure/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"@material-ui/core": "^3.9.2",
|
|
11
11
|
"@material-ui/icons": "^3.0.2",
|
|
12
12
|
"@pie-framework/pie-configure-events": "^1.3.0",
|
|
13
|
-
"@pie-lib/pie-toolbox": "1.5.
|
|
13
|
+
"@pie-lib/pie-toolbox": "1.5.4",
|
|
14
14
|
"classnames": "^2.2.6",
|
|
15
15
|
"debug": "^3.1.0",
|
|
16
16
|
"konva": "^3.2.4",
|
|
@@ -5,16 +5,23 @@ import { faDelete } from './icons';
|
|
|
5
5
|
import { ImageComponent } from '@pie-lib/pie-toolbox/icons';
|
|
6
6
|
import { calculate } from './utils';
|
|
7
7
|
|
|
8
|
-
const DeleteWidget = ({ height, id, width, x, y, points,
|
|
8
|
+
const DeleteWidget = ({ height, id, width, x, y, points, isCircle, radius, handleWidgetClick }) => {
|
|
9
9
|
let positionX, positionY;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const offset = 20;
|
|
11
|
+
|
|
12
|
+
if (isCircle) {
|
|
13
|
+
// For circles, position the delete icon above the circle
|
|
14
|
+
positionX = x + radius - offset;
|
|
14
15
|
positionY = y;
|
|
16
|
+
} else if (points) {
|
|
17
|
+
// For polygons, compute position based on points
|
|
18
|
+
const calculated = calculate(points);
|
|
19
|
+
positionX = calculated.x;
|
|
20
|
+
positionY = calculated.y;
|
|
15
21
|
} else {
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
// For rectangles
|
|
23
|
+
positionX = x + width - offset;
|
|
24
|
+
positionY = y + height - offset;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
return (
|
|
@@ -31,13 +38,14 @@ DeleteWidget.propTypes = {
|
|
|
31
38
|
x: PropTypes.number.isRequired,
|
|
32
39
|
y: PropTypes.number.isRequired,
|
|
33
40
|
handleWidgetClick: PropTypes.func.isRequired,
|
|
41
|
+
radius: PropTypes.number,
|
|
42
|
+
isCircle: PropTypes.bool,
|
|
34
43
|
points: PropTypes.arrayOf(
|
|
35
44
|
PropTypes.shape({
|
|
36
45
|
x: PropTypes.number,
|
|
37
46
|
y: PropTypes.number,
|
|
38
47
|
}),
|
|
39
48
|
),
|
|
40
|
-
outlineColor: PropTypes.string.isRequired,
|
|
41
49
|
};
|
|
42
50
|
|
|
43
51
|
export default DeleteWidget;
|
|
@@ -25,6 +25,13 @@ exports[`HotspotContainer render renders 1`] = `
|
|
|
25
25
|
isActive={false}
|
|
26
26
|
/>
|
|
27
27
|
</div>
|
|
28
|
+
<div
|
|
29
|
+
onClick={[Function]}
|
|
30
|
+
>
|
|
31
|
+
<CircleButton
|
|
32
|
+
isActive={false}
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
28
35
|
<WithStyles(UploadControl)
|
|
29
36
|
label="Replace Image"
|
|
30
37
|
onInputClick={[Function]}
|
|
@@ -157,6 +164,24 @@ exports[`HotspotContainer render renders 1`] = `
|
|
|
157
164
|
},
|
|
158
165
|
],
|
|
159
166
|
},
|
|
167
|
+
Object {
|
|
168
|
+
"correct": false,
|
|
169
|
+
"group": "circles",
|
|
170
|
+
"id": "6",
|
|
171
|
+
"index": 6,
|
|
172
|
+
"radius": 70,
|
|
173
|
+
"x": 100,
|
|
174
|
+
"y": 100,
|
|
175
|
+
},
|
|
176
|
+
Object {
|
|
177
|
+
"correct": true,
|
|
178
|
+
"group": "circles",
|
|
179
|
+
"id": "7",
|
|
180
|
+
"index": 7,
|
|
181
|
+
"radius": 30,
|
|
182
|
+
"x": 200,
|
|
183
|
+
"y": 150,
|
|
184
|
+
},
|
|
160
185
|
]
|
|
161
186
|
}
|
|
162
187
|
strokeWidth={5}
|
|
@@ -26,7 +26,6 @@ exports[`HotspotDrawable render renders 1`] = `
|
|
|
26
26
|
>
|
|
27
27
|
<Layer>
|
|
28
28
|
<WithStyles(RectComponent)
|
|
29
|
-
addPolygonPoint={[Function]}
|
|
30
29
|
correct={true}
|
|
31
30
|
height={140}
|
|
32
31
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
@@ -45,7 +44,6 @@ exports[`HotspotDrawable render renders 1`] = `
|
|
|
45
44
|
y={1}
|
|
46
45
|
/>
|
|
47
46
|
<WithStyles(RectComponent)
|
|
48
|
-
addPolygonPoint={[Function]}
|
|
49
47
|
height={140}
|
|
50
48
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
51
49
|
id="1"
|
|
@@ -63,7 +61,6 @@ exports[`HotspotDrawable render renders 1`] = `
|
|
|
63
61
|
y={1}
|
|
64
62
|
/>
|
|
65
63
|
<WithStyles(RectComponent)
|
|
66
|
-
addPolygonPoint={[Function]}
|
|
67
64
|
height={140}
|
|
68
65
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
69
66
|
id="2"
|
|
@@ -216,7 +213,6 @@ exports[`HotspotDrawable render renders with default strokeWidth 1`] = `
|
|
|
216
213
|
>
|
|
217
214
|
<Layer>
|
|
218
215
|
<WithStyles(RectComponent)
|
|
219
|
-
addPolygonPoint={[Function]}
|
|
220
216
|
correct={true}
|
|
221
217
|
height={140}
|
|
222
218
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
@@ -235,7 +231,6 @@ exports[`HotspotDrawable render renders with default strokeWidth 1`] = `
|
|
|
235
231
|
y={1}
|
|
236
232
|
/>
|
|
237
233
|
<WithStyles(RectComponent)
|
|
238
|
-
addPolygonPoint={[Function]}
|
|
239
234
|
height={140}
|
|
240
235
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
241
236
|
id="1"
|
|
@@ -253,7 +248,6 @@ exports[`HotspotDrawable render renders with default strokeWidth 1`] = `
|
|
|
253
248
|
y={1}
|
|
254
249
|
/>
|
|
255
250
|
<WithStyles(RectComponent)
|
|
256
|
-
addPolygonPoint={[Function]}
|
|
257
251
|
height={140}
|
|
258
252
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
259
253
|
id="2"
|
|
@@ -406,7 +400,6 @@ exports[`HotspotDrawable render renders with given strokeWidth 1`] = `
|
|
|
406
400
|
>
|
|
407
401
|
<Layer>
|
|
408
402
|
<WithStyles(RectComponent)
|
|
409
|
-
addPolygonPoint={[Function]}
|
|
410
403
|
correct={true}
|
|
411
404
|
height={140}
|
|
412
405
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
@@ -425,7 +418,6 @@ exports[`HotspotDrawable render renders with given strokeWidth 1`] = `
|
|
|
425
418
|
y={1}
|
|
426
419
|
/>
|
|
427
420
|
<WithStyles(RectComponent)
|
|
428
|
-
addPolygonPoint={[Function]}
|
|
429
421
|
height={140}
|
|
430
422
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
431
423
|
id="1"
|
|
@@ -443,7 +435,6 @@ exports[`HotspotDrawable render renders with given strokeWidth 1`] = `
|
|
|
443
435
|
y={1}
|
|
444
436
|
/>
|
|
445
437
|
<WithStyles(RectComponent)
|
|
446
|
-
addPolygonPoint={[Function]}
|
|
447
438
|
height={140}
|
|
448
439
|
hotspotColor="rgba(137, 183, 244, 0.65)"
|
|
449
440
|
id="2"
|
|
@@ -110,6 +110,15 @@ exports[`Root render renders 1`] = `
|
|
|
110
110
|
"partialScoring": false,
|
|
111
111
|
"prompt": "This is the question prompt",
|
|
112
112
|
"shapes": Object {
|
|
113
|
+
"circles": Array [
|
|
114
|
+
Object {
|
|
115
|
+
"correct": false,
|
|
116
|
+
"id": "6",
|
|
117
|
+
"radius": 70,
|
|
118
|
+
"x": 100,
|
|
119
|
+
"y": 100,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
113
122
|
"polygons": Array [
|
|
114
123
|
Object {
|
|
115
124
|
"correct": true,
|
|
@@ -273,6 +282,15 @@ There should be at least 1 shape selected."
|
|
|
273
282
|
preserveAspectRatioEnabled={true}
|
|
274
283
|
shapes={
|
|
275
284
|
Object {
|
|
285
|
+
"circles": Array [
|
|
286
|
+
Object {
|
|
287
|
+
"correct": false,
|
|
288
|
+
"id": "6",
|
|
289
|
+
"radius": 70,
|
|
290
|
+
"x": 100,
|
|
291
|
+
"y": 100,
|
|
292
|
+
},
|
|
293
|
+
],
|
|
276
294
|
"polygons": Array [
|
|
277
295
|
Object {
|
|
278
296
|
"correct": true,
|
|
@@ -63,6 +63,22 @@ const model = () => ({
|
|
|
63
63
|
correct: false,
|
|
64
64
|
},
|
|
65
65
|
],
|
|
66
|
+
circles: [
|
|
67
|
+
{
|
|
68
|
+
id: '6',
|
|
69
|
+
radius: 70,
|
|
70
|
+
x: 100,
|
|
71
|
+
y: 100,
|
|
72
|
+
correct: false,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: '7',
|
|
76
|
+
radius: 30,
|
|
77
|
+
x: 200,
|
|
78
|
+
y: 150,
|
|
79
|
+
correct: true,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
66
82
|
}),
|
|
67
83
|
),
|
|
68
84
|
dimensions: {
|
|
@@ -175,6 +191,24 @@ describe('HotspotContainer', () => {
|
|
|
175
191
|
group: 'polygons',
|
|
176
192
|
index: 5,
|
|
177
193
|
},
|
|
194
|
+
{
|
|
195
|
+
id: '6',
|
|
196
|
+
radius: 70,
|
|
197
|
+
x: 100,
|
|
198
|
+
y: 100,
|
|
199
|
+
correct: false,
|
|
200
|
+
group: 'circles',
|
|
201
|
+
index: 6,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: '7',
|
|
205
|
+
radius: 30,
|
|
206
|
+
x: 200,
|
|
207
|
+
y: 150,
|
|
208
|
+
correct: true,
|
|
209
|
+
group: 'circles',
|
|
210
|
+
index: 7,
|
|
211
|
+
},
|
|
178
212
|
];
|
|
179
213
|
|
|
180
214
|
beforeEach(() => {
|
|
@@ -187,7 +221,7 @@ describe('HotspotContainer', () => {
|
|
|
187
221
|
|
|
188
222
|
it('onUpdateShapes with new added shape', () => {
|
|
189
223
|
const newShape = {
|
|
190
|
-
id: '
|
|
224
|
+
id: '8',
|
|
191
225
|
height: 140,
|
|
192
226
|
width: 130,
|
|
193
227
|
x: 280,
|
|
@@ -201,7 +235,7 @@ describe('HotspotContainer', () => {
|
|
|
201
235
|
rectangles: [
|
|
202
236
|
...initialModel.shapes.rectangles,
|
|
203
237
|
{
|
|
204
|
-
id: '
|
|
238
|
+
id: '8',
|
|
205
239
|
height: 140,
|
|
206
240
|
width: 130,
|
|
207
241
|
x: 280,
|
|
@@ -209,12 +243,13 @@ describe('HotspotContainer', () => {
|
|
|
209
243
|
},
|
|
210
244
|
],
|
|
211
245
|
polygons: initialModel.shapes.polygons,
|
|
246
|
+
circles: initialModel.shapes.circles,
|
|
212
247
|
});
|
|
213
248
|
});
|
|
214
249
|
|
|
215
250
|
it('onDeleteShape by id', () => {
|
|
216
251
|
console.log('wrapper', wrapper.instance());
|
|
217
|
-
wrapper.instance().onDeleteShape('
|
|
252
|
+
wrapper.instance().onDeleteShape('8');
|
|
218
253
|
expect(onUpdateShapes).toHaveBeenCalledWith(
|
|
219
254
|
groupShapes([
|
|
220
255
|
{ correct: true, group: 'rectangles', height: 140, id: '0', index: 0, width: 130, x: 1, y: 1 },
|
|
@@ -256,6 +291,24 @@ describe('HotspotContainer', () => {
|
|
|
256
291
|
{ x: 407, y: 150 },
|
|
257
292
|
],
|
|
258
293
|
},
|
|
294
|
+
{
|
|
295
|
+
id: '6',
|
|
296
|
+
radius: 70,
|
|
297
|
+
x: 100,
|
|
298
|
+
y: 100,
|
|
299
|
+
correct: false,
|
|
300
|
+
group: 'circles',
|
|
301
|
+
index: 6,
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: '7',
|
|
305
|
+
radius: 30,
|
|
306
|
+
x: 200,
|
|
307
|
+
y: 150,
|
|
308
|
+
correct: true,
|
|
309
|
+
group: 'circles',
|
|
310
|
+
index: 7,
|
|
311
|
+
},
|
|
259
312
|
]),
|
|
260
313
|
);
|
|
261
314
|
});
|
|
@@ -266,6 +319,7 @@ describe('HotspotContainer', () => {
|
|
|
266
319
|
expect(onUpdateShapes).toHaveBeenLastCalledWith({
|
|
267
320
|
rectangles: [],
|
|
268
321
|
polygons: [],
|
|
322
|
+
circles: [],
|
|
269
323
|
});
|
|
270
324
|
});
|
|
271
325
|
|
|
@@ -274,6 +328,7 @@ describe('HotspotContainer', () => {
|
|
|
274
328
|
expect(onUpdateShapes).toHaveBeenLastCalledWith({
|
|
275
329
|
rectangles: [],
|
|
276
330
|
polygons: [],
|
|
331
|
+
circles: [],
|
|
277
332
|
});
|
|
278
333
|
});
|
|
279
334
|
});
|
|
@@ -80,6 +80,15 @@ const model = () => ({
|
|
|
80
80
|
id: '5',
|
|
81
81
|
},
|
|
82
82
|
],
|
|
83
|
+
circles: [
|
|
84
|
+
{
|
|
85
|
+
id: '6',
|
|
86
|
+
radius: 70,
|
|
87
|
+
x: 100,
|
|
88
|
+
y: 100,
|
|
89
|
+
correct: false,
|
|
90
|
+
},
|
|
91
|
+
],
|
|
83
92
|
},
|
|
84
93
|
dimensions: { height: 300, width: 400 },
|
|
85
94
|
hotspotColor: 'rgba(137, 183, 244, 0.65)',
|
|
@@ -177,6 +186,7 @@ describe('Root', () => {
|
|
|
177
186
|
index: 1,
|
|
178
187
|
},
|
|
179
188
|
],
|
|
189
|
+
circles: [],
|
|
180
190
|
});
|
|
181
191
|
});
|
|
182
192
|
|
|
@@ -199,6 +209,7 @@ describe('Root', () => {
|
|
|
199
209
|
index: 1,
|
|
200
210
|
},
|
|
201
211
|
],
|
|
212
|
+
circles: [],
|
|
202
213
|
});
|
|
203
214
|
});
|
|
204
215
|
|
|
@@ -221,6 +232,7 @@ describe('Root', () => {
|
|
|
221
232
|
index: 1,
|
|
222
233
|
},
|
|
223
234
|
],
|
|
235
|
+
circles: [],
|
|
224
236
|
});
|
|
225
237
|
});
|
|
226
238
|
|
|
@@ -243,6 +255,7 @@ describe('Root', () => {
|
|
|
243
255
|
index: 1,
|
|
244
256
|
},
|
|
245
257
|
],
|
|
258
|
+
circles: [],
|
|
246
259
|
});
|
|
247
260
|
});
|
|
248
261
|
});
|
|
@@ -284,6 +297,7 @@ describe('Root', () => {
|
|
|
284
297
|
index: 1,
|
|
285
298
|
},
|
|
286
299
|
],
|
|
300
|
+
circles: [],
|
|
287
301
|
});
|
|
288
302
|
});
|
|
289
303
|
|
|
@@ -306,6 +320,7 @@ describe('Root', () => {
|
|
|
306
320
|
index: 1,
|
|
307
321
|
},
|
|
308
322
|
],
|
|
323
|
+
circles: [],
|
|
309
324
|
});
|
|
310
325
|
});
|
|
311
326
|
|
|
@@ -328,6 +343,7 @@ describe('Root', () => {
|
|
|
328
343
|
],
|
|
329
344
|
},
|
|
330
345
|
],
|
|
346
|
+
circles: [],
|
|
331
347
|
});
|
|
332
348
|
});
|
|
333
349
|
|
|
@@ -350,6 +366,7 @@ describe('Root', () => {
|
|
|
350
366
|
index: 1,
|
|
351
367
|
},
|
|
352
368
|
],
|
|
369
|
+
circles: [],
|
|
353
370
|
});
|
|
354
371
|
});
|
|
355
372
|
});
|
|
@@ -160,6 +160,13 @@ const shapesArray = [
|
|
|
160
160
|
group: 'polygons',
|
|
161
161
|
index: 3,
|
|
162
162
|
},
|
|
163
|
+
{
|
|
164
|
+
radius: 50,
|
|
165
|
+
x: 300,
|
|
166
|
+
y: 150,
|
|
167
|
+
group: 'circles',
|
|
168
|
+
index: 4,
|
|
169
|
+
},
|
|
163
170
|
];
|
|
164
171
|
|
|
165
172
|
const shapesMap = {
|
|
@@ -199,6 +206,14 @@ const shapesMap = {
|
|
|
199
206
|
index: 3,
|
|
200
207
|
},
|
|
201
208
|
],
|
|
209
|
+
circles: [
|
|
210
|
+
{
|
|
211
|
+
radius: 50,
|
|
212
|
+
x: 300,
|
|
213
|
+
y: 150,
|
|
214
|
+
index: 4,
|
|
215
|
+
},
|
|
216
|
+
],
|
|
202
217
|
};
|
|
203
218
|
|
|
204
219
|
describe('getAllShapes', () => {
|
|
@@ -217,9 +232,9 @@ describe('groupShapes', () => {
|
|
|
217
232
|
it.each`
|
|
218
233
|
shapesArray | expected
|
|
219
234
|
${shapesArray} | ${shapesMap}
|
|
220
|
-
${null} | ${{ rectangles: [], polygons: [] }}
|
|
221
|
-
${undefined} | ${{ rectangles: [], polygons: [] }}
|
|
222
|
-
${[]} | ${{ rectangles: [], polygons: [] }}
|
|
235
|
+
${null} | ${{ rectangles: [], polygons: [], circles: [] }}
|
|
236
|
+
${undefined} | ${{ rectangles: [], polygons: [], circles: [] }}
|
|
237
|
+
${[]} | ${{ rectangles: [], polygons: [], circles: [] }}
|
|
223
238
|
`('TURNS shapes = $shapesArray INTO $expected', async ({ shapesArray, expected }) => {
|
|
224
239
|
expect(groupShapes(shapesArray)).toEqual(expected);
|
|
225
240
|
});
|
|
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
4
|
export const CircleButton = ({ isActive = false }) => (
|
|
5
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" viewBox="
|
|
5
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="32" viewBox="56 0 48 32" fill="none">
|
|
6
6
|
<path
|
|
7
7
|
fillRule="evenodd"
|
|
8
8
|
clipRule="evenodd"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { Circle, Group, Transformer } from 'react-konva';
|
|
4
|
+
import { withStyles } from '@material-ui/core/styles';
|
|
5
|
+
import DeleteWidget from './DeleteWidget';
|
|
6
|
+
|
|
7
|
+
class CircleComponent extends React.Component {
|
|
8
|
+
constructor(props) {
|
|
9
|
+
super(props);
|
|
10
|
+
this.state = {
|
|
11
|
+
hovered: false,
|
|
12
|
+
isDragging: false,
|
|
13
|
+
};
|
|
14
|
+
this.shapeRef = React.createRef();
|
|
15
|
+
this.trRef = React.createRef();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
handleClick = (e) => {
|
|
19
|
+
const { radius, isDrawing, onClick, id } = this.props;
|
|
20
|
+
if (radius <= 0 && isDrawing) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
e.cancelBubble = true;
|
|
24
|
+
onClick(id);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
handleMouseEnter = () => {
|
|
28
|
+
document.body.style.cursor = 'pointer';
|
|
29
|
+
this.setState({ hovered: true });
|
|
30
|
+
this.trRef.current.setNode(this.shapeRef.current);
|
|
31
|
+
this.trRef.current.getLayer().batchDraw();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
handleMouseLeave = () => {
|
|
35
|
+
this.setState({ hovered: false });
|
|
36
|
+
document.body.style.cursor = 'default';
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
handleOnDragEnd = (e) => {
|
|
40
|
+
const { onDragEnd, id } = this.props;
|
|
41
|
+
this.setState({ isDragging: false });
|
|
42
|
+
onDragEnd(id, {
|
|
43
|
+
x: e.target.x(),
|
|
44
|
+
y: e.target.y(),
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
onResizeEnd = () => {
|
|
49
|
+
const { onDragEnd, id } = this.props;
|
|
50
|
+
const node = this.shapeRef.current;
|
|
51
|
+
|
|
52
|
+
const newRadius = Math.max(node.radius() * node.scaleX(), 5);
|
|
53
|
+
|
|
54
|
+
this.setState({ isDragging: false });
|
|
55
|
+
onDragEnd(id, {
|
|
56
|
+
x: node.x(),
|
|
57
|
+
y: node.y(),
|
|
58
|
+
radius: newRadius,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
node.scaleX(1);
|
|
62
|
+
node.scaleY(1);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
handleDelete = (id) => {
|
|
66
|
+
const { onDeleteShape } = this.props;
|
|
67
|
+
onDeleteShape(id);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
render() {
|
|
71
|
+
const { classes, correct, radius, hotspotColor, id, outlineColor, x, y, strokeWidth = 5 } = this.props;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<Group classes={classes.group} onMouseLeave={this.handleMouseLeave} onMouseEnter={this.handleMouseEnter}>
|
|
75
|
+
<Circle
|
|
76
|
+
classes={classes.base}
|
|
77
|
+
ref={this.shapeRef}
|
|
78
|
+
radius={radius}
|
|
79
|
+
fill={hotspotColor}
|
|
80
|
+
onClick={this.handleClick}
|
|
81
|
+
onTap={this.handleClick}
|
|
82
|
+
draggable
|
|
83
|
+
stroke={outlineColor}
|
|
84
|
+
strokeWidth={correct ? strokeWidth : 0}
|
|
85
|
+
onDragStart={() => this.setState({ isDragging: true })}
|
|
86
|
+
onDragEnd={this.handleOnDragEnd}
|
|
87
|
+
onTransformStart={() => this.setState({ isDragging: true })}
|
|
88
|
+
onTransformEnd={this.onResizeEnd}
|
|
89
|
+
x={x}
|
|
90
|
+
y={y}
|
|
91
|
+
/>
|
|
92
|
+
{!this.state.isDragging && this.state.hovered && (
|
|
93
|
+
<DeleteWidget id={id} radius={radius} x={x} y={y} handleWidgetClick={this.handleDelete} isCircle={true} />
|
|
94
|
+
)}
|
|
95
|
+
{this.state.hovered && (
|
|
96
|
+
<Transformer
|
|
97
|
+
ref={this.trRef}
|
|
98
|
+
rotateEnabled={false}
|
|
99
|
+
keepRatio={true}
|
|
100
|
+
boundBoxFunc={(oldBox, newBox) => {
|
|
101
|
+
// Constraint to prevent resizing too small
|
|
102
|
+
if (newBox.width < 10 || newBox.height < 10) {
|
|
103
|
+
return oldBox;
|
|
104
|
+
}
|
|
105
|
+
return newBox;
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
</Group>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const styles = () => ({
|
|
115
|
+
base: {
|
|
116
|
+
cursor: 'pointer',
|
|
117
|
+
opacity: 0.5,
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
group: {
|
|
121
|
+
padding: '12px',
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
CircleComponent.propTypes = {
|
|
126
|
+
classes: PropTypes.object.isRequired,
|
|
127
|
+
correct: PropTypes.bool,
|
|
128
|
+
isDrawing: PropTypes.bool.isRequired,
|
|
129
|
+
id: PropTypes.string.isRequired,
|
|
130
|
+
radius: PropTypes.number.isRequired,
|
|
131
|
+
hotspotColor: PropTypes.string.isRequired,
|
|
132
|
+
onClick: PropTypes.func.isRequired,
|
|
133
|
+
onDeleteShape: PropTypes.func.isRequired,
|
|
134
|
+
onDragEnd: PropTypes.func.isRequired,
|
|
135
|
+
outlineColor: PropTypes.string.isRequired,
|
|
136
|
+
x: PropTypes.number.isRequired,
|
|
137
|
+
y: PropTypes.number.isRequired,
|
|
138
|
+
strokeWidth: PropTypes.number,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
CircleComponent.defaultProps = {
|
|
142
|
+
correct: false,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export default withStyles(styles)(CircleComponent);
|