Is there an function in react-vis to scale each line series into it's % range having the domain min set to 0 and max to 100 - react-vis

I am having 9 different line series being drawn on the react-vis graph. Values of those line series vary. The smallest range is between 0-4, the largest one is between 0 - 12000 (image 1). When I draw all those line series most of them sit down at the bottom of the graph not being readable enough.
react-vis graph showing the current range 0 - 2000
I have tried using the yDomain={[0, 100]}. However, what I see happening now is that the graph max value ends up being 100 and all the other line series with higher values than 100 are not visible (they are being drawn above what we can see).
react-vis graph showing the range set by yDomain to 0-100 and missing other line series as a result
Here is an example of the code if this helps:
<FlexibleWidthXYPlot
onMouseLeave={() => this.setState({crosshairValues: []})}
height={250}
color="blue"
size="12"
xType="time"
yDomain={[0, 100]}
>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis
tickFormat={function tickFormat(d){
const date = new Date(d)
return date.toISOString().substr(11, 8)
}}
tickLabelAngle={45}
margin={{bottom: 100}}
padding={{left: 100}}
/>
<YAxis />
<LineSeries
onNearestX={(value, {index}) =>
this.setState({crosshairValues: gasDataFiltered.map(d => d[index])}
)}
data={gasDataFiltered[0]}
color="#27AE60"
opacity={battVoltShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[1]}
color="#2A80B9"
opacity={fuelInjShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[2]}
color="#8E44AD"
opacity={gasInjShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[3]}
color="#560E0D"
opacity={gasLvlShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[4]}
color="#F39C13"
opacity={gasPressShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[5]}
color="#E91F62"
opacity={gasTempShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[6]}
color="#20E3D1"
opacity={mapShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[7]}
color="#246A80"
opacity={reducerTempShow === true ? 1 : 0.15}
/>
<LineSeries
data={gasDataFiltered[8]}
color="#FF81C3"
opacity={rpmShow === true ? 1 : 0.15}
/>
<Crosshair values={crosshairValues}>
<div className='oscilloscope-tooltip'>
<ul>
<li><span className='oscilloscope-color oscilloscope-color--green'></span>{t('oscilloscope.battVolt')}: {crosshairValues[0] !== undefined && crosshairValues[0].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--blue'></span>{t('oscilloscope.fuelInj')}: {crosshairValues[1] !== undefined && crosshairValues[1].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--purple'></span>{t('oscilloscope.gasInj')}: {crosshairValues[2] !== undefined && crosshairValues[2].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--dark'></span>{t('oscilloscope.gasLvl')}: {crosshairValues[3] !== undefined && crosshairValues[3].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--orange'></span>{t('oscilloscope.gasPress')}: {crosshairValues[4] !== undefined && crosshairValues[4].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--red'></span>{t('oscilloscope.gasTemp')}: {crosshairValues[5] !== undefined && crosshairValues[5].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--light'></span>{t('oscilloscope.map')}: {crosshairValues[6] !== undefined && crosshairValues[6].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--navy'></span>{t('oscilloscope.reducerTemp')}: {crosshairValues[7] !== undefined && crosshairValues[7].y}</li>
<li><span className='oscilloscope-color oscilloscope-color--pink'></span>{t('oscilloscope.rpm')}: {crosshairValues[8] !== undefined && crosshairValues[8].y}</li>
</ul>
</div>
</Crosshair>
</FlexibleWidthXYPlot>
What I would like to have is each line series being scaled perceptually to the 0-100% range without amending the actual values. I need those values still to be shown as I am using the crosshair to show them.

Here is an example how I scaled two graphs ( one values in millions, second in % ) to show on one plot at the same time.
export const getBound = (arr, key, max = true) => {
if (!Array.isArray(arr)) {
return false
}
// `${key}0` is a check for graphs that has y0 and x0 values, for example Bar Charts
const key0 = `${key}0`
let result = max ? 0 : Number(arr[0][key])
arr.forEach(item => {
if (max) {
if (Number(item[key]) > result || (item[key0] && Number(item[key0]) > result)) {
result = item[key0] ? (Number(item[key]) > Number(item[key0])
? Number(item[key]) : Number(item[key0])) : Number(item[key])
}
} else {
if (Number(item[key]) < result || (item[key0] && Number(item[key0]) < result)) {
result = item[key0] ? (Number(item[key]) < Number(item[key0])
? Number(item[key]) : Number(item[key0])) : Number(item[key])
}
}
})
return result
}
export const getScaleValues = (arr1, arr2, roundTicksTo = 5) => {
const arr1AbsMax = Math.abs(getBound(arr1, 'y')) > Math.abs(getBound(arr1, 'y', false))
? Math.abs(getBound(arr1, 'y')) : Math.abs(getBound(arr1, 'y', false))
const arr2AbsMax = Math.abs(getBound(arr2, 'y')) > Math.abs(getBound(arr2, 'y', false))
? Math.abs(getBound(arr2, 'y')) : Math.abs(getBound(arr2, 'y', false))
const coef = arr1AbsMax / arr2AbsMax
const scaled = arr2.map(item => {
return Object.assign({}, item, {
y: item.y * coef,
})
})
const ticksFormat = (v) => formatPercentageTicks(v, coef, roundTicksTo)
return {
coef: coef,
scaled: scaled,
ticksFormat: ticksFormat,
}
}
export const formatPercentageTicks = (value, coef, roundTo = 1) => {
return `${round(value / (coef), roundTo)} %`
}
export const round = (num, roundTo) => {
return num % roundTo < (Math.ceil(roundTo / 2))
? (num % roundTo === 0 ? num : Math.floor(num / roundTo) * roundTo) : Math.ceil(num / roundTo) * roundTo
}
If you have 9 Lines you could take 1 as default, and scale 8 others as % from default.
Also, default YAxis will show numbers, and you could add additional Yaxis for % on the right side:
<YAxis orientation={'right'} tickFormat={v => scaledObj.ticksFormat(v)} />

Related

Formik - arrayfields -- validation handling

I am working with formik/material ui -- and yup validation. I am struggling to get validation showing/working on field arrays
my schema and validation looks like this currently for each field.
"fields": [
{
"type": "date",
"label": "Start Date",
"name": "startDate",
"validation": yup.date().default(function () { return new Date() }).required("date is required").nullable().typeError(''),
"minDate": moment().add(1, 'weeks'),
"maxDate": moment().add(8, 'weeks'),
"disablePast": true,
"disableFuture": false,
//"disabled": true
},
{
"type": "date",
"label": "End Date",
"name": "endDate",
"validation": yup.date().default(function () { return new Date() }).required("date is required").nullable().typeError(''),
"minDate": moment().add(1, 'weeks'),
"maxDate": moment().add(8, 'weeks'),
"disablePast": true,
"disableFuture": false,
//"disabled": true
}
]
I've seen on formik - they have some validation like this - but how do I apply it my code base for dates?
https://formik.org/docs/api/fieldarray
const schema = Yup.object().shape({
friends: Yup.array()
.of(
Yup.object().shape({
name: Yup.string().min(4, 'too short').required('Required'), // these constraints take precedence
salary: Yup.string().min(3, 'cmon').required('Required'), // these constraints take precedence
})
)
.required('Must have friends') // these constraints are shown if and only if inner constraints are satisfied
.min(3, 'Minimum of 3 friends'),
});
my fieldarray looks like this -- and I believe errors should appear under the field group -- the fields outer border goes red -- but it doesn't seem to work for when I null the date - like is required date working?
<>
<FieldArray
name={item.name}
onChange={event => {
console.log("event field array change", event)
}}
>
{({ insert, remove, push }) => (
<div className="field field-array">
<div className="row" key={0}>
{item.fields.map((ch, inx) => (
<span key={"x"+inx}>
<div className="col-x">
<Field
name={`${item.name}.${ch.name}`}
>
{({
field, // { name, value, onChange, onBlur }
form,
meta,
}) => (
<>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DatePicker
label={ch.label}
disablePast={ch.disablePast}
disableFuture={ch.disableFuture}
minDate={moment(ch.minDate)}
maxDate={moment(ch.maxDate)}
value={field.value? moment(field.value).format('YYYY-MM-DD'): moment().format('YYYY-MM-DD')}
{...field}
onChange={(value) => {
form.setFieldValue(field.name, value);
this.props.onHandle(field.name, value);
}}
renderInput={(params) => {
return (<TextField {...params} name={field.name} />)
}}
/>
</LocalizationProvider>
{meta.touched && meta.error && (
<div className="error">{meta.error}</div>
)}
</>
)}
</Field>
</div>
{inx === 0 &&
(<span></span>)
}
</span>
))}
</div>
</div>
)}
</FieldArray>
</>
I worked this out
"validation": yup.array().of( yup.object().shape({ firstName: yup.string().min(4, 'too short').required('Required'), lastName: yup.string().min(3, 'cmon').required('Required'), }) ).min(1, 'Minimum of 1 friends')
-- but in the display of errors had to check if it was an array or a string to avoid a render error
under the add more button to display array errors of the main list.
<FormHelperText
error={(form.errors[parent.name] && form.errors[parent.name].length > 0 ? true : false)}
>
{typeof form.errors[parent.name] === "string" &&
<>{form.errors[parent.name]}</>
}
</FormHelperText>
and under the fields - meta errors
{(getHelperVisibility(values, ch)) &&
<FormHelperText
error={meta.touched && (meta.error && meta.error.length > 0 ? true : false)}
>
{meta.error}
</FormHelperText>
}

Fomik FormGroup textfields

I am working on an application and I have made a form framework -- but there is a request to have dual fields.
Min and Max age
rather then having two fields -- "min_age" and "max_age" -- I think they would want an array field "age"
so instead of min_age: 18 and max_age: 33 --- I think they would want an array - age: [18, 33]
I have seen and implemented Radio and Checkbox groups.
-- but when I've tried to swap out the controlled field to a TextField -- the field is malfunctioning and not changing value.
this is what I have got -- as a textfield array group
<>
<FormGroup
row
name={item.name}
disabled={item.disabled}
{...field}
>
{
item.options.map((itm, j) => {
return (
<FormControlLabel key={j}
disabled={item.disabled}
control={
<div className="field field-text">
<TextField
fullWidth={false}
label={itm.label}
value={field.value[j]}
inputProps={{
maxLength: item.charLimit? item.charLimit:null,
autoComplete: item.autoComplete? item.autoComplete:"off"
}}
rows={(item.type === "comment") ? 6 : null}
multiline={(item.type === "comment") ? true : false}
/>
</div>
}
//label={itm.label}
onChange={(e, value) => {
//form.setFieldValue(item.name, value)
//this.props.onHandle(item.name, itm.value);
}}
/>
)
})
}
</FormGroup>
</>
and this is the radio group field that works just fine -- I've not seen any other example where textfields are controlled by the formgroup
<>
<RadioGroup
row
name={item.name}
{...field}
>
{
item.options.map((itm, j) => {
return (
<FormControlLabel key={j}
value={itm.value}
disabled={itm.disabled}
control={<Radio />}
label={itm.label}
onChange={(e, value) => {
//form.setFieldValue(item.name, value)
this.props.onHandle(item.name, itm.value);
}}
/>
)
})
}
</RadioGroup>
</>
I've tried to wrap tags around it - from this example -- but then the field_names are uncontrolled.
https://codesandbox.io/s/formik-multi-step-set-value-context-wrapper-sezzs?file=/src/App.js:2157-2449
:rf: : "111"
:rh: : "222"
age : 18
age_array : [18, 30]
button_field : "3"

How do I trim long text with three dots of Node in jstree?

When long text documents are uploaded then my popup's width gets altered.
Is there any way to trim long text with three dots for tree node's text?
Following is my HTML code to create tree structure
<div class="col-md-12" style="height:100%;overflow:auto" ng-if="IsTree">
<oe-jstree source="AssemblyDocuments"
name="documenttree"
is-upload-file="true"
options="treeOptions"
tree-node-creator="createNode(item)"
on-item-selected="NodeSelected(item)"
on-item-created="NodeCreated(item, callback)"
on-item-renamed="NodeRenamed(item, callback)"
on-item-removed="NodeRemoved(item, callback)"
on-item-archived="NodeArcive(item, callback)"
on-item-download="onItemDownload(item, callback)"
on-item-tagged="onItemTagged(item, callback)"
tag-list="TagMst"
is-read-only="isReadOnly"
id="documenttree"></oe-jstree>
</div>
How can I cut text and show three dots with a tooltip?
$scope.createNode = function (nodedata) {
if (nodedata.Name != null)
nodedata.Name = nodedata.Name.trim();
var node = {
id: nodedata.Id,
text: nodedata.Name.substr(0, 60) + (nodedata.Name.length > 60 ? "..." : ""),
state: {
opened: true
},
type: nodedata.isFile == true ? File : Folder,
icon: nodedata.isFile == true ? (nodedata.Archive == true ? 'jstree-zip' : 'jstree-file') : 'jstree-folder',
children: GetChilders(nodedata),
FileTagDetails: nodedata.FileTagDetails,
model: nodedata,
a_attr: {
title: nodedata.Name
}
};
return node;
};
By using text: nodedata.Name.substr(0, 60) + (nodedata.Name.length > 60 ? "..." : ""), you can achieve 3 dots

iTextSharp error Invalid nested tag body found, expected closing tag script

I am getting the following error when trying to generate PDF after converting a Pie Chart to Image.
Can someone advise what is wrong in my HTML file?
**Additional information: Invalid nested tag body found, expected closing tag script.**
The following call in BaseHtmlToPDF.cs raise the exception
parser.Parse(reader);
The is is my HTML file
<html>
<head>
<title> Chart</title>
<link href="https://localhost:44302/Content/report-pdf.css" rel="stylesheet" />
<link href="https://localhost:44303/Content/nv.d3.css" rel="stylesheet" />
<link href="https://localhost:44303/css/app.css" rel="stylesheet" />
<script type="text/javascript" src="https://localhost:44303/Scripts/d3.min.js"></script>
<script type="text/javascript" src="https://localhost:44303/Scripts/d3.tip.v0.6.3.js"></script>
<script type="text/javascript" src="https://localhost:44303/Scripts/nv.d3.js"></script>
</head>
<body class="reportBody">
<div id="SummaryChart">
<table cellpadding="5" cellspacing="0" width="100%" border="0">
<tr>
<td class="title-con">
<h2>IdleTime (Hours)</h2>
</td>
</tr>
<tr>
<td>
<div id="SummaryChart" style="height:500px">
<svg></svg>
</div>
</td>
</tr>
</table>
</div>
<script>
var values = [];
var data = [{
values: values,
key: 'IdleTime'
}];
data[0].values.push({"y": undefined, "x" : '2015/03/01'});
data[0].values.push({"y": undefined, "x" : '2015/03/22'});
data[0].values.push({"y": undefined, "x" : '2015/04/20'});
data[0].values.push({"y": undefined, "x" : '2015/04/21'});
data[0].values.push({"y": 19.5, "x" : '2015/04/22'});
data[0].values.push({"y": undefined, "x" : '2015/04/23'});
data[0].values.push({"y": undefined, "x" : '2015/04/24'});
data[0].values.push({"y": undefined, "x" : '2015/04/29'});
data[0].values.push({"y": undefined, "x" : '2015/04/30'});
init_graphs(data);
function init_graphs(data) {
nv.addGraph(function () {
var chart = nv.models.multiBarChart();
chart.xAxis.tickFormat(function (d) {
var dateTimeFormat = 'dd-MMM-yyyy';
dateTimeFormat = dateTimeFormat.replace('dd', '%d');
dateTimeFormat = dateTimeFormat.replace('MMM', '%b');
dateTimeFormat = dateTimeFormat.replace('yyyy', '%Y');
return d3.time.format(dateTimeFormat)(new Date(d));
});
chart.yAxis.tickFormat(d3.format(',.1f'));
chart.showLegend(false)
chart.xAxis.axisLabel('Time');
chart.yAxis.axisLabel('NPT Hours');
chart.showControls(false);
chart.margin({ left: 90, top: 90, bottom: 50, right: 20 });
chart.transitionDuration(0);
var max = 19.5;
var scale = calculate(0, !max || max < 10 ? 10 : max, 10);
chart.yDomain([scale.niceMin, scale.niceMax]);
d3.select('#SummaryChart svg')
.datum(data)
.call(chart);
nv.utils.windowResize(chart.update);
return chart;
});
function niceNum(range, round) {
// exponent of range
var exponent;
// fractional part of range
var fraction;
// nice, rounded fraction
var niceFraction;
exponent = Math.floor(Math.log(range)/Math.LN10);
fraction = range / Math.pow(10, exponent);
if (round) {
if (fraction < 1.5) niceFraction = 1;
else if (fraction < 3) niceFraction = 2;
else if (fraction < 7) niceFraction = 5;
else niceFraction = 10;
} else {
if (fraction <= 1) niceFraction = 1;
else if (fraction <= 2) niceFraction = 2;
else if (fraction <= 5) niceFraction = 5;
else niceFraction = 10;
}
return niceFraction * Math.pow(10, exponent);
}
function calculate (min, max, maxTicks) {
maxTicks = maxTicks ? maxTicks : 10;
var range = niceNum(max - min, false);
var tickSpacing = niceNum(range / (maxTicks - 1), true);
var niceMin = Math.floor(min / tickSpacing) * tickSpacing;
var niceMax = Math.ceil(max / tickSpacing) * tickSpacing;
var tickValues = [];
for (var value = niceMin; value <= niceMax; value += tickSpacing)
tickValues.push(value);
return { niceMin: niceMin, niceMax: niceMax, tickSpacing: tickSpacing, tickValues: tickValues };
}
}
</script>
</body>
</html>

Drag and drop with touch support for react.js

How to implement drag and drop for Facebooks' react.js with support for touch events?
There's a couple of questions and articles and libraries about drag and drop for react.js, but none of them seems to mention touch events, and none of the demo's work on my phone.
In general I wonder what would be the easiest: Try to implement this using existing d&d libraries which already support touch, but may need some work to properly work together with react. Or try to use any of the react d&d examples and make them work with touch (which, seeing this issue, may not be trivial?)
react-motion (with touch events)
We have tried "react-motion" for dragging items in a list. With more than 15-20 items it becomes really laggy. (But with small list it works good, like in this demo). Be aware that mobile devices are much slower than desktops.
Important note about react-motion: Don't forget to use production mode when testing your animation's performance!
react-dnd (with touch events)
The second option was "react-dnd". It is a great library. It is low level, however, it is rather easy to understand how to work with it. But at first, "react-dnd" was not an option for us because of no touch events support.
Later, when Yahoo had released react-dnd-touch-backend we decided to switch our app from "react-motion" to "react-dnd". This solved all our performance issues. We have list 50-70 items and it just works as expected.
Yahoo has done really good work and the solution works in our production apps.
You already mentioned react-dnd and I make PR that enable dnd for touch devices so you can try it
I haven't found any answer to this yet. The accepted answer is not really an answer but it points to a github library. I am going to try to include here a complete answer using only react.
Here it goes, the code should be self explanatory, but a couple of words ahead of time. We need to use a lot of state variables to keep state between renders, otherwise any variables get reset out. To make the transitions smooth, I update the position once a render was completed using useEffect hook. I tested this in codesandbox, I'm including the link here for anybody to edit the code and play with it, just fork it. It workd with the MS Surface Book2 Pro
and Android. It has a formatting problem with the iPhone IOS. Both for Safari and Chrome. If somebody fixes it that'd be great. For now I have what I need and claim success.
Here are the files under src in codesandbox.io:
App.js
import "./styles/index.pcss";
import "./styles/tailwind-pre-build.css";
import Photos from "./Photos.js";
export default function App() {
return (
<>
<div className="flow-root bg-green-200">
<div className="my-4 bg-blue-100 mb-20">
Drag and Drop with touch screens
</div>
</div>
<div className="flow-root bg-red-200">
<div className="bg-blue-100">
<Photos />
</div>
</div>
</>
);
}
Photos.js:
import React, { useState } from "react";
import "./styles/index.pcss";
import Image from "./image";
export default function Photos() {
const [styleForNumber, setStyleForNumber] = useState({
position: "relative",
width: "58px",
height: "58px"
});
const photosArray = [
"https://spinelli.io/noderestshop/uploads/G.1natalie.1642116451444",
"https://spinelli.io/noderestshop/uploads/G.2natalie.1642116452437",
"https://spinelli.io/noderestshop/uploads/G.3natalie.1642116453418",
"https://spinelli.io/noderestshop/uploads/G.4natalie.1642116454396",
"https://spinelli.io/noderestshop/uploads/G.5natalie.1642116455384",
"https://spinelli.io/noderestshop/uploads/G.6natalie.1642116456410",
"https://spinelli.io/noderestshop/uploads/G.7natalie.1642116457466",
"https://spinelli.io/noderestshop/uploads/G.8natalie.1642116458535",
"https://spinelli.io/noderestshop/uploads/G.0natalie.1642116228246"
];
return (
<>
<div
className="w-1/2 bg-green-200"
style={{
display: "grid",
gridTemplateColumns: "[first] 60px [second] 60px [third] 60px",
gridTemplateRows: "60px 60px 60px",
rowGap: "10px",
columnGap: "20px",
position: "relative",
justifyContent: "center",
placeItems: "center"
}}
>
{photosArray.map((photo, i) => (
<div
className="relative z-1 h-full w-full flex flex-wrap content-center touch-none"
key={i}
>
<div className="contents">
<Image photo={photo} i={i} />
</div>
</div>
))}
</div>
</>
);
}
Image.js:
import React, { useRef, useState, useEffect } from "react";
import "./styles/index.pcss";
export default function Image({ photo, i }) {
const imgRef = useRef();
const [top, setTop] = useState(0);
const [left, setLeft] = useState(0);
const [drag, setDrag] = useState(false);
const [styleForImg, setStyleForImg] = useState({
position: "absolute",
width: "58px",
height: "58px"
});
const [offsetTop, setOffsetTop] = useState(-40);
const [offsetLeft, setOffsetLeft] = useState(0);
const [xAtTouchPointStart, setXAtTouchPointStart] = useState(0);
const [yAtTouchPointStart, setYAtTouchPointStart] = useState(0);
useEffect(() => {
if (drag) {
setStyleForImg({
position: "relative",
width: "58px",
height: "58px",
top: top,
left: left
});
} else {
setStyleForImg({
position: "relative",
width: "58px",
height: "58px"
});
}
console.log("style: ", styleForImg);
}, [drag, top, left]);
const handleTouchStart = (e, i) => {
e.preventDefault();
let evt = typeof e.originalEvent === "undefined" ? e : e.originalEvent;
let touch = evt.touches[0] || evt.changedTouches[0];
const x = +touch.pageX;
const y = +touch.pageY;
console.log(
"onTouchStart coordinates of icon # start: X: " + x + " | Y: " + y
);
console.log("dragged from position n = ", i + 1);
// get the mouse cursor position at startup:
setXAtTouchPointStart(x);
setYAtTouchPointStart(y);
setDrag(true);
};
const handleTouchEnd = (e) => {
// if (process.env.NODE_ENV === 'debug5' || process.env.NODE_ENV === 'development') {
e.preventDefault();
setDrag(false);
console.log(
new Date(),
"onTouchEnd event, coordinates of icon # end: X: " +
e.changedTouches[0]?.clientX +
" | Y: " +
e.changedTouches[0]?.clientY +
" | top: " +
top +
" | left: " +
left
);
};
const handleElementDrag = (e) => {
e = e || window.event;
e.preventDefault();
let x = 0;
let y = 0;
//Get touch or click position
//https://stackoverflow.com/a/41993300/5078983
if (
e.type === "touchstart" ||
e.type === "touchmove" ||
e.type === "touchend" ||
e.type === "touchcancel"
) {
let evt = typeof e.originalEvent === "undefined" ? e : e.originalEvent;
let touch = evt.touches[0] || evt.changedTouches[0];
x = +touch.pageX; // X Coordinate relative to the viewport of the touch point
y = +touch.pageY; // same for Y
} else if (
e.type === "mousedown" ||
e.type === "mouseup" ||
e.type === "mousemove" ||
e.type === "mouseover" ||
e.type === "mouseout" ||
e.type === "mouseenter" ||
e.type === "mouseleave"
) {
x = +e.clientX;
y = +e.clientY;
}
console.log("x: ", x, "y: ", y);
// calculate the new cursor position:
const xRelativeToStart = x - xAtTouchPointStart;
console.log(
"xRel = ",
x,
" - ",
xAtTouchPointStart,
" = ",
xRelativeToStart
);
const yRelativeToStart = y - yAtTouchPointStart;
console.log(
"yRel = ",
y,
" - ",
yAtTouchPointStart,
" = ",
yRelativeToStart
);
// setXAtTouchPointStart(x); // Reseting relative point to current touch point
// setYAtTouchPointStart(y);
// set the element's new position:
setTop(yRelativeToStart + "px");
setLeft(xRelativeToStart + "px");
console.log("top: ", yRelativeToStart + "px");
console.log("Left: ", xRelativeToStart + "px");
};
const handleDragEnd = (e) => {
// if (process.env.NODE_ENV === 'debug5' || process.env.NODE_ENV === 'development') {
console.log(
new Date(),
"Coordinates of icon # end X: " + e.clientX + " | Y: " + e.clientY
);
};
const handleDragStart = (e, i) => {
// From https://stackoverflow.com/a/69109382/15355839
e.stopPropagation(); // let child take the drag
e.dataTransfer.dropEffect = "move";
e.dataTransfer.effectAllowed = "move";
console.log(
"Coordinates of icon # start: X: " + e.clientX + " | Y: " + e.clientY
);
// console.log ('event: ', e)
console.log("dragged from position n = ", i + 1);
};
return (
<img
ref={imgRef}
className="hover:border-none border-4 border-solid border-green-600 mb-4"
src={photo}
alt="placeholder"
style={styleForImg}
onDragStart={(e) => handleDragStart(e, i)}
onDragEnd={handleDragEnd}
onTouchStart={(e) => handleTouchStart(e, i)}
onTouchEnd={handleTouchEnd}
onTouchMove={handleElementDrag}
></img>
);
}
index.js:
import { StrictMode } from "react";
import ReactDOM from "react-dom";
import "./styles/index.pcss";
import App from "./App";
const root = document.getElementById("root");
ReactDOM.render(
<StrictMode>
<App />
</StrictMode>,
root
);
styles.css:
.Main {
font-family: sans-serif;
text-align: center;
}
/styles/index.pcss:
#tailwind base;
#tailwind components;
#tailwind utilities;
I couldn't make tailwinds grid work, so I used the actual css inline styles. No idea why they didn't in codesandbox.