solid-pianoroll 0.0.18 → 0.0.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,97 +1,89 @@
1
1
  import styles from "./PianoRoll.module.css";
2
- import { createSignal, createMemo, createEffect, Show, mergeProps, } from "solid-js";
2
+ import { createSignal, Show, mergeProps } from "solid-js";
3
3
  import { PianoRollContextProvider, splitContextProps } from "./PianoRollContext";
4
4
  import PianoRollKeys from "./PianoRollKeys";
5
5
  import PianoRollNotes from "./PianoRollNotes";
6
- import ScrollContainer from "./viewport/ScrollContainer";
6
+ import ScrollZoomContainer from "./viewport/ScrollZoomContainer";
7
7
  import PianoRollGrid from "./PianoRollGrid";
8
8
  import { ScrollZoomViewPort as ScrollZoomViewPort } from "./viewport/ScrollZoomViewPort";
9
9
  import useBoundingClientRect from "./useBoundingClientRect";
10
- import { clamp } from "./viewport/createViewPortDimension";
11
- import VerticalZoomControl from "./viewport/VerticalZoomControl";
12
- import HorizontalZoomControl from "./viewport/HorizontalZoomControl";
10
+ import ZoomSliderControl from "./viewport/ZoomSliderControl";
13
11
  import PianoRollTrackList from "./PianoRollTrackList";
