lodash#last JavaScript Examples
The following examples show how to use
lodash#last.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ActivityFeed.js From datapass with GNU Affero General Public License v3.0 | 5 votes |
render() {
const { showDetails } = this.state;
const { events } = this.props;
let eventsToDisplay = chain(events)
.sortBy('updated_at')
.reject(
({ name, diff }) => name === 'update' && isEmpty(getChangelog(diff))
)
.value();
if (!showDetails && events.length > 0) {
eventsToDisplay = [last(eventsToDisplay)];
}
return (
<div>
<div className="activity-head">
<Button
outline
icon="eye"
onClick={() => this.setState({ showDetails: !showDetails })}
>
{showDetails ? 'Cacher l’historique' : 'Voir l’historique'}
</Button>
</div>
{eventsToDisplay.map(
({
id,
comment,
name,
updated_at,
user: { email, given_name, family_name },
diff,
}) => (
<EventItem
key={id}
comment={comment}
name={name}
updated_at={updated_at}
email={email}
family_name={family_name}
given_name={given_name}
diff={diff}
/>
)
)}
</div>
);
}
Example #2
Source File: StatsCell.js From covid19 with MIT License | 5 votes |
Success = ({ countries = [], country = 'usa' }) => {
// Calculate stats
const [counts, setCounts] = useState([])
const stat = (key) =>
commaNumber(last(map(orderBy(counts, 'date.date'), key)))
useEffect(() => {
setCounts(find(countries, ['iso', country])?.dailyCounts)
}, [country])
return (
<div>
<section>
<StatChart data={counts} dataKey="newCases" color="green" />
<Stat value={stat('newCases')} label="New cases" />
</section>
<section>
<StatChart data={counts} dataKey="currentlyInfected" color="yellow" />
<Stat value={stat('currentlyInfected')} label="Currently infected" />
</section>
<section>
<StatChart data={counts} dataKey="totalCases" color="orange" />
<Stat value={stat('totalCases')} label="Confirmed cases" />
</section>
<section>
<StatChart data={counts} dataKey="totalDeaths" color="red" />
<Stat value={stat('totalDeaths')} label="Confirmed deaths" />
</section>
<style jsx>{`
div {
display: grid;
grid-gap: 1rem;
margin-top: 2rem;
}
@media (min-width: 48em) {
div {
grid-template-columns: repeat(4, 1fr);
}
}
section {
position: relative;
min-height: 8rem;
}
section :global(.recharts-responsive-container) {
position: absolute !important;
top: 0;
left: 0;
right: 0;
}
`}</style>
</div>
)
}
Example #3
Source File: enhancers.js From plant-3d-explorer with GNU Affero General Public License v3.0 | 5 votes |
forgeCameraPointsEnhancer = (scan) => {
const poses = scan.camera.poses
let index = 0
return {
...scan,
camera: {
...scan.camera,
poses: orderBy(
poses,
(d) => d.photoUri
).map((point) => {
const m3rotation = new THREE.Matrix3()
m3rotation.set(
...point.rotmat[0],
...point.rotmat[1],
...point.rotmat[2]
)
m3rotation.transpose()
m3rotation.multiplyScalar(-1)
const v3position = new THREE.Vector3(
point.tvec[0],
point.tvec[1],
point.tvec[2]
).applyMatrix3(m3rotation)
function createM4Rot (rotmat) {
const m4rotation = new THREE.Matrix4()
m4rotation.set(
...point.rotmat[0], 0,
...point.rotmat[1], 0,
...point.rotmat[2], 0,
0, 0, 0, 1
)
return m4rotation
}
const objM4rotation = createM4Rot()
const objT = new THREE.Matrix4().makeRotationX(-Math.PI / 2)
objM4rotation.transpose()
objM4rotation.multiply(objT)
const vueM4rotation = createM4Rot()
const vueT = new THREE.Matrix4().makeRotationX(-Math.PI)
vueM4rotation.transpose()
vueM4rotation.multiply(vueT)
return {
index: index++,
id: point.photoUri,
fileName: last(point.photoUri.split('/')),
...point,
v3position,
objM4rotation,
vueM4rotation
}
})
}
}
}
Example #4
Source File: [key].js From hivemind with Apache License 2.0 | 4 votes |
Page = () => {
const { user } = useUser()
const router = useRouter()
const [timestamp, setTimestamp] = useState(
typeof window === 'undefined'
? null
: parseFloat(new URLSearchParams(location.search).get('timestamp'))
)
const { key } = router.query
const { data, error } = useFetch(
user ? user : null,
`/api/mindmaps/${key}?timestamp=${timestamp || ''}`
)
const { data: edata, error: eerror } = useFetch(
user ? user : null,
`/api/timeline/events?key=${key}`
)
const [title, setTitle] = useState(key)
useEffect(() => {
if (user) {
mutate(
[`/api/mindmaps/${key}?timestamp=${timestamp || ''}`, user.token],
null,
true
)
}
}, [user, timestamp, key])
useEffect(() => {
if (user) {
mutate([`/api/timeline/events?key=${key}`, user.token], null, true)
}
}, [user, key])
useEffect(() => {
if (data && data.ok) {
setTitle(data.data.meta.name)
}
}, [data])
useEffect(() => {
const handleRouteChange = (url) => {
const fullURL = new URL(url, location.origin)
const toTs = fullURL.searchParams.get('timestamp')
const toTsF = parseFloat(toTs) || null
if ((!toTsF && timestamp) || toTsF !== timestamp) {
setTimestamp(toTsF)
}
}
router.events.on('routeChangeComplete', handleRouteChange)
return () => {
router.events.off('routeChangeComplete', handleRouteChange)
}
}, [router.events, timestamp])
if (typeof user === 'undefined') {
return <Spinner />
}
if (error && window.notify) {
const options = {
place: 'tr',
message: 'Failed to fetch mind map!',
type: 'danger',
autoDismiss: 7,
}
window.notify(options)
}
if (eerror && window.notify) {
const options = {
place: 'tr',
message: 'Failed to fetch events!',
type: 'danger',
autoDismiss: 7,
}
window.notify(options)
}
const gotEventData = !eerror && edata && edata.ok
const cEvents = gotEventData && edata.data
const prevDisabled = !gotEventData || timestamp === cEvents[0].lctime
const nextDisabled = !gotEventData || timestamp === last(cEvents).lctime
async function jump(to) {
if (to === 'now') {
await router.push('/mmaps/[key]', `/mmaps/${key}`, { shallow: true })
setTimestamp(null)
} else if (gotEventData) {
let toTS, idx
switch (to) {
case 'first':
toTS = cEvents[0].lctime
break
case 'prev':
idx = timestamp
? findIndex(cEvents, { lctime: timestamp })
: cEvents.length
toTS = cEvents[idx - 1].lctime
break
case 'next':
idx = timestamp
? findIndex(cEvents, { lctime: timestamp })
: cEvents.length - 2
toTS = cEvents[idx + 1].lctime
break
case 'last':
toTS = last(cEvents).lctime
break
default:
toTS = to
}
await router.push(
'/mmaps/[key]',
{
pathname: `/mmaps/${key}`,
query: { timestamp: toTS },
},
{ shallow: true }
)
setTimestamp(toTS)
}
}
if (user) {
const output = [
<Row key="title">
<Col xs="auto" md={7}>
<h3>
{title}
{timestamp ? (
<>
<small className={'text-muted'}>
{' '}
@ {new Date(timestamp * 1000).toLocaleString()}
</small>
</>
) : null}
</h3>
</Col>
<Col xs="auto" md={5} className={'text-right'}>
<ShowAll />
<Fit />
<Search />
|
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="tag"
disabled={true}
tooltip="Tag (Coming Soon)"
>
<Tag size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="first"
disabled={prevDisabled}
tooltip="First"
onClick={() => jump('first')}
>
<SkipBack size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="prev"
disabled={prevDisabled}
tooltip="Previous"
onClick={() => jump('prev')}
>
<Rewind size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="next"
disabled={nextDisabled}
tooltip="Next"
onClick={() => jump('next')}
>
<FastForward size={16} />
</ToolTippedButton>
<ToolTippedButton
className="ml-1"
outline
color="secondary"
id="last"
disabled={nextDisabled}
tooltip="Last"
onClick={() => jump('last')}
>
<SkipForward size={16} />
</ToolTippedButton>
|
<Rename
nameChangedCallBack={setTitle}
disabled={!!timestamp}
rootNode={get(data, ['data', 'meta'], {})}
/>
<ToolTippedButton
className="ml-1"
outline
color={timestamp ? 'secondary' : 'danger'}
id="now"
tooltip={timestamp ? 'Click to unlock' : 'Click to lock'}
onClick={() => jump(timestamp ? 'now' : 'last')}
>
{timestamp ? <Lock size={16} /> : <Unlock size={16} />}
</ToolTippedButton>
</Col>
</Row>,
]
if (error && data) {
output.push(
<Row key="content">
<Col>
<Error statusCode={data.status} />
</Col>
</Row>
)
} else if (eerror && edata) {
output.push(
<Row key="content">
<Col>
<Error statusCode={edata.status} />
</Col>
</Row>
)
} else {
output.push(
<Row key="content">
<Col>
<MindMap
data={data}
edata={edata}
timestamp={timestamp}
jump={jump}
/>
</Col>
</Row>
)
}
return output
}
return <AuthPrompt />
}
Example #5
Source File: Chart.js From covid19 with MIT License | 4 votes |
Chart = ({
dailyCounts = [],
countries = [],
enabledCountries,
defaultCountry
// log
}) => {
// sort dailyCounts for all later operations
const sortedDailyCounts = orderBy(dailyCounts, 'date.date')
const offsets = calculateDayOffsets(sortedDailyCounts, defaultCountry)
const offsetDailyCounts = sortedDailyCounts.map((origCount) => {
// deep clone
let count = JSON.parse(JSON.stringify(origCount))
let offset = offsets[count.country.iso]
if (!offset) {
return count
} // in case of benchmark
let newDate = addDays(new Date(count.date.date), offset)
// round date to the nearest day
let offsetForRounded = new Date(newDate.getTime() + 12 * 60 * 60)
let roundedDate = new Date(
offsetForRounded.getFullYear(),
offsetForRounded.getMonth(),
offsetForRounded.getDate()
)
// extract the YYYY-DD-MM portion
count.date.date = new Date(
roundedDate.toISOString().substring(0, 10)
).toISOString()
return count
})
const sortedOffsetDailyCounts = orderBy(offsetDailyCounts, 'date.date')
// Assemble chart display
let days = {}
sortedOffsetDailyCounts.forEach((count) => {
days[count.date.date] = days[count.date.date] || {}
days[count.date.date][`${count.country.iso}TotalCases`] = count.totalCases
days[count.date.date][`${count.country.iso}TotalDeaths`] = count.totalDeaths
})
const countryCounts = groupBy(sortedDailyCounts, 'country.iso')
// Highest date in benchmark country
const maxBenchmarkDate = last(countryCounts[defaultCountry]).date.date
// Calculate X axis numbers to show how many days ahead / behind a country is
for (const day in days) {
const daysBehind = daysBetween(new Date(day), new Date(maxBenchmarkDate))
days[day]['daysBehind'] = daysBehind
}
const behindOrAhead =
(last(Object.values(days))?.daysBehind || -1) > 0 ? 'ahead of' : 'behind'
let updated = new Date(last(countryCounts[defaultCountry]).date.createdAt)
updated.setDate(updated.getDate() + 1) // JS dates suck
updated = updated
.toLocaleDateString()
.replace('/2020', '')
.replace('2020-', '')
// Prepare chart data
const [chartData, setChartData] = useState([])
useEffect(() => {
setChartData(
Object.keys(days).map((day) => ({
date: day,
...days[day]
}))
)
}, [dailyCounts])
// Sorting
useEffect(() => {
setChartData((chartData) => orderBy(chartData, 'date'))
}, [dailyCounts])
return (
<ResponsiveContainer height={512} id="primary">
<LineChart
data={chartData}
margin={{ top: 0, right: 10, bottom: 25, left: 15 }}
>
<XAxis
dataKey="daysBehind"
label={{
value: `Days ${behindOrAhead} ${countryFromKey(
defaultCountry,
countries
)} (last updated: ${updated})`,
position: 'bottom'
}}
/>
<YAxis
tickFormatter={yAxisFormatter}
label={{
value: 'Total COVID-19 Cases',
angle: -90,
position: 'left'
}}
/>
<Tooltip
separator=": "
formatter={(value, key) => [
commaNumber(value),
countryFromKey(key, countries)
]}
/>
<CartesianGrid stroke={theme.colors.snow} strokeDasharray="8 8" />
{enabledCountries.map((iso) => (
<Line
key={iso}
type="monotone"
dataKey={`${iso}TotalCases`}
stroke={theme.colors[iso]}
strokeWidth={defaultCountry === iso ? 6 : 3}
dot={false}
activeDot={{ r: 8 }}
connectNulls
/>
))}
<style>{`
.recharts-label {
fill: ${theme.colors.muted};
}
.recharts-default-tooltip {
border-radius: 0.375rem;
}
.recharts-tooltip-label {
color: ${theme.colors.muted};
font-family: ${theme.fonts.sans};
font-size: 2rem;
line-height: 1.5;
}
#primary .recharts-tooltip-label:after {
content: ' days';
}
#primary .recharts-tooltip-item {
font-family: ${theme.fonts.serif};
font-size: 1rem;
}
@media (prefers-color-scheme: dark) {
.recharts-default-tooltip {
background-color: #1e1e1e !important;
}
.recharts-label {
fill: ${theme.colors.snow};
}
.recharts-tooltip-label {
color: ${theme.colors.snow};
}
.recharts-layer:not(.recharts-active-dot) .recharts-dot {
fill: #1e1e1e !important;
}
line.recharts-cartesian-axis-line,
line.recharts-cartesian-axis-tick-line,
.recharts-cartesian-grid line {
opacity: 0.25 !important;
}
}
`}</style>
</LineChart>
</ResponsiveContainer>
)
}
Example #6
Source File: graph.js From plant-3d-explorer with GNU Affero General Public License v3.0 | 4 votes |
Chart = sceneWrapper(({ valueTransformFn, ifManualData, data, unit, containerWidth, containerHeight }) => {
const [hoveredAngle, setHoveredAngle] = useHoveredAngle()
const [selectedAngle, setSelectedAngle] = useSelectedAngle()
const [colors] = useColor()
const height = containerHeight - (37 * 1.6)
const goal = data.goal
const vertiaclTickNb = Math.max(
data.fruitPoints.length,
data.automated.length,
(data.manual ? data.manual.length : 0)
)
const nb = vertiaclTickNb - 1 // intermediate variable used when creating the Array to plot angles and internodes sequences with the correct size
const verticalTicks = Array(Math.ceil(vertiaclTickNb / 5))
.fill()
.map((_, i) => (i * 5) - (i !== 0 ? 1 : 0))
.filter((d) => (vertiaclTickNb - d) > 3)
// .concat(data.fruitPoints.length - 1)
.concat(vertiaclTickNb - 1)
verticalScale
.domain([first(verticalTicks), last(verticalTicks)])
.rangeRound([height, 5])
const horizontalTicks = data.bounds
horizontalScale
.domain([first(horizontalTicks), last(horizontalTicks)])
.rangeRound([0, containerWidth - 37])
const barHeight = Math.floor(height / vertiaclTickNb)
const points = data.automated
.map((rad, i) => {
return {
datum: rad,
x: horizontalScale(valueTransformFn(rad)) + pointsOffset,
y: verticalScale(i)
}
})
const manualPoints = (!ifManualData ? [] : data.manual)
.map((rad, i) => {
return {
x: horizontalScale(valueTransformFn(rad)) + pointsOffset,
y: verticalScale(i)
}
})
const highligthed = [hoveredAngle, selectedAngle]
.filter((d) => isNotNullAndUndefiend(d))
.filter((d) => d < vertiaclTickNb)[0]
return <Content>
<TopPart>
<HorizontalAxis>
{
horizontalTicks.map((index) => {
return <HorizontalTick
key={`horizontal-tick-${index}`}
left={horizontalScale(index) + 34}
>
<span>
{index} {unit}
</span>
</HorizontalTick>
})
}
{
isNotNullAndUndefiend(goal) && <GoalHorizontalTick
key={'horizontal-tick-goal'}
left={horizontalScale(goal) + 34}
>
<span>
{goal} {unit}
</span>
</GoalHorizontalTick>
}
</HorizontalAxis>
<GraphPart>
<VerticalAxis>
{
verticalTicks.map((index) => {
return <VerticalTick
key={`vertical-tick-${index}`}
top={verticalScale(index)}
>
{index + 1}
</VerticalTick>
})
}
</VerticalAxis>
<SVG
width={containerWidth - 37 + 5}
height={height}
>
<Area d={area(points)} />
<g>
<Line d={line(points)} />
{
points.map((d, index) => {
return <Point
key={`point-${index}`}
cx={d.x}
cy={d.y}
/>
})
}
</g>
{
ifManualData && <g>
<Line d={line(manualPoints)} red />
{
manualPoints.map((d, index) => {
return <Point
red
key={`manual-point-${index}`}
cx={d.x}
cy={d.y}
/>
})
}
</g>
}
{
isNotNullAndUndefiend(goal) && <GoalLine
x1={horizontalScale(goal)}
x2={horizontalScale(goal)}
y1={0}
y2={height}
/>
}
</SVG>
</GraphPart>
</TopPart>
<InteractorContainer
width={containerWidth - 37}
height={height}
onMouseLeave={() => setHoveredAngle(null)}
>
{
new Array(nb)
.fill()
.map((_, i) => {
const d = points[i] || manualPoints[i]
return <Interactor
key={`interactor-${i}`}
top={d.y - (barHeight * 0.5)}
height={barHeight}
selectedAngle={isNotNullAndUndefiend(selectedAngle)}
selected={selectedAngle === i}
hoveredColor={
colors.organs[hoveredAngle]
? colors.organs[hoveredAngle].rgb
: hoveredAngle % 2
? colors.globalOrganColors[1].rgb
: colors.globalOrganColors[0].rgb
}
selectedColor={
colors.organs[selectedAngle]
? colors.organs[selectedAngle].rgb
: selectedAngle % 2
? colors.globalOrganColors[1].rgb
: colors.globalOrganColors[0].rgb
}
hovered={hoveredAngle === i}
onMouseEnter={() => setHoveredAngle(i)}
onClick={() => {
selectedAngle === i ? setSelectedAngle(null) : setSelectedAngle(i)
}}
/>
})
}
{
isNotNullAndUndefiend(highligthed) && <div
style={{
position: 'absolute',
width: 72,
height: 70,
top: -6 + verticalScale(highligthed) - 20,
paddingTop: 10,
left: -40,
background: 'rgba(255, 255, 255, 0.8)'
}}
>
<HighlightedIndex
top={3}
color={
(isNotNullAndUndefiend(selectedAngle) &&
!isNotNullAndUndefiend(hoveredAngle))
? colors.organs[selectedAngle + 1]
? Color(colors.organs[selectedAngle + 1].rgb).toString()
: Color(colors.globalOrganColors[selectedAngle % 2 ? 0 : 1].rgb)
.toString()
: isNotNullAndUndefiend(hoveredAngle)
? colors.organs[hoveredAngle + 1]
? Color(colors.organs[hoveredAngle + 1].rgb).toString()
: Color(colors.globalOrganColors[hoveredAngle % 2 ? 0 : 1]
.rgb)
.toString()
: darkGreen
}
>
<HighlightedIndexContentTop>
Org.<HighlightedIndexValue>
{highligthed + 2}
</HighlightedIndexValue>
{/* {`Org.${highligthed + 2}`} */}
</HighlightedIndexContentTop>
</HighlightedIndex>
<HighlightedIndex
top={20}
color={
(isNotNullAndUndefiend(selectedAngle) && isNotNullAndUndefiend(hoveredAngle))
? Color('#84EEE6').toString()
: Color('#78D89D').toString()
}
>
<HighlightedIndexContent>
<HighlightedIndexValue>
{highligthed + 1}
</HighlightedIndexValue>
{/* {highligthed + 1} */}
</HighlightedIndexContent>
</HighlightedIndex>
<HighlightedIndex
top={20 + 20 - 7}
color={
(isNotNullAndUndefiend(selectedAngle) &&
!isNotNullAndUndefiend(hoveredAngle))
? colors.organs[selectedAngle]
? Color(colors.organs[selectedAngle].rgb).toString()
: Color(colors.globalOrganColors[selectedAngle % 2 ? 1 : 0]
.rgb)
.toString()
: isNotNullAndUndefiend(hoveredAngle)
? colors.organs[hoveredAngle]
? Color(colors.organs[hoveredAngle].rgb).toString()
: Color(colors.globalOrganColors[hoveredAngle % 2 ? 1 : 0]
.rgb)
.toString()
: Color('#78D89D').toString()
}
>
<HighlightedIndexContentBottom>
Org.<HighlightedIndexValue>
{highligthed + 1}
</HighlightedIndexValue>
{/* {`Org.${highligthed + 1}`} */}
</HighlightedIndexContentBottom>
</HighlightedIndex>
</div>
}
{
[selectedAngle, hoveredAngle]
.filter((d) => isNotNullAndUndefiend(d))
.map((d, i) => {
return <div
key={`interacted-angle-${i}`}
>
{
(isNotNullAndUndefiend(data.automated[d])) && (
<HoveredPoint
key={'main'}
top={verticalScale(d + 1) + barHeight - 4}
left={horizontalScale(
valueTransformFn(data.automated[d])
) + 37 - 7}
/>
)
}
{
(ifManualData && isNotNullAndUndefiend(data.manual[d])) && (
<HoveredPoint
red
key={'secondary'}
top={verticalScale(d + 1) + barHeight - 4}
left={horizontalScale(
valueTransformFn(data.manual[d])
) + 37 - 7}
/>
)
}
</div>
})
}
</InteractorContainer>
</Content>
})