Skip to content

Commit

Permalink
Working towards data on the map.
Browse files Browse the repository at this point in the history
  • Loading branch information
chmac committed Oct 16, 2024
1 parent 07be9ef commit 984d99a
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 4 deletions.
21 changes: 21 additions & 0 deletions nr-app/src/components/Map.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import {
allPlusCodesForRegion,
coordinatesToPlusCode,
} from "@/utils/map.utils";
import { StyleSheet, View } from "react-native";

import MapView, { Marker } from "react-native-maps";
Expand All @@ -7,8 +11,25 @@ export default function Map() {
<View style={styles.mapContainer}>
<MapView
style={styles.map}
rotateEnabled={false}
pitchEnabled={false}
onRegionChangeComplete={(region, details) => {
console.log("#rIMmxg Map move completed", region, details);
const topRightCoordinates = {
latitude: region.latitude + region.latitudeDelta,
longitude: region.longitude + region.longitudeDelta,
};
const bottomLeftCoordinates = {
latitude: region.latitude - region.latitudeDelta,
longitude: region.longitude - region.longitudeDelta,
};
const topRightCode = coordinatesToPlusCode(topRightCoordinates);
const bottomLeftCode = coordinatesToPlusCode(bottomLeftCoordinates);
console.log(
`#bu2PoU Bottom left is ${bottomLeftCode}, top right is ${topRightCode}`,
);
const parts = allPlusCodesForRegion(region);
console.log("#fWrvAt Got parts", parts);
}}
>
<Marker coordinate={{ latitude: 52, longitude: 13 }} title="A marker" />
Expand Down
3 changes: 3 additions & 0 deletions nr-app/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export const ID_SEPARATOR = ":" as const;

export const DEFAULT_PLUS_CODE_LENGTH = 4;
export const NOSTR_EVENT_INDEX_MAXIMUM_PLUS_CODE_LENGTH = 6;
4 changes: 3 additions & 1 deletion nr-app/src/redux/actions/map.actions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createAction } from "@reduxjs/toolkit";

export const setVisiblePlusCodes = createAction("SET_VISIBLE_PLUS_CODES");
export const setVisiblePlusCodes = createAction<string[]>(
"map/setVisiblePlusCodes",
);
9 changes: 7 additions & 2 deletions nr-app/src/redux/sagas/map.saga.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { PayloadAction } from "@reduxjs/toolkit";
import { put, takeEvery } from "redux-saga/effects";
import {
setMapSubscriptionIsUpdating,
setVisiblePlusCodes,
} from "../slices/map.slice";

function* updateDataForMap(action: PayloadAction<string[]>) {
try {
// Setup a subscription
const visiblePlusCodes = action.payload;
console.log("#tJ7hyp Got visible plus codes", visiblePlusCodes);
// Write the state to redux
put({ type: "success" });
put(setMapSubscriptionIsUpdating(true));
// Call a subscription
} catch (error) {
const message = error instanceof Error ? error.message : "";
yield put({ type: "fail", action: message });
}
}

export function* mapSaga() {
yield takeEvery("some_action", updateDataForMap);
yield takeEvery(setVisiblePlusCodes, updateDataForMap);
}

