Skip to content

Commit

Permalink
add group item order labels
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielburnworth committed Jun 19, 2020
1 parent 33bed28 commit fdc6eea
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 11 deletions.
6 changes: 6 additions & 0 deletions frontend/farm_designer/map/__tests__/zoom_test.ts
Expand Up @@ -51,4 +51,10 @@ describe("zoom utilities", () => {
ZoomUtils.calcZoomLevel(ZoomUtils.getZoomLevelIndex(() => undefined));
expect(defaultZoom).toEqual(1);
});

it("zoomCompensation()", () => {
expect(ZoomUtils.zoomCompensation(0.1)).toEqual(2);
expect(ZoomUtils.zoomCompensation(1, 2)).toEqual(2);
expect(ZoomUtils.zoomCompensation(1.8)).toEqual(0.7);
});
});
1 change: 1 addition & 0 deletions frontend/farm_designer/map/garden_map.tsx
Expand Up @@ -510,6 +510,7 @@ export class GardenMap extends
GroupOrder = () => <GroupOrder
group={this.group}
groupPoints={this.pointsSelectedByGroup}
zoomLvl={this.props.zoomLvl}
mapTransformProps={this.mapTransformProps} />
NNPath = () => <NNPath pathPoints={this.props.allPoints}
mapTransformProps={this.mapTransformProps} />
Expand Down
30 changes: 26 additions & 4 deletions frontend/farm_designer/map/zoom.ts
@@ -1,5 +1,5 @@
import { NumericSetting } from "../../session_keys";
import { findIndex, isNumber, clamp } from "lodash";
import { findIndex, isNumber, clamp, round } from "lodash";
import {
setWebAppConfigValue, GetWebAppConfigValue,
} from "../../config_storage/actions";
Expand Down Expand Up @@ -31,21 +31,43 @@ export function atMinZoom(getConfigValue: GetWebAppConfigValue): boolean {
return getZoomLevelIndex(getConfigValue) <= 0;
}

/* Load the index of a saved zoom level. */
/** Load the index of a saved zoom level. */
export function getZoomLevelIndex(getConfigValue: GetWebAppConfigValue): number {
const savedValue = getConfigValue(NumericSetting.zoom_level);
if (!isNumber(savedValue)) { return zoomLevel1Index; }
const zoomLevelIndex = savedValue + zoomLevel1Index - 1;
return clampZoom(zoomLevelIndex);
}

/* Save a zoom level index. */
/** Save a zoom level index. */
export function saveZoomLevelIndex(dispatch: Function, index: number) {
const payload = index - zoomLevel1Index + 1;
dispatch(setWebAppConfigValue(NumericSetting.zoom_level, payload));
}

/* Calculate map zoom level from a zoom level index. */
/** Calculate map zoom level from a zoom level index. */
export function calcZoomLevel(index: number): number {
return zoomLevels[clampZoom(index)];
}