14
12
  const PianoRoll = (allProps) => {
15
13
  const propsWithDefaults = mergeProps({ showAllTracks: false }, allProps);
16
14
  const [context, divProps] = splitContextProps(propsWithDefaults);
17
- const [scrollerRef, setScrollerRef] = createSignal();
18
- const [trackScrollerRef, setTrackScrollerRef] = createSignal();
19
- const clientRect = useBoundingClientRect(scrollerRef);
20
- const trackClientRef = useBoundingClientRect(trackScrollerRef);
15
+ const [notesScrollerRef, setNotesScrollerRef] = createSignal();
16
+ const [tracksScrollerRef, setTracksScrollerRef] = createSignal();
17
+ const notesScrollerClientRect = useBoundingClientRect(notesScrollerRef);
18
+ const tracksScrollerClientRect = useBoundingClientRect(tracksScrollerRef);
21
19
  const zoomFactor = 500;
22
- const minZoom = createMemo(() => 1 / (zoomFactor / clientRect().width));
23
- const maxZoom = createMemo(() => 500 * (zoomFactor / clientRect().width));
24
- const minVerticalZoom = createMemo(() => 1 / (zoomFactor / clientRect().height));
25
- const maxVerticalZoom = createMemo(() => 10 * (zoomFactor / clientRect().height));
26
- const minVerticalTracksZoom = createMemo(() => 0.8 / (zoomFactor / trackClientRef().height));
27
- const maxVerticalTracksZoom = createMemo(() => 3 * (zoomFactor / trackClientRef().height));
28
- createEffect((isInitial) => {
29
- if (isInitial)
30
- return false;
31
- if (context.mode === "tracks") {
32
- context.onVerticalPositionChange?.(0);
33
- }
34
- }, true);
35
20
  return (<PianoRollContextProvider value={context}>
36
21
  <div {...divProps} class={styles.PianoRoll}>
37
22
  <ScrollZoomViewPort dimensions={{
38
23
  horizontal: () => ({
39
- pixelOffset: clientRect().left,
40
- pixelSize: clientRect().width,
24
+ pixelOffset: notesScrollerClientRect().left,
25
+ pixelSize: notesScrollerClientRect().width,
41
26
  position: context.position,
42
27
  range: context.duration,
43
- zoom: context.zoom * (zoomFactor / clientRect().width),
28
+ zoom: context.zoom * (zoomFactor / notesScrollerClientRect().width),
44
29
  onPositionChange: context.onPositionChange,
45
- onZoomChange: (zoom) => context.onZoomChange?.(clamp(zoom / (zoomFactor / clientRect().width), minZoom(), maxZoom())),
30
+ onZoomChange: (zoom) => context.onZoomChange?.(zoom / (zoomFactor / notesScrollerClientRect().width)),
31
+ minZoom: 1,
32
+ maxZoom: 500,
46
33
  }),
47
34
  vertical: () => ({
48
- pixelOffset: clientRect().top,
49
- pixelSize: clientRect().height,
35
+ pixelOffset: notesScrollerClientRect().top,
36
+ pixelSize: notesScrollerClientRect().height,
50
37
  position: context.verticalPosition,
51
38
  range: 128,
52
- zoom: context.verticalZoom * (zoomFactor / clientRect().height),
39
+ zoom: context.verticalZoom * (zoomFactor / notesScrollerClientRect().height),
53
40
  onPositionChange: context.onVerticalPositionChange,
54
- onZoomChange: (verticalZoom) => context.onVerticalZoomChange?.(clamp(verticalZoom / (zoomFactor / clientRect().height), minVerticalZoom(), maxVerticalZoom())),
41
+ onZoomChange: (verticalZoom) => context.onVerticalZoomChange?.(verticalZoom / (zoomFactor / notesScrollerClientRect().height)),
42
+ minZoom: 1,
43
+ maxZoom: 10,
55
44
  }),
56
45
  horizontalTracks: () => ({
57
- pixelOffset: clientRect().left,
58
- pixelSize: clientRect().width,
59
- position: 0,
60
- range: 1,
61
- zoom: 1,
46
+ pixelOffset: 0,
47
+ pixelSize: notesScrollerClientRect().width,
62
48
  }),
63
49
  verticalTracks: () => ({
64
- pixelOffset: trackClientRef().top,
65
- pixelSize: trackClientRef().height,
50
+ pixelOffset: tracksScrollerClientRect().top,
51
+ pixelSize: tracksScrollerClientRect().height,
66
52
  position: context.verticalTrackPosition,
67
53
  range: context.tracks.length,
68
- zoom: context.verticalTrackZoom * (zoomFactor / trackClientRef().height),
54
+ zoom: context.verticalTrackZoom * (zoomFactor / tracksScrollerClientRect().height),
69
55
  onPositionChange: context.onVerticalTrackPositionChange,
70
- onZoomChange: (verticalTrackZoom) => context.onVerticalTrackZoomChange?.(clamp(verticalTrackZoom / (zoomFactor / trackClientRef().height), minVerticalTracksZoom(), maxVerticalTracksZoom())),
56
+ onZoomChange: (verticalTrackZoom) => context.onVerticalTrackZoomChange?.(verticalTrackZoom / (zoomFactor / tracksScrollerClientRect().height)),
57
+ minZoom: 0.8,
58
+ maxZoom: 3,
71
59
  }),
60
+ horizontalKeys: () => ({ pixelSize: 60 }),
72
61
  }}>
73
62
  <div class={styles.PianoRollContainer}>
74
- <VerticalZoomControl min={minVerticalTracksZoom()} max={maxVerticalTracksZoom()} dimensionName="verticalTracks"/>
75
- <div style={{ display: "flex", width: "20%" }}>
63
+ <ZoomSliderControl orientation="vertical" dimensionName="verticalTracks"/>
64
+ <div style={{ display: "flex", width: "30%", "max-width": "250px" }}>
76
65
  <Show when={context.showTrackList}>
77
- <ScrollContainer ref={setTrackScrollerRef} horizontalDimensionName="horizontalTracks" verticalDimensionName="verticalTracks" showScrollbar={context.mode === "keys"}>
66
+ <ScrollZoomContainer ref={setTracksScrollerRef} horizontalDimensionName="horizontalTracks" verticalDimensionName="verticalTracks" showScrollbar={context.mode === "keys"}>
78
67
  <PianoRollTrackList />
79
- </ScrollContainer>
68
+ </ScrollZoomContainer>
80
69
  </Show>
81
70
  <Show when={context.mode === "keys"}>
82
71
  <PianoRollKeys />
83
72
  </Show>
84
73
  </div>
85
74
 
86
- <ScrollContainer ref={setScrollerRef} verticalDimensionName={context.mode === "keys" ? "vertical" : "verticalTracks"}>
75
+ <ScrollZoomContainer ref={setNotesScrollerRef} verticalDimensionName={context.mode === "keys" ? "vertical" : "verticalTracks"}>
87
76
  {allProps.children}
88
77
  <PianoRollGrid />
89
78
  <PianoRollNotes />
90
- </ScrollContainer>
79
+ </ScrollZoomContainer>
91
80
 
92
- <VerticalZoomControl min={minVerticalZoom()} max={maxVerticalZoom()} disabled={context.mode !== "keys"}/>
81
+ <ZoomSliderControl orientation="vertical" disabled={context.mode !== "keys"}/>
93
82
  </div>
94
- <HorizontalZoomControl min={minZoom()} max={maxZoom()}/>
83
+ <ZoomSliderControl orientation="horizontal" style={{
84
+ "margin-left": `${tracksScrollerClientRect().width + 24}px`,
85
+ "margin-right": "24px",
86
+ }}/>
95
87
  </ScrollZoomViewPort>
96
88
  </div>
97
89
  </PianoRollContextProvider>);
@@ -2,9 +2,10 @@ import styles from "./PianoRollKeys.module.css";
2
2
  import { createEffect, createMemo, createSignal, Index, Show } from "solid-js";
3
3
  import { useViewPortDimension } from "./viewport/ScrollZoomViewPort";
4
4
  import { usePianoRollContext } from "./PianoRollContext";
5
- import ScrollContainer from "./viewport/ScrollContainer";
5
+ import ScrollZoomContainer from "./viewport/ScrollZoomContainer";
6
6
  const PianoRollKeys = () => {
7
- const viewPort = createMemo(() => useViewPortDimension("vertical"));
7
+ const verticalViewPort = createMemo(() => useViewPortDimension("vertical"));
8
+ const horizontalViewPort = createMemo(() => useViewPortDimension("horizontalKeys"));
8
9
  const [isMouseDown, setIsMouseDown] = createSignal(false);
9
10
  const context = usePianoRollContext();
10
11
  const handleMouseUp = () => {
@@ -18,9 +19,10 @@ const PianoRollKeys = () => {
18
19
  window.removeEventListener("mouseup", handleMouseUp);
19
20
  }
20
21
  });
21
- return (<ScrollContainer classList={{ [styles.PianoRollKeys]: true }} showScrollbar={false}>
22
- <Index each={keys}>
23
- {(key) => {
22
+ return (<div class={styles.PianoRollKeys} style={{ width: `${horizontalViewPort().pixelSize}px` }}>
23
+ <ScrollZoomContainer horizontalDimensionName="horizontalKeys" showScrollbar={false}>
24
+ <Index each={keys}>
25
+ {(key) => {
24
26
  const isDown = createMemo(() => context.pressedKeys.includes(key().number));
25
27
  const handleKeyDown = () => {
26
28
  context.onPressedKeysChange?.([...context.pressedKeys, key().number]);
@@ -28,11 +30,11 @@ const PianoRollKeys = () => {
28
30
  const handleKeyUp = () => {
29
31
  context.onPressedKeysChange?.([...context.pressedKeys].filter((number) => number !== key().number));
30
32
  };
31
- const virtualDimensions = createMemo(() => viewPort().calculatePixelDimensions(127 - key().number, 1));
33
+ const virtualDimensions = createMemo(() => verticalViewPort().calculatePixelDimensions(127 - key().number, 1));
32
34
  const previousIsBlack = blackKeys.includes((key().number - 1) % 12);
33
35
  const nextIsBlack = blackKeys.includes((key().number + 1) % 12);
34
36
  return (<Show when={virtualDimensions().size > 0}>
35
- <div classList={{
37
+ <div classList={{
36
38
  [styles["Key"]]: true,
37
39
  [styles["black"]]: key().isBlack,
38
40
  [styles["white"]]: !key().isBlack,
@@ -64,17 +66,18 @@ const PianoRollKeys = () => {
64
66
  .filter((item) => !!item)
65
67
  .join(", "),
66
68
  }}>
67
- <Show when={key().isBlack && false}>
68
- <div class={styles["black-separator"]} style={{
69
+ <Show when={key().isBlack && false}>
70
+ <div class={styles["black-separator"]} style={{
69
71
  top: `${virtualDimensions().offset}px`,
70
72
  height: `${virtualDimensions().size / 2 - 0.25}px`,
71
73
  }}></div>
72
- </Show>
73
- </div>
74
- </Show>);
74
+ </Show>
75
+ </div>
76
+ </Show>);
75
77
  }}
76
- </Index>
77
- </ScrollContainer>);
78
+ </Index>
79
+ </ScrollZoomContainer>
80
+ </div>);
78
81
  };
79
82
  export const blackKeys = [1, 3, 6, 8, 10];
80
83
  export const keyNames = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
@@ -44,7 +44,7 @@ const PianoRollNotes = (props) => {
44
44
  const getClasses = (noteDragMode) => {
45
45
  return noteDragMode ? [styles.Note, styles[noteDragMode]] : [styles.Note];
46
46
  };
47
- return (<div class={styles.PianoRollNotes} ref={props.ref} onMouseDown={(event) => {
47
+ return (<div classList={{ [styles.PianoRollNotes]: true }} ref={props.ref} onMouseDown={(event) => {
48
48
  batch(() => {
49
49
  setIsMouseDown(true);
50
50
  const index = insertOrUpdateNote(event);
@@ -1,7 +1,7 @@
1
1
  import { createEffect, createMemo, mergeProps, splitProps } from "solid-js";
2
2
  import { useViewPortDimension } from "./ScrollZoomViewPort";
3
- import styles from "./ScrollContainer.module.css";
4
- const ScrollContainer = (props) => {
3
+ import styles from "./ScrollZoomContainer.module.css";
4
+ const ScrollZoomContainer = (props) => {
5
5
  let scrollContentRef;
6
6
  const [ownProps, divProps] = splitProps(props, [
7
7
  "ref",
@@ -74,13 +74,13 @@ const ScrollContainer = (props) => {
74
74
  top: scrollTop,
75
75
  });
76
76
  });
77
- return (<div ref={props.ref} style={{
77
+ return (<div ref={props.ref} onScroll={handleScroll} onWheel={handleWheel} {...divProps} style={{
78
78
  overflow: propsWithDefaults.showScrollbar ? "scroll" : "hidden",
79
79
  ...(typeof divProps.style === "object" && divProps.style),
80
80
  }} classList={{
81
- [styles.ScrollContainer]: true,
81
+ [styles.ScrollZoomContainer]: true,
82
82
  ...divProps.classList,
83
- }} onScroll={handleScroll} onWheel={handleWheel} {...divProps}>
83
+ }}>
84
84
  <div ref={scrollContentRef}>
85
85
  <div style={{
86
86
  top: 0,
@@ -101,4 +101,4 @@ const ScrollContainer = (props) => {
101
101
  </div>
102
102
  </div>);
103
103
  };
104
- export default ScrollContainer;
104
+ export default ScrollZoomContainer;
@@ -1,7 +1,19 @@
1
1
  import { createContext, useContext } from "solid-js";
2
2
  import createViewPortDimension from "./createViewPortDimension";
3
+ const defaultViewPortProps = {
4
+ pixelOffset: 0,
5
+ position: 0,
6
+ range: 1,
7
+ zoom: 1,
8
+ minZoom: 1,
9
+ maxZoom: Infinity,
10
+ };
3
11
  export const ScrollZoomViewPort = (props) => {
4
- const viewPorts = Object.entries(props.dimensions).map(([name, viewPortProps]) => createViewPortDimension(() => ({ name: name, ...viewPortProps() })));
12
+ const viewPorts = Object.entries(props.dimensions).map(([name, viewPortProps]) => createViewPortDimension(() => ({
13
+ name: name,
14
+ ...defaultViewPortProps,
15
+ ...viewPortProps(),
16
+ })));
5
17
  const parentViewPorts = useContext(ScrollZoomViewPortContext);
6
18
  return (<ScrollZoomViewPortContext.Provider value={[...parentViewPorts, ...viewPorts]}>
7
19
  {props.children}
@@ -0,0 +1,26 @@
1
+ import { createMemo, mergeProps } from "solid-js";
2
+ import { useViewPortDimension } from "./ScrollZoomViewPort";
3
+ const ZoomSliderControl = (props) => {
4
+ const propsWithDefaults = mergeProps({ orientation: "horizontal" }, props);
5
+ const dimension = createMemo(() => useViewPortDimension(props.dimensionName ?? propsWithDefaults.orientation));
6
+ return (<input min={dimension().minZoom} max={dimension().maxZoom} step={0.01} {...props} value={dimension().zoom} onInput={(event) => dimension().onZoomChange?.(event.currentTarget.valueAsNumber)} type="range" {...{ orient: propsWithDefaults.orientation }} style={propsWithDefaults.orientation === "vertical"
7
+ ? {
8
+ margin: 0,
9
+ "margin-left": "4px",
10
+ "margin-right": "4px",
11
+ width: "16px",
12
+ transform: "rotate(180deg)",
13
+ ...{
14
+ "writing-mode": "bt-lr" /* IE */,
15
+ "-webkit-appearance": "slider-vertical" /* WebKit */,
16
+ },
17
+ ...(typeof props.style === "object" && props.style),
18
+ }
19
+ : {
20
+ margin: 0,
21
+ "margin-top": "4px",
22
+ "margin-bottom": "4px",
23
+ ...(typeof props.style === "object" && props.style),
24
+ }}/>);
25
+ };
26
+ export default ZoomSliderControl;
@@ -1,16 +1,23 @@
1
1
  import { createEffect } from "solid-js";
2
2
  import { createStore } from "solid-js/store";
3
3
  export default function createViewPortDimension(getState) {
4
- const getStateWithFunctions = () => ({
5
- ...getState(),
6
- calculatePixelOffset,
7
- calculatePixelValue,
8
- calculatePosition,
9
- calculatePixelDimensions,
10
- calculateVisibleRange,
11
- calculateMaxPosition,
12
- isVisible,
13
- });
4
+ const getStateWithFunctions = () => {
5
+ const state = getState();
6
+ const onZoomChange = (zoom) => state.onZoomChange?.(clamp(zoom, state.minZoom, state.maxZoom));
7
+ const onPositionChange = (position) => state.onPositionChange?.(position);
8
+ return {
9
+ ...state,
10
+ onZoomChange,
11
+ onPositionChange,
12
+ calculatePixelOffset,
13
+ calculatePixelValue,
14
+ calculatePosition,
15
+ calculatePixelDimensions,
16
+ calculateVisibleRange,
17
+ calculateMaxPosition,
18
+ isVisible,
19
+ };
20
+ };
14
21
  const [state, setState] = createStore(getStateWithFunctions());
15
22
  createEffect(() => setState(getStateWithFunctions()));
16
23
  function calculatePixelValue(position = state.position) {
@@ -1,8 +1,8 @@
1
1
  import { JSX, ParentProps, Ref } from "solid-js";
2
- declare const ScrollContainer: (props: ParentProps<{
2
+ declare const ScrollZoomContainer: (props: ParentProps<{
3
3
  ref?: Ref<HTMLDivElement>;
4
4
  verticalDimensionName?: string;
5
5
  horizontalDimensionName?: string;
6
6
  showScrollbar?: boolean;
7
7
  } & JSX.IntrinsicElements["div"]>) => JSX.Element;
8
- export default ScrollContainer;
8
+ export default ScrollZoomContainer;
@@ -1,9 +1,19 @@
1
1
  import { ParentProps } from "solid-js";
2
2
  import { ViewPortDimensionName, ViewPortDimensionState } from "./createViewPortDimension";
3
+ declare const defaultViewPortProps: {
4
+ pixelOffset: number;
5
+ position: number;
6
+ range: number;
7
+ zoom: number;
8
+ minZoom: number;
9
+ maxZoom: number;
10
+ };
3
11
  export declare const ScrollZoomViewPort: (props: ParentProps<{
4
- dimensions: Record<ViewPortDimensionName, () => Omit<ViewPortDimensionState, "name">>;
12
+ dimensions: Record<ViewPortDimensionName, () => Omit<ViewPortDimensionState, "name" | keyof typeof defaultViewPortProps> & Partial<Pick<ViewPortDimensionState, keyof typeof defaultViewPortProps>>>;
5
13
  }>) => import("solid-js").JSX.Element;
6
14
  export declare const useViewPortDimension: (name: ViewPortDimensionName) => {
15
+ onZoomChange: (zoom: number) => void;
16
+ onPositionChange: (position: number) => void;
7
17
  calculatePixelOffset: (position: number) => number;
8
18
  calculatePixelValue: (position?: number) => number;
9
19
  calculatePosition: (offset: number) => number;
@@ -22,7 +32,8 @@ export declare const useViewPortDimension: (name: ViewPortDimensionName) => {
22
32
  pixelOffset: number;
23
33
  pixelSize: number;
24
34
  name: string;
25
- onZoomChange?: (zoom: number) => void;
26
- onPositionChange?: (zoom: number) => void;
27
35
  zoom: number;
36
+ minZoom: number;
37
+ maxZoom: number;
28
38
  };
39
+ export {};
@@ -1,5 +1,6 @@
1
1
  import { JSX } from "solid-js/jsx-runtime";
2
- declare const VerticalZoomControl: (props: {
2
+ declare const ZoomSliderControl: (props: {
3
3
  dimensionName?: string;
4
+ orientation?: "horizontal" | "vertical";
4
5
  } & JSX.IntrinsicElements["input"]) => JSX.Element;
5
- export default VerticalZoomControl;
6
+ export default ZoomSliderControl;
@@ -9,8 +9,12 @@ export type ViewPortDimensionState = {
9
9
  onZoomChange?: (zoom: number) => void;
10
10
  onPositionChange?: (zoom: number) => void;
11
11
  zoom: number;
12
+ minZoom: number;
13
+ maxZoom: number;
12
14
  };
13
15
  export default function createViewPortDimension(getState: () => ViewPortDimensionState): {
16
+ onZoomChange: (zoom: number) => void;
17
+ onPositionChange: (position: number) => void;
14
18
  calculatePixelOffset: (position: number) => number;
15
19
  calculatePixelValue: (position?: number) => number;
16
20
  calculatePosition: (offset: number) => number;
@@ -29,8 +33,8 @@ export default function createViewPortDimension(getState: () => ViewPortDimensio
29
33
  pixelOffset: number;
30
34
  pixelSize: number;
31
35
  name: string;
32
- onZoomChange?: (zoom: number) => void;
33
- onPositionChange?: (zoom: number) => void;
34
36
  zoom: number;
37
+ minZoom: number;
38
+ maxZoom: number;
35
39
  };
36
40
  export declare const clamp: (value: number, min: number, max: number) => number;
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.18",
2
+ "version": "0.0.19",
3
3
  "name": "solid-pianoroll",
4
4
  "description": "Pianoroll UI Control for Solid JS apps",
5
5
  "license": "MIT",
@@ -1,11 +0,0 @@
1
- import { createMemo } from "solid-js";
2
- import { useViewPortDimension } from "./ScrollZoomViewPort";
3
- const HorizontalZoomControl = (props) => {
4
- const dimension = createMemo(() => useViewPortDimension(props.dimensionName ?? "horizontal"));
5
- return (<input max="500" min="1" step={0.01} {...props} value={dimension().zoom} onInput={(event) => dimension().onZoomChange?.(event.currentTarget.valueAsNumber)} type="range" style={{
6
- "margin-left": "50px",
7
- "margin-right": "16px",
8
- ...(typeof props.style === "object" && props.style),
9
- }}/>);
10
- };
11
- export default HorizontalZoomControl;
@@ -1,14 +0,0 @@
1
- import { createMemo } from "solid-js";
2
- import { useViewPortDimension } from "./ScrollZoomViewPort";
3
- const VerticalZoomControl = (props) => {
4
- const dimension = createMemo(() => useViewPortDimension(props.dimensionName ?? "vertical"));
5
- return (<input min="1" max="11" step={0.01} {...props} value={dimension().zoom} onInput={(event) => dimension().onZoomChange?.(event.currentTarget.valueAsNumber)} type="range" {...{ orient: "vertical" }} style={{
6
- width: "16px",
7
- transform: "rotate(180deg)",
8
- ...{
9
- "writing-mode": "bt-lr" /* IE */,
10
- "-webkit-appearance": "slider-vertical" /* WebKit */,
11
- },
12
- }}/>);
13
- };
14
- export default VerticalZoomControl;
@@ -1,5 +0,0 @@
1
- import { JSX } from "solid-js/jsx-runtime";
2
- declare const HorizontalZoomControl: (props: {
3
- dimensionName?: string;
4
- } & JSX.IntrinsicElements["input"]) => JSX.Element;
5
- export default HorizontalZoomControl;