Skip to content

Commit b9ca50a

Browse files
committed
added stay highlighted feature
1 parent 2a65dd8 commit b9ca50a

File tree

3 files changed

+134
-121
lines changed

3 files changed

+134
-121
lines changed

README.md

Lines changed: 118 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,119 @@
1-
# React Img Mapper
2-
React Component to highlight interactive zones in images
3-
4-
> This repository is based on react-image-mapper but with some enhancements
5-
```
6-
1. Decreased size of bundled
7-
2. Added image highlight stay feature
8-
3. Added Natural Dimensions options
9-
4. Added rerenderProps options
10-
5. Added Image Reference in Width, Height and onLoad function to access image properties
11-
6. Added responsive image mapper
12-
7. Promise to be maintained this repository
13-
```
14-
15-
## Installation
16-
```
17-
npm install react-img-mapper --save
18-
```
19-
20-
## Demo & Examples
21-
Live demo: [demo](https://nishargshah.github.io/react-img-mapper)
22-
23-
To build the example locally, run:
24-
25-
```
26-
npm install
27-
npm start
28-
```
29-
30-
Then open [`localhost:3000`](http://localhost:3000) in a browser.
31-
32-
If you want to change something and want to make a compiled file, you just need to run `npm run compile`
33-
## Usage
34-
Import the component as you normally do, and add it wherever you like in your JSX views as below:
35-
36-
```javascript
37-
// ES5 require
38-
var ImageMapper = require('react-img-mapper');
39-
40-
// ES6 import
41-
import ImageMapper from 'react-img-mapper';
42-
43-
<ImageMapper src={IMAGE_URL} map={AREAS_MAP}/>
44-
```
45-
46-
### Properties
47-
|Props|type|Description|default|
48-
|---|---|---|---|
49-
|**src**|*string*|Image source url| **required**|
50-
|**map**|*string*|Mapping description| { name: generated, areas: [ ] }|
51-
|**fillColor**|*string*|Fill color of the highlighted zone|rgba(255, 255, 255, 0.5)|
52-
|**strokeColor**|*string*|Border color of the highlighted zone|rgba(0, 0, 0, 0.5)|
53-
|**lineWidth**|*number*|Border thickness of the highlighted zone|1|
54-
|**width**|*number \| func*|Image width, in function you will get image reference object|0|
55-
|**height**|*number \| func*|Image height, in function you will get image reference object|0|
56-
|**active**|*bool*|Enable/Disable highlighting|true|
57-
|**imgWidth**|*number*|Original image width|0|
58-
|**natural**|*bool*|Give the original dimensions ( height & width ) to canvas and image wrapper|false|
59-
|**rerenderProps**|*array*|specify rerenderProps property, if you want to rerender your map with different property|[]|
60-
|**responsive**|*bool*|responsive map in all resolution ( for enable it you need to specify parentWidth )|false|
61-
|**parentWidth**|*number*|parent max width for responsive|0|
62-
63-
&nbsp;
64-
65-
|Props callbacks|Called on|signature|
66-
|---|---|---|
67-
|**onLoad**|Image loading and canvas initialization completed|(imageRef: obj, parentDimensions: { width, height }): void|
68-
|**onMouseEnter**|Hovering a zone in image|(area: obj, index: num, event): void|
69-
|**onMouseLeave**|Leaving a zone in image|(area: obj, index: num, event): void|
70-
|**onMouseMove**|Moving mouse on a zone in image|(area: obj, index: num, event): void|
71-
|**onClick**|Click on a zone in image|(area: obj, index: num, event): void|
72-
|**onImageClick**|Click outside of a zone in image|(event): void|
73-
|**onImageMouseMove**|Moving mouse on the image itself|(event): void|
74-
75-
&nbsp;
76-
77-
A map is an object describing highlighted areas in the image.
78-
79-
Its structure is similar to the HTML syntax of mapping:
80-
81-
- **map**: (*object*) Object to describe highlighted zones
82-
- **name**: (*string*) Name of the map, used to bind to the image.
83-
- **areas**: (*array*) Array of **area objects**
84-
- **area**: (*object*) Shaped like below :
85-
86-
|Property| type|Description|
87-
|---|:---:|---|
88-
|**_id**|*string*|Uniquely identify an area. An index in an array is used if this value is not provided.|
89-
|**shape**|*string*|Either `rect`, `circle` or `poly`|
90-
|**coords**|*array of number*|Coordinates delimiting the zone according to the specified shape: <ul><li>**rect**: `top-left-X`,`top-left-Y`,`bottom-right-X`,`bottom-right-Y`</li><li>**circle**: `center-X`,`center-Y`,`radius`</li><li>**poly**: Every point in the polygon path as `point-X`,`point-Y`,...</li></ul>|
91-
|**href**|*string*|Target link for a click in the zone (note that if you provide an onClick prop, `href` will be prevented)|
92-
93-
&nbsp;
94-
95-
When received from an event handler, an area is extended with the following properties:
96-
97-
|Property| type|Description|
98-
|---|:---:|---|
99-
|**scaledCoords**|*array of number*|Scaled coordinates (see [Dynamic Scaling](#dynamic-scaling) below)|
100-
|**center**|*array of number*|Coordinates positioning the center or centroid of the area: `[X, Y]`|
101-
102-
## Dynamic scaling When a parent component updates the **width** prop on `<ImageMapper>`, the area coordinates also have to be scaled. This can be accomplished by specifying both the new **width** and a constant **imgWidth**. **imgWidth** is the width of the original image. `<ImageMapper>` will calculate the new coordinates for each area. For example:
103-
104-
```javascript
105-
/* assume that image is actually 1500px wide */
106-
107-
// this will be a 1:1 scale, areas will be 3x bigger than they should be
108-
<ImageMapper width={500} />
109-
110-
// this will be the same 1:1 scale, same problem with areas being too big
111-
<ImageMapper width={500} imgWidth={500} />
112-
113-
// this will scale the areas to 1/3rd, they will now fit the 500px image on the screen
114-
<ImageMapper width={500} imgWidth={1500} />
115-
```
116-
117-
118-
## License
119-
Distributed with an MIT License. See LICENSE.txt for more details!
120-
1+
# React Img Mapper
2+
React Component to highlight interactive zones in images
3+
4+
> This repository is based on react-image-mapper but with some enhancements ```
5+
1. Decreased size of bundled
6+
2. Added image highlight area stay feature
7+
3. Added Natural Dimensions options
8+
4. Added rerenderProps options
9+
5. Added Image Reference in Width, Height and onLoad function to access image properties
10+
6. Added responsive image mapper
11+
7. Promise to be maintained this repository
12+
```
13+
14+
## Installation ```
15+
npm install react-img-mapper --save
16+
```
17+
18+
## Demo & Examples
19+
Live demo: [demo](https://nishargshah.github.io/react-img-mapper)
20+
21+
To build the example locally, run:
22+
23+
```
24+
npm install
25+
npm start
26+
```
27+
28+
Then open [`localhost:3000`](http://localhost:3000) in a browser.
29+
30+
If you want to change something and want to make a compiled file, you just need to run `npm run compile`
31+
## Usage
32+
Import the component as you normally do, and add it wherever you like in your JSX views as below:
33+
34+
```javascript
35+
// ES5 require
36+
var ImageMapper = require('react-img-mapper');
37+
38+
// ES6 import
39+
import ImageMapper from 'react-img-mapper';
40+
41+
<ImageMapper src={IMAGE_URL} map={AREAS_MAP}/>
42+
```
43+
44+
### Properties
45+
|Props|type|Description|default|
46+
|---|---|---|---|
47+
|**src**|*string*|Image source url| **required**|
48+
|**map**|*string*|Mapping description| { name: generated, areas: [ ] }|
49+
|**areaKeyName**|*string*|default unique key name ( **required** for `stayHighlighted` )|id|
50+
|**fillColor**|*string*|Fill color of the highlighted zone|rgba(255, 255, 255, 0.5)|
51+
|**strokeColor**|*string*|Border color of the highlighted zone|rgba(0, 0, 0, 0.5)|
52+
|**lineWidth**|*number*|Border thickness of the highlighted zone|1|
53+
|**width**|*number \| func*|Image width, in function you will get image reference object|0|
54+
|**height**|*number \| func*|Image height, in function you will get image reference object|0|
55+
|**active**|*bool*|Enable/Disable highlighting|true|
56+
|**imgWidth**|*number*|Original image width|0|
57+
|**natural**|*bool*|Give the original dimensions ( height & width ) to canvas and image wrapper|false|
58+
|**stayHighlighted**|*bool*|You will see the highlighted area after clicking on the perticular area|false|
59+
|**rerenderProps**|*array*|specify rerenderProps property, if you want to rerender your map with different property|[]|
60+
|**responsive**|*bool*|responsive map in all resolution ( for enable it you need to specify parentWidth )|false|
61+
|**parentWidth**|*number*|parent max width for responsive|0|
62+
63+
&nbsp;
64+
65+
|Props callbacks|Called on|signature|
66+
|---|---|---|
67+
|**onLoad**|Image loading and canvas initialization completed|(imageRef: obj, parentDimensions: { width, height }): void|
68+
|**onMouseEnter**|Hovering a zone in image|(area: obj, index: num, event): void|
69+
|**onMouseLeave**|Leaving a zone in image|(area: obj, index: num, event): void|
70+
|**onMouseMove**|Moving mouse on a zone in image|(area: obj, index: num, event): void|
71+
|**onClick**|Click on a zone in image|(area: obj, index: num, event): void|
72+
|**onImageClick**|Click outside of a zone in image|(event): void|
73+
|**onImageMouseMove**|Moving mouse on the image itself|(event): void|
74+
75+
&nbsp;
76+
77+
A map is an object describing highlighted areas in the image.
78+
79+
Its structure is similar to the HTML syntax of mapping:
80+
81+
- **map**: (*object*) Object to describe highlighted zones
82+
- **name**: (*string*) Name of the map, used to bind to the image.
83+
- **areas**: (*array*) Array of **area objects** - **area**: (*object*) Shaped like below :
84+
85+
|Property| type|Description|
86+
|---|:---:|---|
87+
|**id**|*string*|Uniquely identify an area. An index in an array is used if this value is not provided. You can set it with `areaKeyName` property|
88+
|**shape**|*string*|Either `rect`, `circle` or `poly`|
89+
|**coords**|*array of number*|Coordinates delimiting the zone according to the specified shape: <ul><li>**rect**: `top-left-X`,`top-left-Y`,`bottom-right-X`,`bottom-right-Y`</li><li>**circle**: `center-X`,`center-Y`,`radius`</li><li>**poly**: Every point in the polygon path as `point-X`,`point-Y`,...</li></ul>|
90+
|**href**|*string*|Target link for a click in the zone (note that if you provide an onClick prop, `href` will be prevented)|
91+
92+
&nbsp;
93+
94+
When received from an event handler, an area is extended with the following properties:
95+
96+
|Property| type|Description|
97+
|---|:---:|---|
98+
|**scaledCoords**|*array of number*|Scaled coordinates (see [Dynamic Scaling](#dynamic-scaling) below)|
99+
|**center**|*array of number*|Coordinates positioning the center or centroid of the area: `[X, Y]`|
100+
101+
## Dynamic scaling When a parent component updates the **width** prop on `<ImageMapper>`, the area coordinates also have to be scaled. This can be accomplished by specifying both the new **width** and a constant **imgWidth**. **imgWidth** is the width of the original image. `<ImageMapper>` will calculate the new coordinates for each area. For example:
102+
```javascript
103+
/* assume that image is actually 1500px wide */
104+
105+
// this will be a 1:1 scale, areas will be 3x bigger than they should be
106+
<ImageMapper width={500} />
107+
108+
// this will be the same 1:1 scale, same problem with areas being too big
109+
<ImageMapper width={500} imgWidth={500} />
110+
111+
// this will scale the areas to 1/3rd, they will now fit the 500px image on the screen
112+
<ImageMapper width={500} imgWidth={1500} />
113+
```
114+
115+
116+
## License
117+
Distributed with an MIT License. See LICENSE.txt for more details!
118+
121119
Copyright (c) 2021 Nisharg Shah

src/example/example.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const Example = () => {
6969
lineWidth={1}
7070
strokeColor="black"
7171
parentWidth={parentRef.current.clientWidth}
72+
stayHighlighted
7273
responsive
7374
/>
7475
{hoveredArea && (
@@ -139,6 +140,7 @@ const Example = () => {
139140
lineWidth={1}
140141
strokeColor="black"
141142
parentWidth={parentRef.current.clientWidth}
143+
stayHighlighted
142144
responsive
143145
/>
144146
)}

src/lib/ImageMapper.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const ImageMapper = props => {
77
const { map: mapProp, src: srcProp, rerenderProps } = props;
88

99
const [map, setMap] = useState(JSON.parse(JSON.stringify(mapProp)));
10+
const [storedMap] = useState(map);
1011
const [isRendered, setRendered] = useState(false);
1112
const [imgRef, setImgRef] = useState(false);
1213
const container = useRef(null);
@@ -171,6 +172,14 @@ const ImageMapper = props => {
171172
const click = (area, index, event) => {
172173
if (props.onClick) {
173174
event.preventDefault();
175+
if (props.stayHighlighted) {
176+
const newArea = { ...area };
177+
newArea.preFillColor = area.fillColor;
178+
const updatedAreas = storedMap.areas.map(cur =>
179+
cur[props.areaKeyName] === area[props.areaKeyName] ? newArea : cur
180+
);
181+
setMap(prev => ({ ...prev, areas: updatedAreas }));
182+
}
174183
props.onClick(area, index, event);
175184
}
176185
};
@@ -242,7 +251,7 @@ const ImageMapper = props => {
242251

243252
return (
244253
<area
245-
key={area._id || index}
254+
key={area[props.areaKeyName] || index.toString()}
246255
shape={area.shape}
247256
coords={scaledCoords.join(',')}
248257
onMouseEnter={event => hoverOn(extendedArea, index, event)}
@@ -290,6 +299,8 @@ ImageMapper.defaultProps = {
290299
height: 0,
291300
imgWidth: 0,
292301
width: 0,
302+
areaKeyName: 'id',
303+
stayHighlighted: false,
293304
rerenderProps: [],
294305
parentWidth: 0,
295306
responsive: false,
@@ -313,6 +324,8 @@ ImageMapper.propTypes = {
313324
strokeColor: PropTypes.string,
314325
width: PropTypes.oneOfType([PropTypes.number, PropTypes.func]),
315326
natural: PropTypes.bool,
327+
areaKeyName: PropTypes.string,
328+
stayHighlighted: PropTypes.bool,
316329
rerenderProps: PropTypes.array,
317330
parentWidth: PropTypes.number,
318331
responsive: PropTypes.bool,

0 commit comments

Comments
 (0)