/**
Expand Down
16 changes: 15 additions & 1 deletion nr-app/src/redux/slices/map.slice.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,43 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { RootState } from "../store";
import { setVisiblePlusCodes as REAL_setVisiblePlusCodes } from "../actions/map.actions";

export const SLICE_NAME = "map";

interface MapState {
mapSubscriptionIsUpdating: boolean;
visiblePlusCodes: string[];
}

const initialState: MapState = {
mapSubscriptionIsUpdating: false,
visiblePlusCodes: [],
};

const mapSlice = createSlice({
name: SLICE_NAME,
initialState,
reducers: {
setMapSubscriptionIsUpdating: (state, action: PayloadAction<boolean>) => {
if (state.mapSubscriptionIsUpdating !== action.payload) {
state.mapSubscriptionIsUpdating = action.payload;
}
},
setVisiblePlusCodes: (state, action: PayloadAction<string[]>) => {
state.visiblePlusCodes = action.payload;
},
},
extraReducers: (builder) => {
builder.addCase(REAL_setVisiblePlusCodes, (state, action) => {
state.visiblePlusCodes = action.payload;
});
},
});

export default mapSlice.reducer;

export const { setVisiblePlusCodes } = mapSlice.actions;
export const { setMapSubscriptionIsUpdating, setVisiblePlusCodes } =
mapSlice.actions;

export const mapSelectors = mapSlice.getSelectors(
(state: RootState) => state[SLICE_NAME],
Expand Down
146 changes: 146 additions & 0 deletions nr-app/src/utils/map.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {
DEFAULT_PLUS_CODE_LENGTH,
NOSTR_EVENT_INDEX_MAXIMUM_PLUS_CODE_LENGTH,
} from "@/constants";
import OpenLocationCode from "open-location-code-typescript";

type PlusCodeShortLength = 2 | 4 | 6 | 8;

const plusCodeCharacters = "23456789CFGHJMPQRVWX" as const;

export function coordinatesToPlusCode({
latitude,
longitude,
length: codeLength = DEFAULT_PLUS_CODE_LENGTH,
}: {
latitude: number;
longitude: number;
length?: PlusCodeShortLength;
}): string {
const plusCode = OpenLocationCode.encode(latitude, longitude, codeLength);
return plusCode;
}

export function plusCodeToArrayPairs(plusCode: string): [string, string][] {
const [beforePlus, afterPlus] = plusCode.split("+");
const [
firstRow,
firstColumn,
secondRow,
secondColumn,
thirdRow,
thirdColumn,
fourthRow,
fourthColumn,
] = beforePlus;
if (afterPlus !== "") {
throw new Error(
"Cannot split plus codes with values after the plus. #GKPQHB",
);
}

const allPairs: [string, string][] = [
[firstRow, firstColumn],
[secondRow, secondColumn],
[thirdRow, thirdColumn],
[fourthRow, fourthColumn],
];

const pairs = allPairs.filter(([row]) => row !== "0");

return pairs;
}

export function allPlusCodesForRegion({
latitude,
latitudeDelta,
longitude,
longitudeDelta,
codeLength = NOSTR_EVENT_INDEX_MAXIMUM_PLUS_CODE_LENGTH,
}: {
latitude: number;
latitudeDelta: number;
longitude: number;
longitudeDelta: number;
codeLength?: PlusCodeShortLength;
}) {
// - Code for bottom left
// - Code for top right
const bottomLeftCoordinates = {
latitude: latitude - latitudeDelta,
longitude: longitude - longitudeDelta,
};
const topRightCoordinates = {
latitude: latitude + latitudeDelta,
longitude: longitude + longitudeDelta,
};

const bottomLeftCode = OpenLocationCode.encode(
bottomLeftCoordinates.latitude,
bottomLeftCoordinates.longitude,
codeLength,
);
const topRightCode = OpenLocationCode.encode(
topRightCoordinates.latitude,
topRightCoordinates.longitude,
codeLength,
);

const bottomLeftPairs = plusCodeToArrayPairs(bottomLeftCode);
const topRightPairs = plusCodeToArrayPairs(topRightCode);

// Find the first digit that changes for row and column
const firstIndexWithDifference = bottomLeftPairs.findIndex(
([bottomRow, leftColumn], index) => {
const [topRow, rightColumn] = topRightPairs[index];
return topRow !== bottomRow || leftColumn !== rightColumn;
},
);

const outputCodeLength = (firstIndexWithDifference + 1) * 2;
console.log(
"#x6E7CR Got output code length",
firstIndexWithDifference,
outputCodeLength,
);

const bottomLeftLastPair = bottomLeftPairs.at(firstIndexWithDifference)!;
const topRightLastPair = topRightPairs.at(firstIndexWithDifference)!;

const [bottomRow, leftColumn] = bottomLeftLastPair;
const [topRow, rightColumn] = topRightLastPair;

const bottomRowIndex = plusCodeCharacters.indexOf(bottomRow);
const topRowIndex = plusCodeCharacters.indexOf(topRow);
const leftColumnIndex = plusCodeCharacters.indexOf(leftColumn);
const rightColumnIndex = plusCodeCharacters.indexOf(rightColumn);

const rows = topRowIndex - bottomRowIndex + 1;
const columns = rightColumnIndex - leftColumnIndex + 1;

// Nested iteration
const parts = Array.from({ length: rows })
.map((empty, rowIndex) => {
return Array.from({ length: columns }).map((empty, columnIndex) => {
const outputRowIndex = bottomRowIndex + rowIndex;
const outputColumnIndex = leftColumnIndex + columnIndex;

const rowCode = plusCodeCharacters[outputRowIndex];
const columnCode = plusCodeCharacters[outputColumnIndex];

return [rowCode, columnCode];
});
})
.flat();

const codePrefixLength = outputCodeLength > 2 ? outputCodeLength - 2 : 0;
const codePrefix = bottomLeftCode.slice(0, codePrefixLength);

const codes = parts.map(([row, column]) => {
const partialCode = `${codePrefix}${row}${column}`;
const codeToPlus = partialCode.padEnd(8, "0");
const code = `${codeToPlus}+`;
return code;
});
return codes;
}

0 comments on commit 984d99a

Please sign in to comment.