blob: bbf685ed913fb0ee21e423cc98c569c0075362e9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* AUTO-GENERATED FILE. DO NOT MODIFY.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import Axis2D from '../coord/cartesian/Axis2D.js';
import { makeInner } from './model.js';
export function needFixJitter(seriesModel, axis) {
var coordinateSystem = seriesModel.coordinateSystem;
var coordType = coordinateSystem && coordinateSystem.type;
var baseAxis = coordinateSystem && coordinateSystem.getBaseAxis && coordinateSystem.getBaseAxis();
var scaleType = baseAxis && baseAxis.scale && baseAxis.scale.type;
var seriesValid = coordType === 'cartesian2d' && scaleType === 'ordinal' || coordType === 'single';
var axisValid = axis.model.get('jitter') > 0;
return seriesValid && axisValid;
}
var inner = makeInner();
/**
* Fix jitter for overlapping data points.
*
* @param fixedAxis The axis whose coord doesn't change with jitter.
* @param fixedCoord The coord of fixedAxis.
* @param floatCoord The coord of the other axis, which should be changed with jittering.
* @param radius The radius of the data point, considering the symbol is a circle.
* @returns updated floatCoord.
*/
export function fixJitter(fixedAxis, fixedCoord, floatCoord, radius) {
if (fixedAxis instanceof Axis2D) {
var scaleType = fixedAxis.scale.type;
if (scaleType !== 'category' && scaleType !== 'ordinal') {
return floatCoord;
}
}
var axisModel = fixedAxis.model;
var jitter = axisModel.get('jitter');
var jitterOverlap = axisModel.get('jitterOverlap');
var jitterMargin = axisModel.get('jitterMargin') || 0;
// Get band width to limit jitter range
var bandWidth = fixedAxis.scale.type === 'ordinal' ? fixedAxis.getBandWidth() : null;
if (jitter > 0) {
if (jitterOverlap) {
return fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius);
} else {
return fixJitterAvoidOverlaps(fixedAxis, fixedCoord, floatCoord, radius, jitter, jitterMargin);
}
}
return floatCoord;
}
function fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius) {
// Don't clamp single axis
if (bandWidth === null) {
return floatCoord + (Math.random() - 0.5) * jitter;
}
var maxJitter = bandWidth - radius * 2;
var actualJitter = Math.min(Math.max(0, jitter), maxJitter);
return floatCoord + (Math.random() - 0.5) * actualJitter;
}
function fixJitterAvoidOverlaps(fixedAxis, fixedCoord, floatCoord, radius, jitter, margin) {
var store = inner(fixedAxis);
if (!store.items) {
store.items = [];
}
var items = store.items;
// Try both positive and negative directions, choose the one with smaller movement
var overlapA = placeJitterOnDirection(items, fixedCoord, floatCoord, radius, jitter, margin, 1);
var overlapB = placeJitterOnDirection(items, fixedCoord, floatCoord, radius, jitter, margin, -1);
var minFloat = Math.abs(overlapA - floatCoord) < Math.abs(overlapB - floatCoord) ? overlapA : overlapB;
// Clamp only category axis
var bandWidth = fixedAxis.scale.type === 'ordinal' ? fixedAxis.getBandWidth() : null;
var distance = Math.abs(minFloat - floatCoord);
if (distance > jitter / 2 || bandWidth && distance > bandWidth / 2 - radius) {
// If the new item is moved too far, then give up.
// Fall back to random jitter.
return fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius);
}
// Add new point to array
items.push({
fixedCoord: fixedCoord,
floatCoord: minFloat,
r: radius
});
return minFloat;
}
function placeJitterOnDirection(items, fixedCoord, floatCoord, radius, jitter, margin, direction) {
var y = floatCoord;
// Check all existing items for overlap and find the maximum adjustment needed
for (var i = 0; i < items.length; i++) {
var item = items[i];
var dx = fixedCoord - item.fixedCoord;
var dy = y - item.floatCoord;
var d2 = dx * dx + dy * dy;
var r = radius + item.r + margin;
if (d2 < r * r) {
// Has overlap, calculate required adjustment
var requiredY = item.floatCoord + Math.sqrt(r * r - dx * dx) * direction;
// Check if this adjustment would move too far
if (Math.abs(requiredY - floatCoord) > jitter / 2) {
return Number.MAX_VALUE; // Give up
}
// Update y only when it's larger to the center
if (direction === 1 && requiredY > y || direction === -1 && requiredY < y) {
y = requiredY;
// Loop from the start again
i = -1; // Reset index to recheck all items
continue; // Recalculate with the new y position
}
}
}
return y;
}