/**
* Calculate a size for important labels and annotations to make them
* less affected by zoom (1/5x to 1.25x instead of 1/10x to ~2x apparent size).
*
* zoom level: 0.1 0.15 0.2 0.25 0.33 0.41 0.5 0.6 0.75 1 1.25 1.5 1.8
* 1/x zoom level: 10 7 5 4 3 2.4 3 1.7 1.3 1 0.8 0.7 0.6
*
* reduction factor: 2 1.94 1.9 1.8 1.74 1.66 1.6 1.4 1.3 1 0.9 0.8 0.7
* 1/x compensated: 5 3.5 2.6 2.2 1.75 1.47 1.3 1.2 1 1 0.9 0.8 0.8
*/
export const zoomCompensation = (zoom: number, scale = 1) => {
/** Desired zoom reduction factor for farthest out zoom level. */
const RF_ZOOM_IN_MAX = 0.7;
/** Desired zoom reduction factor for farthest in (closest) zoom level. */
const RF_ZOOM_OUT_MIN = 2;
const zoomLimit = zoom > 1 ? Math.max(...zoomLevels) : Math.min(...zoomLevels);
const reductionFactor = zoom > 1 ? RF_ZOOM_IN_MAX : RF_ZOOM_OUT_MIN;
const multiplier = (reductionFactor - 1) / (zoomLimit - 1);
const base = 1 - multiplier;
return round(scale * (base + multiplier * zoom), 2);
};
Expand Up @@ -30,6 +30,7 @@ describe("<GroupOrder />", () => {
group.body.point_ids = [1, 2, 3];
return {
mapTransformProps: fakeMapTransformProps(),
zoomLvl: 1,
groupPoints: [plant1, plant2, plant3],
group,
};
Expand All @@ -42,6 +43,7 @@ describe("<GroupOrder />", () => {

it("renders optimized group order", () => {
const p = fakeProps();
p.zoomLvl = 1.5;
mockState.resources.consumers.farm_designer.tryGroupSortType = "nn";
const wrapper = svgMount(<GroupOrder {...p} />);
expect(wrapper.find("line").length).toEqual(3);
Expand Down
51 changes: 44 additions & 7 deletions frontend/farm_designer/point_groups/group_order_visual.tsx
Expand Up @@ -7,10 +7,12 @@ import { Color } from "../../ui";
import { transformXY } from "../map/util";
import { nn } from "./paths";
import { TaggedPoint, TaggedPointGroup } from "farmbot";
import { zoomCompensation } from "../map/zoom";

export interface GroupOrderProps {
group: TaggedPointGroup | undefined;
groupPoints: TaggedPoint[];
zoomLvl: number;
mapTransformProps: MapTransformProps;
}

Expand All @@ -33,22 +35,57 @@ export interface PointsPathLineProps {
color?: Color;
dash?: number;
strokeWidth?: number;
zoomLvl: number;
}

export const PointsPathLine = (props: PointsPathLineProps) =>
<g id="group-order" style={{ pointerEvents: "none" }}
<g id="group-order-line"
stroke={props.color || Color.mediumGray}
strokeWidth={props.strokeWidth || 3}
strokeDasharray={props.dash || 12}>
strokeWidth={props.strokeWidth || zoomCompensation(props.zoomLvl, 3)}
strokeDasharray={props.dash || zoomCompensation(props.zoomLvl, 12)}>
{props.orderedPoints.map((p, i) => {
const prev = i > 0 ? props.orderedPoints[i - 1] : p;
const one = transformXY(prev.x, prev.y, props.mapTransformProps);
const two = transformXY(p.x, p.y, props.mapTransformProps);
return <line key={i} x1={one.qx} y1={one.qy} x2={two.qx} y2={two.qy} />;
return <g id="group-order-element" key={i}>
<line x1={one.qx} y1={one.qy} x2={two.qx} y2={two.qy} />
</g>;
})}
</g>;

export interface PointsPathLabelsProps {
orderedPoints: { x: number, y: number }[];
mapTransformProps: MapTransformProps;
zoomLvl: number;
}

export const PointsPathLabels = (props: PointsPathLabelsProps) =>
<g id="group-order-labels">
{props.orderedPoints.map((p, i) => {
const position = transformXY(p.x, p.y, props.mapTransformProps);
const offset = 15;
return <g id="group-order-label-element" key={i} stroke={"none"}>
<circle cx={position.qx + offset} cy={position.qy - offset}
r={zoomCompensation(props.zoomLvl, 9.5)}
fill={Color.white} fillOpacity={0.65} />
<text x={position.qx + offset} y={position.qy - offset}
fontSize={zoomCompensation(props.zoomLvl, 1.45) + "rem"}
fill={Color.darkGray} fillOpacity={0.75} fontWeight={"bold"}
textAnchor={"middle"} alignmentBaseline={"middle"} >
{i + 1}
</text>
</g>;
})}
</g>;

export const GroupOrder = (props: GroupOrderProps) =>
<PointsPathLine
orderedPoints={sortedPointCoordinates(props.group, props.groupPoints)}
mapTransformProps={props.mapTransformProps} />;
<g id="group-order" style={{ pointerEvents: "none" }}>
<PointsPathLine
orderedPoints={sortedPointCoordinates(props.group, props.groupPoints)}
zoomLvl={props.zoomLvl}
mapTransformProps={props.mapTransformProps} />
<PointsPathLabels
orderedPoints={sortedPointCoordinates(props.group, props.groupPoints)}
zoomLvl={props.zoomLvl}
mapTransformProps={props.mapTransformProps} />
</g>;
1 change: 1 addition & 0 deletions frontend/farm_designer/point_groups/paths.tsx
Expand Up @@ -136,5 +136,6 @@ export const NNPath = (props: NNPathProps) =>
strokeWidth={2}
dash={1}
orderedPoints={nn(props.pathPoints).map(xy)}
zoomLvl={1}
mapTransformProps={props.mapTransformProps} />
: <g />;

0 comments on commit fdc6eea

Please sign in to comment.