148 lines
5.9 KiB
JavaScript
148 lines
5.9 KiB
JavaScript
|
|
/*
|
|
* 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;
|
|
} |