@playkit-js/manual-hotspots 3.3.1-canary.0-7e9f2da → 3.3.1-canary.0-2996ab6
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.
- package/CHANGELOG.md +1 -1
- package/dist/playkit-manual-hotspots.js +1 -1
- package/package.json +2 -3
- package/src/components/Hotspot.tsx +0 -267
- package/src/components/HotspotWrapper.tsx +0 -115
- package/src/events/events.ts +0 -4
- package/src/global.d.ts +0 -4
- package/src/hotspots-plugin.tsx +0 -180
- package/src/index.ts +0 -15
- package/src/utils/analyticsEvents.ts +0 -3
- package/src/utils/hotspot-config.ts +0 -54
- package/src/utils/hotspot-loader.ts +0 -72
- package/src/utils/hotspot-normalizer.ts +0 -104
- package/src/utils/hotspot-presets.ts +0 -51
- package/src/utils/hotspot-timeline-simple.ts +0 -78
- package/src/utils/hotspot.ts +0 -88
- package/src/utils/scale-video.ts +0 -57
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import {RawLayoutHotspot} from './hotspot';
|
|
2
|
-
import {HotspotConfigFull, HotspotInputConfig} from './hotspot-config';
|
|
3
|
-
import {normalizeHotspotConfig} from './hotspot-normalizer';
|
|
4
|
-
|
|
5
|
-
export class HotspotLoader {
|
|
6
|
-
constructor(private logger: KalturaPlayerTypes.Logger) {}
|
|
7
|
-
|
|
8
|
-
load(configHotspots: HotspotInputConfig[] | undefined): RawLayoutHotspot[] | null {
|
|
9
|
-
if (!Array.isArray(configHotspots)) {
|
|
10
|
-
this.logger.warn('Hotspots config should be an array');
|
|
11
|
-
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
return configHotspots
|
|
16
|
-
.map(hotspot => normalizeHotspotConfig(hotspot))
|
|
17
|
-
.filter((hotspot, index) => this._validateHotspot(hotspot, index))
|
|
18
|
-
.map(hotspot => this._transformConfigToRawHotspot(hotspot));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
private _validateHotspot(hotspot: HotspotConfigFull, index: number): boolean {
|
|
22
|
-
if (!hotspot.id) {
|
|
23
|
-
this.logger.warn(`Hotspot at index ${index} is missing required 'id' field, skipping`);
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (typeof hotspot.startTime !== 'number') {
|
|
28
|
-
this.logger.warn(`Hotspot '${hotspot.id}' is missing required 'startTime' field, skipping`);
|
|
29
|
-
return false;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!hotspot.layout) {
|
|
33
|
-
this.logger.warn(`Hotspot '${hotspot.id}' is missing required 'layout' field, skipping`);
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const requiredLayoutFields = ['relativeX', 'relativeY', 'relativeWidth', 'relativeHeight', 'stageWidth', 'stageHeight'];
|
|
38
|
-
|
|
39
|
-
for (const field of requiredLayoutFields) {
|
|
40
|
-
if (typeof hotspot.layout[field as keyof typeof hotspot.layout] !== 'number') {
|
|
41
|
-
this.logger.warn(`Hotspot '${hotspot.id}' has invalid layout.${field}, skipping`);
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (!hotspot.styles) {
|
|
47
|
-
this.logger.warn(`Hotspot '${hotspot.id}' is missing required 'styles' field, skipping`);
|
|
48
|
-
return false;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private _transformConfigToRawHotspot(config: HotspotConfigFull): RawLayoutHotspot {
|
|
55
|
-
return {
|
|
56
|
-
id: config.id,
|
|
57
|
-
startTime: config.startTime,
|
|
58
|
-
endTime: config.endTime,
|
|
59
|
-
label: config.label,
|
|
60
|
-
styles: config.styles as {[key: string]: string},
|
|
61
|
-
onClick: config.onClick as RawLayoutHotspot['onClick'],
|
|
62
|
-
rawLayout: {
|
|
63
|
-
relativeX: config.layout.relativeX,
|
|
64
|
-
relativeY: config.layout.relativeY,
|
|
65
|
-
relativeWidth: config.layout.relativeWidth,
|
|
66
|
-
relativeHeight: config.layout.relativeHeight,
|
|
67
|
-
stageWidth: config.layout.stageWidth,
|
|
68
|
-
stageHeight: config.layout.stageHeight
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import {POSITION_PRESETS, SIZE_PRESETS, DEFAULT_STAGE, DEFAULT_STYLES, POSITION_ANCHORS, PositionPreset, SizePreset} from './hotspot-presets';
|
|
2
|
-
import {HotspotConfigFull, HotspotInputConfig} from './hotspot-config';
|
|
3
|
-
|
|
4
|
-
let idCounter = 0;
|
|
5
|
-
function generateHotspotId(): string {
|
|
6
|
-
return `hotspot-${Date.now()}-${idCounter++}`;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function isPositionPreset(value: unknown): value is PositionPreset {
|
|
10
|
-
return typeof value === 'string' && value in POSITION_PRESETS;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function isSizePreset(value: unknown): value is SizePreset {
|
|
14
|
-
return typeof value === 'string' && value in SIZE_PRESETS;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function calculateAnchoredPosition(
|
|
18
|
-
baseX: number,
|
|
19
|
-
baseY: number,
|
|
20
|
-
width: number,
|
|
21
|
-
height: number,
|
|
22
|
-
position: PositionPreset
|
|
23
|
-
): {relativeX: number; relativeY: number} {
|
|
24
|
-
if (!position || !isPositionPreset(position)) {
|
|
25
|
-
return {relativeX: baseX, relativeY: baseY};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const anchor = POSITION_ANCHORS[position];
|
|
29
|
-
return {
|
|
30
|
-
relativeX: Math.max(0, Math.min(1 - width, baseX - width * anchor.anchorX)),
|
|
31
|
-
relativeY: Math.max(0, Math.min(1 - height, baseY - height * anchor.anchorY))
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export function normalizeHotspotConfig(simplified: HotspotInputConfig): HotspotConfigFull {
|
|
36
|
-
const layout = simplified.layout || {};
|
|
37
|
-
|
|
38
|
-
const sizePreset: SizePreset = isSizePreset(layout.size) ? layout.size : 'm';
|
|
39
|
-
const presetSize = SIZE_PRESETS[sizePreset];
|
|
40
|
-
const relativeWidth = layout.relativeWidth ?? presetSize.relativeWidth;
|
|
41
|
-
const relativeHeight = layout.relativeHeight ?? presetSize.relativeHeight;
|
|
42
|
-
|
|
43
|
-
const positionPreset = isPositionPreset(layout.position) ? layout.position : undefined;
|
|
44
|
-
|
|
45
|
-
let baseX: number;
|
|
46
|
-
let baseY: number;
|
|
47
|
-
|
|
48
|
-
if (layout.relativeX !== undefined) {
|
|
49
|
-
baseX = layout.relativeX;
|
|
50
|
-
} else if (positionPreset) {
|
|
51
|
-
baseX = POSITION_PRESETS[positionPreset].relativeX;
|
|
52
|
-
} else {
|
|
53
|
-
// default to center
|
|
54
|
-
baseX = POSITION_PRESETS['center'].relativeX;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (layout.relativeY !== undefined) {
|
|
58
|
-
baseY = layout.relativeY;
|
|
59
|
-
} else if (positionPreset) {
|
|
60
|
-
baseY = POSITION_PRESETS[positionPreset].relativeY;
|
|
61
|
-
} else {
|
|
62
|
-
// default to center
|
|
63
|
-
baseY = POSITION_PRESETS['center'].relativeY;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const hasExplicitPosition = layout.relativeX !== undefined || layout.relativeY !== undefined;
|
|
67
|
-
const {relativeX, relativeY} = hasExplicitPosition
|
|
68
|
-
? {relativeX: baseX, relativeY: baseY}
|
|
69
|
-
: calculateAnchoredPosition(baseX, baseY, relativeWidth, relativeHeight, positionPreset || 'center');
|
|
70
|
-
|
|
71
|
-
const userStyles = simplified.styles || {};
|
|
72
|
-
const mergedStyles: Record<string, string> = {};
|
|
73
|
-
|
|
74
|
-
// defaults
|
|
75
|
-
for (const [key, value] of Object.entries(DEFAULT_STYLES)) {
|
|
76
|
-
mergedStyles[key] = value;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// user overrides
|
|
80
|
-
for (const [key, value] of Object.entries(userStyles)) {
|
|
81
|
-
if (value !== undefined) {
|
|
82
|
-
mergedStyles[key] = value;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const fullConfig: HotspotConfigFull = {
|
|
87
|
-
id: simplified.id || generateHotspotId(),
|
|
88
|
-
startTime: simplified.startTime,
|
|
89
|
-
endTime: simplified.endTime,
|
|
90
|
-
label: simplified.label,
|
|
91
|
-
onClick: simplified.onClick,
|
|
92
|
-
layout: {
|
|
93
|
-
relativeX,
|
|
94
|
-
relativeY,
|
|
95
|
-
relativeWidth,
|
|
96
|
-
relativeHeight,
|
|
97
|
-
stageWidth: layout.stageWidth ?? DEFAULT_STAGE.stageWidth,
|
|
98
|
-
stageHeight: layout.stageHeight ?? DEFAULT_STAGE.stageHeight
|
|
99
|
-
},
|
|
100
|
-
styles: mergedStyles
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
return fullConfig;
|
|
104
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
export type PositionPreset = 'top-left' | 'top' | 'top-right' | 'left' | 'center' | 'right' | 'bottom-left' | 'bottom' | 'bottom-right';
|
|
2
|
-
|
|
3
|
-
export type SizePreset = 'xs' | 's' | 'm' | 'l' | 'xl';
|
|
4
|
-
|
|
5
|
-
// include 5% padding from edges
|
|
6
|
-
export const POSITION_PRESETS: Record<PositionPreset, {relativeX: number; relativeY: number}> = {
|
|
7
|
-
'top-left': {relativeX: 0.05, relativeY: 0.05},
|
|
8
|
-
top: {relativeX: 0.5, relativeY: 0.05},
|
|
9
|
-
'top-right': {relativeX: 0.95, relativeY: 0.05},
|
|
10
|
-
left: {relativeX: 0.05, relativeY: 0.5},
|
|
11
|
-
center: {relativeX: 0.5, relativeY: 0.5},
|
|
12
|
-
right: {relativeX: 0.95, relativeY: 0.5},
|
|
13
|
-
'bottom-left': {relativeX: 0.05, relativeY: 0.95},
|
|
14
|
-
bottom: {relativeX: 0.5, relativeY: 0.95},
|
|
15
|
-
'bottom-right': {relativeX: 0.95, relativeY: 0.95}
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const SIZE_PRESETS: Record<SizePreset, {relativeWidth: number; relativeHeight: number}> = {
|
|
19
|
-
xs: {relativeWidth: 0.12, relativeHeight: 0.08},
|
|
20
|
-
s: {relativeWidth: 0.18, relativeHeight: 0.1},
|
|
21
|
-
m: {relativeWidth: 0.25, relativeHeight: 0.12},
|
|
22
|
-
l: {relativeWidth: 0.32, relativeHeight: 0.14},
|
|
23
|
-
xl: {relativeWidth: 0.42, relativeHeight: 0.16}
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// used for scaling font sizes and border radius
|
|
27
|
-
export const DEFAULT_STAGE = {
|
|
28
|
-
stageWidth: 960,
|
|
29
|
-
stageHeight: 640
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export const DEFAULT_STYLES: Record<string, string> = {
|
|
33
|
-
background: 'rgba(0, 0, 0, 0.75)',
|
|
34
|
-
color: '#ffffff',
|
|
35
|
-
'border-radius': '12px',
|
|
36
|
-
'font-size': '20px',
|
|
37
|
-
'font-weight': '500',
|
|
38
|
-
'font-family': '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const POSITION_ANCHORS: Record<PositionPreset, {anchorX: number; anchorY: number}> = {
|
|
42
|
-
'top-left': {anchorX: 0, anchorY: 0},
|
|
43
|
-
top: {anchorX: 0.5, anchorY: 0},
|
|
44
|
-
'top-right': {anchorX: 1, anchorY: 0},
|
|
45
|
-
left: {anchorX: 0, anchorY: 0.5},
|
|
46
|
-
center: {anchorX: 0.5, anchorY: 0.5},
|
|
47
|
-
right: {anchorX: 1, anchorY: 0.5},
|
|
48
|
-
'bottom-left': {anchorX: 0, anchorY: 1},
|
|
49
|
-
bottom: {anchorX: 0.5, anchorY: 1},
|
|
50
|
-
'bottom-right': {anchorX: 1, anchorY: 1}
|
|
51
|
-
};
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
interface TimelineHotspot {
|
|
2
|
-
id: string;
|
|
3
|
-
startTime: number; // ms
|
|
4
|
-
endTime?: number; // ms (exclusive); undefined => infinite
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class HotspotTimelineSimple<T extends TimelineHotspot> {
|
|
8
|
-
private _hotspotsMap: Map<string, T> = new Map();
|
|
9
|
-
private _visibleIds: Set<string> = new Set();
|
|
10
|
-
|
|
11
|
-
initialize(hotspots: T[]): void {
|
|
12
|
-
this._hotspotsMap.clear();
|
|
13
|
-
this._visibleIds.clear();
|
|
14
|
-
|
|
15
|
-
for (const hotspot of hotspots) {
|
|
16
|
-
this._hotspotsMap.set(hotspot.id, hotspot);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Recompute visible set at time currentTimeMs.
|
|
21
|
-
// Returns true if visible set changed.
|
|
22
|
-
update(currentTimeMs: number): boolean {
|
|
23
|
-
const nextVisible = new Set<string>();
|
|
24
|
-
|
|
25
|
-
this._hotspotsMap.forEach((h, id) => {
|
|
26
|
-
if (currentTimeMs < h.startTime) {
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (h.endTime !== undefined && currentTimeMs >= h.endTime) {
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
nextVisible.add(id);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
const prevVisible = this._visibleIds;
|
|
38
|
-
|
|
39
|
-
if (nextVisible.size !== prevVisible.size) {
|
|
40
|
-
this._visibleIds = nextVisible;
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let changed = false;
|
|
45
|
-
nextVisible.forEach(id => {
|
|
46
|
-
if (!changed && !prevVisible.has(id)) {
|
|
47
|
-
changed = true;
|
|
48
|
-
}
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
this._visibleIds = nextVisible;
|
|
52
|
-
|
|
53
|
-
return changed;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
getVisibleHotspots(): T[] {
|
|
57
|
-
const result: T[] = [];
|
|
58
|
-
|
|
59
|
-
this._visibleIds.forEach(id => {
|
|
60
|
-
const hotspot = this._hotspotsMap.get(id);
|
|
61
|
-
|
|
62
|
-
if (hotspot) {
|
|
63
|
-
result.push(hotspot);
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
return result;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
get size(): number {
|
|
71
|
-
return this._hotspotsMap.size;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
clear(): void {
|
|
75
|
-
this._hotspotsMap.clear();
|
|
76
|
-
this._visibleIds.clear();
|
|
77
|
-
}
|
|
78
|
-
}
|
package/src/utils/hotspot.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
export interface Layout {
|
|
2
|
-
x: number;
|
|
3
|
-
y: number;
|
|
4
|
-
width: number;
|
|
5
|
-
height: number;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface Style {
|
|
9
|
-
radiusBorder: number;
|
|
10
|
-
fontSize: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface RawFloatingCuepoint {
|
|
14
|
-
id: string;
|
|
15
|
-
startTime: number;
|
|
16
|
-
endTime?: number;
|
|
17
|
-
rawLayout: {
|
|
18
|
-
relativeX: number;
|
|
19
|
-
relativeY: number;
|
|
20
|
-
relativeWidth: number;
|
|
21
|
-
relativeHeight: number;
|
|
22
|
-
stageWidth: number;
|
|
23
|
-
stageHeight: number;
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface FloatingCuepoint extends RawFloatingCuepoint {
|
|
28
|
-
layout: Layout;
|
|
29
|
-
relativeStyle : Style;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface OpenUrl {
|
|
33
|
-
type: 'openUrl';
|
|
34
|
-
url: string;
|
|
35
|
-
}
|
|
36
|
-
export interface OpenUrlInNewTab {
|
|
37
|
-
type: 'openUrlInNewTab';
|
|
38
|
-
url: string;
|
|
39
|
-
}
|
|
40
|
-
export interface JumpToTime {
|
|
41
|
-
type: 'jumpToTime';
|
|
42
|
-
jumpToTime: number;
|
|
43
|
-
}
|
|
44
|
-
interface ScrollToAnchor {
|
|
45
|
-
type: 'scrollToAnchor';
|
|
46
|
-
selector: string;
|
|
47
|
-
scrollBehavior?: ScrollBehavior;
|
|
48
|
-
offsetY?: number;
|
|
49
|
-
}
|
|
50
|
-
interface PostMessage {
|
|
51
|
-
type: 'postMessage';
|
|
52
|
-
message: unknown;
|
|
53
|
-
targetOrigin?: string;
|
|
54
|
-
pauseVideo?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type OnClickAction = OpenUrl | OpenUrlInNewTab | JumpToTime | ScrollToAnchor | PostMessage;
|
|
58
|
-
|
|
59
|
-
export type RawLayoutHotspot = RawFloatingCuepoint & {
|
|
60
|
-
onClick?: OnClickAction;
|
|
61
|
-
label?: string;
|
|
62
|
-
styles: {[key: string]: string};
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export type LayoutHotspot = RawLayoutHotspot & FloatingCuepoint;
|
|
66
|
-
|
|
67
|
-
export interface Size {
|
|
68
|
-
width: number;
|
|
69
|
-
height: number;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface Canvas {
|
|
73
|
-
playerSize: Size;
|
|
74
|
-
videoSize: Size;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export const shallowCompareHotspots = (arrA: LayoutHotspot[], arrB: LayoutHotspot[]) => {
|
|
78
|
-
const len = arrA.length;
|
|
79
|
-
if (arrB.length !== len) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
for (let i = 0; i < len; i++) {
|
|
83
|
-
if (arrA[i] !== arrB[i]) {
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
return true;
|
|
88
|
-
};
|
package/src/utils/scale-video.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
export interface ScaleCalculation {
|
|
2
|
-
width: number;
|
|
3
|
-
height: number;
|
|
4
|
-
left: number;
|
|
5
|
-
top: number;
|
|
6
|
-
scaleToTargetWidth: boolean;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function scaleVideo(
|
|
10
|
-
videoWidth: number,
|
|
11
|
-
videoHeight: number,
|
|
12
|
-
playerWidth: number,
|
|
13
|
-
playerHeight: number,
|
|
14
|
-
fLetterBox: boolean
|
|
15
|
-
): ScaleCalculation {
|
|
16
|
-
const result: ScaleCalculation = {
|
|
17
|
-
width: 0,
|
|
18
|
-
height: 0,
|
|
19
|
-
left: 0,
|
|
20
|
-
top: 0,
|
|
21
|
-
scaleToTargetWidth: true
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
if (videoWidth <= 0 || videoHeight <= 0 || playerWidth <= 0 || playerHeight <= 0) {
|
|
25
|
-
return result;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// scale to the target width
|
|
29
|
-
const scaleX1 = playerWidth;
|
|
30
|
-
const scaleY1 = (videoHeight * playerWidth) / videoWidth;
|
|
31
|
-
|
|
32
|
-
// scale to the target height
|
|
33
|
-
const scaleX2 = (videoWidth * playerHeight) / videoHeight;
|
|
34
|
-
const scaleY2 = playerHeight;
|
|
35
|
-
|
|
36
|
-
// now figure out which one we should use
|
|
37
|
-
let fScaleOnWidth = scaleX2 > playerWidth;
|
|
38
|
-
if (fScaleOnWidth) {
|
|
39
|
-
fScaleOnWidth = fLetterBox;
|
|
40
|
-
} else {
|
|
41
|
-
fScaleOnWidth = !fLetterBox;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (fScaleOnWidth) {
|
|
45
|
-
result.width = Math.abs(scaleX1);
|
|
46
|
-
result.height = Math.abs(scaleY1);
|
|
47
|
-
result.scaleToTargetWidth = true;
|
|
48
|
-
} else {
|
|
49
|
-
result.width = Math.abs(scaleX2);
|
|
50
|
-
result.height = Math.abs(scaleY2);
|
|
51
|
-
result.scaleToTargetWidth = false;
|
|
52
|
-
}
|
|
53
|
-
result.left = Math.abs((playerWidth - result.width) / 2);
|
|
54
|
-
result.top = Math.abs((playerHeight - result.height) / 2);
|
|
55
|
-
|
|
56
|
-
return result;
|
|
57
|
-
}
|